PIPS
pipsmake.c
Go to the documentation of this file.
1 /*
2 
3  $Id: pipsmake.c 23412 2017-08-09 15:07:09Z irigoin $
4 
5  Copyright 1989-2016 MINES ParisTech
6 
7  This file is part of PIPS.
8 
9  PIPS is free software: you can redistribute it and/or modify it
10  under the terms of the GNU General Public License as published by
11  the Free Software Foundation, either version 3 of the License, or
12  any later version.
13 
14  PIPS is distributed in the hope that it will be useful, but WITHOUT ANY
15  WARRANTY; without even the implied warranty of MERCHANTABILITY or
16  FITNESS FOR A PARTICULAR PURPOSE.
17 
18  See the GNU General Public License for more details.
19 
20  You should have received a copy of the GNU General Public License
21  along with PIPS. If not, see <http://www.gnu.org/licenses/>.
22 
23 */
24 #ifdef HAVE_CONFIG_H
25  #include "pips_config.h"
26 #endif
27 /*
28  * pipsmake: call by need (make),
29  * rule selection (activate),
30  * explicit call (apply/capply)
31  *
32  * Remi Triolet, Francois Irigoin, Pierre Jouvelot, Bruno Baron,
33  * Arnauld Leservot, Guillaume Oget, Fabien Coelho.
34  *
35  * Notes:
36  * - pismake uses some RI fields explicitly
37  * - see Bruno Baron's DEA thesis for more details
38  * - do not forget the difference between *virtual* resources like
39  * CALLERS.CODE and *real* resources like FOO.CODE; CALLERS is a
40  * variable (or a function) whose value depends on the current module;
41  * it is expanded into a list of real resources;
42  * the variables are CALLEES, CALLERS, ALL and MODULE (the current module
43  * itself);
44  * these variables are used to implement top-down and bottom-up traversals
45  * of the call tree; they make pipsmake different from
46  *
47  * - memoization added to make() to speed-up a sequence of interprocedural
48  * requests on real applications; a resource r is up-to-date if it already
49  * has been
50  * proved up-to-date, or if all its arguments have been proved up-to-date and
51  * all its arguments are in the database and all its arguments are
52  * older than the requested resource r; this scheme is correct as soon as
53  * activate()
54  * destroys the resources produced by the activated (and de-activated) rule
55  * - include of an automatically generated builder_map
56  * - explicit *recursive* destruction of obsolete resources by
57  * activate() but not by apply(); beware! You cannot assume that all
58  * resources in the database are consistent;
59  *
60  */
61 
62 #include <stdio.h>
63 #include <stdlib.h>
64 #include <unistd.h>
65 #include <string.h>
66 #include <sys/types.h>
67 
68 #include "genC.h"
69 
70 #include "linear.h"
71 #include "ri.h"
72 #include "constants.h"
73 
74 #include "misc.h"
75 
76 #include "ri-util.h"
77 #include "pipsdbm.h"
78 #include "workspace-util.h"
79 #include "resources.h"
80 #include "phases.h"
81 #include "properties.h"
82 #include "pips-libs.h"
83 
84 #include "pipsmake.h"
85 
86 // static generated table with all passes
87 #include "builder_map.h"
88 
89 void set_current_phase_context(const char* rname, const char* oname)
90 {
91  set_pips_current_computation(rname, oname);
94 }
95 
97 {
101 }
102 
103 /* call builder to build a resource for something.
104  * handle possible exceptions while doing so.
105  */
106 static bool catch_user_error(builder_func_t builder,
107  const char* rname, const char* oname)
108 {
109  volatile bool success = false;
110 
111  // warn once if inconsistent gmp requirement
112  // probably this could be moved elsewhere.
113  // this is checked over and over again because environment variable
114  // may be changed from a tpips script...
115  static bool warned_about_gmp_inconsistent_requirement = false;
116  if (!warned_about_gmp_inconsistent_requirement &&
118  {
119  pips_user_warning("gmp required but not available\n");
120  warned_about_gmp_inconsistent_requirement = true;
121  }
122 
123  set_current_phase_context(rname, oname);
125 
127 
129  {
131  success = false;
133 
135  RETHROW();
136  }
137  TRY
138  {
140  success = (*builder)((const string) oname);
143  }
144 
145  if (!success)
146  pips_user_warning("pass has failed\n");
147 
148  if (linear_error_count())
149  {
150  unsigned int oe, se, me;
151  linear_get_error_counts(&oe, &se, &me);
152  if (oe || se)
153  pips_user_warning("linear errors: overflow=%u, simplex=%u\n", oe, se);
154  if (me)
155  pips_user_warning("misc exceptions: %u\n", me);
156  }
157 
159 
160  return success;
161 }
162 
163 static builder_func_t get_builder(const char* name)
164 {
165  struct builder_map * pbm;
166  for (pbm = builder_maps; pbm->builder_name; pbm++)
167  if (same_string_p(pbm->builder_name, name))
168  return pbm->builder_func;
169  pips_internal_error("no builder for %s", name);
170  return NULL;
171 }
172 
173 /*********************************************** UP TO DATE RESOURCES CACHE */
174 
175 /* FI: pipsmmake is very slow when interprocedural analyzes have been selected;
176  * some memoization has been added; we need to distinguish betweeen an
177  * external make which initializes a set of up-to-date resources and
178  * an internal recursive make which updates and exploits that set.
179  *
180  * This new functionality is extremely useful when old databases
181  * are re-opened.
182  *
183  * apply(), which calls make() many times, does not fully benefit from
184  * this memoization scheme.
185  *
186  * What is cached? a resource id, i.e. a db_resource, i.e. an object
187  * hidden in pipsdbm_private...
188  */
190 
192 {
193  pips_debug(8, "The up-to-date resource cache is reset\n");
194  pips_assert("set is defined", !set_undefined_p(up_to_date_resources));
197 }
198 
199 void init_make_cache(void)
200 {
201  pips_debug(8, "The up-to-date resource cache is initialized to empty\n");
204 }
205 
206 /* Can the make cache be used? */
208 {
210 }
211 
213 {
216 }
217 
218 //bool make_cache_hit_p(real_resource rr)
219 bool make_cache_hit_p(void * rr_id)
220 {
221  return set_belong_p(up_to_date_resources, rr_id);
222 }
223 
224 //void add_resource_to_make_cache(real_resource res)
225 void add_resource_to_make_cache(void * res_id)
226 {
227  /* FI: debugging messages cannot be factorized here because of
228  sibling resources, unless an extra parameter is added... */
229  //string res_rn = real_resource_resource_name((real_resource) res);
230  //string res_on = real_resource_owner_name((real_resource) res);
231  //pips_debug(5, "resource %s(%s) added to up_to_date make cache\n",
232  // res_rn, res_on);
235  res_id);
236 }
237 
238 //void remove_resource_from_make_cache(real_resource res)
240 {
241  string res_rn = db_resource_name(res_id);
242  string res_on = db_resource_owner_name(res_id);
243  pips_debug(5, "resource %s(%s) deleted from up_to_date make cache\n",
244  res_rn, res_on);
247  res_id);
248 }
249 
250 /* Debug function, to be tested... */
252 {
254  int count = 0;
255  SET_FOREACH(void *, res_id, up_to_date_resources) {
256  string res_rn = db_resource_name(res_id);
257  string res_on = db_resource_owner_name(res_id);
258  if(string_undefined_p(res_rn) || string_undefined_p(res_on))
259  printf("Up-to-date resources/make cache inconsistent with "
260  "pipsdbm resources\n");
261  else
262  printf("Up-to-date resource: \"%s.%s\"\n", res_on, res_rn);
263  count++;
264  }
265  if(count==0)
266  printf("No up-to-date resource is cached in make cache\n");
267  }
268  else
269  printf("The up-to-date resource make cache is currently undefined\n");
270 }
271 
272 /* Debug function: make sure that up-to-date resources do exist in the
273  resource database. If the cache does not exist, it is considered
274  consistent. */
276 {
278  SET_FOREACH(void *, res_id, up_to_date_resources) {
279  string res_rn = db_resource_name(res_id);
280  /* FI: the first test should be enough */
281  if(string_undefined_p(res_rn))
282  return false;
283  string res_on = db_resource_owner_name(res_id);
284  if(string_undefined_p(res_on))
285  return false;
286  if(!db_resource_p(res_rn, res_on))
287  return false;
288  }
289  }
290  return true;
291 }
292 
293 /* Static variables used by phases must be reset on error although
294  pipsmake does not know which ones are used. */
295 /* FI: let us hope this is documented in PIPS developer guide... It is
296  not mentionned in the PIPS tutorial. And rightly so I believe. It
297  should be linked to the exception pips_user_error(). */
299 {
300 #define DECLARE_ERROR_HANDLER(name) extern void name(); name()
301 
302  /* From ri-util/static.c */
305 
306  /* Macro-generated resets */
307 #ifdef HAVE_PIPS_effects_generic_LIBRARY
312  /* Macro-generated resets in effects-generic/utils.c */
314 #endif // HAVE_PIPS_effects_generic_LIBRARY
315 
316 #ifdef HAVE_PIPS_transformer_LIBRARY
318 #endif // HAVE_PIPS_transformer_LIBRARY
319 
320 #ifdef HAVE_PIPS_semantics_LIBRARY
323 #endif // HAVE_PIPS_semantics_LIBRARY
324 
325 #undef DECLARE_ERROR_HANDLER
326 
327  // call registered reset functions
329 }
330 
331 /* Apply an instantiated rule with a given ressource owner
332  */
333 
334 /* FI: uncomment if rmake no longer needed in callgraph.c */
335 /* static bool rmake(string, string); */
336 
337 #define add_res(vrn, on) \
338  result = CONS(REAL_RESOURCE, \
339  make_real_resource(strdup(vrn), strdup(on)), result);
340 
341 /* Translate and expand a list of virtual resources into a potentially
342  * much longer list of real resources
343  *
344  * this is intrinsically a bad idea: if a new module is created as
345  * a side effect of some processing, then the dependency on this new module
346  * will never appear and cannot be checked for a redo here (see comments
347  * of is_owner_all case).
348  *
349  * In spite of the name, no resource is actually built.
350  *
351  * FI: the result "result" seems to be always an empty list, NIL, but
352  * macro add_res does update "result". Once again, macros improve
353  * readability and maintenance.
354  */
355 static list build_real_resources(const char* oname, list lvr)
356 {
357  list pvr, result = NIL;
358 
359  for (pvr = lvr; pvr != NIL; pvr = CDR(pvr))
360  {
362  string vrn = virtual_resource_name(vr);
364 
365  switch (vrt)
366  {
367  // FI: should be is_owner_workspace, but changing Newgen decl...
368  case is_owner_program:
369  // FI: for relocation of workspaces
370  add_res(vrn, "");
371  break;
372 
373  case is_owner_module:
374  add_res(vrn, oname);
375  break;
376 
377  case is_owner_main:
378  {
379  int number_of_main = 0;
381 
382  GEN_ARRAY_FOREACH(string, on, a)
383  {
385  {
386  if (number_of_main)
387  pips_internal_error("More than one main");
388 
389  number_of_main++;
390  pips_debug(8, "Main is %s\n", (string) on);
391  add_res(vrn, on);
392  }
393  }
394 
396  break;
397  }
398  case is_owner_callees:
399  {
401  list lcallees;
402 
403  if (!rmake(DBR_CALLEES, oname)) {
404  // FI: probably missing source code...
405  pips_user_error("unable to build callees for %s\n"
406  "Some source code probably is missing!\n",
407  oname);
408  }
409 
411  db_get_memory_resource(DBR_CALLEES, oname, true);
413 
414  if(!ENDP(lcallees))
415  pips_debug(8, "Callees of %s are:\n", oname);
416  FOREACH(STRING, on, lcallees) {
417  pips_debug(8, "\t%s\n", on);
418  add_res(vrn, on);
419  }
420  gen_free_string_list(lcallees);
421 
422  break;
423  }
424  case is_owner_callers:
425  {
426  // FI: the keyword callees was badly chosen; anyway,
427  // it's just a list of strings... see ri.newgen
428  callees caller_modules;
429  list lcallers;
430 
431  if (!rmake(DBR_CALLERS, oname)) {
432  pips_user_error ("unable to build callers for %s\n"
433  "Any missing source code?\n",
434  oname);
435  }
436 
437  caller_modules = (callees)
438  db_get_memory_resource(DBR_CALLERS, oname, true);
439  lcallers = gen_copy_string_list(callees_callees(caller_modules));
440 
441  pips_debug(8, "Callers of %s are:\n", oname);
442 
443  FOREACH(string, on, lcallers)
444  {
445  pips_debug(8, "\t%s\n", on);
446  add_res(vrn, on);
447  }
448  gen_free_string_list(lcallers);
449  break;
450  }
451 
452  case is_owner_all:
453  {
454  // some funny stuff here:
455  // some modules may be added by the phases here...
456  // then we might expect a later coredump if the new resource
457  // is not found.
458  gen_array_t modules = db_get_module_list();
459 
460  GEN_ARRAY_FOREACH(string, on, modules)
461  {
462  pips_debug(8, "\t%s\n", (string) on);
463  add_res(vrn, on);
464  }
465 
466  gen_array_full_free(modules);
467  break;
468  }
469 
470  case is_owner_select:
471  {
472  // do nothing ...
473  break;
474  }
475 
477  {
480  // Source code for module oname is not available
481  if(compilation_unit_p(oname))
482  {
483  // The user can make typos in tpips scripts
484  // about compilation unit names.
485  pips_user_error("No source code for compilation unit \"%s\"\n."
486  "Compilation units cannot be synthesized.\n",
487  oname);
488  }
489  pips_user_warning("No source code for module %s.\n", oname);
490  // this is a really bad hack !
491  // compilation_unit_name = strdup(concatenate(oname, FILE_SEP_STRING, NULL));
492  } else {
495  }
496  break;
497  }
498 
499  default:
500  pips_internal_error("unknown tag : %d", vrt);
501  }
502  }
503 
504  return gen_nreverse(result);
505 }
506 
507 /* touch the resource if it exits
508  * this is currently an experimental and partial implementation
509  */
510 static void preserve_virtual_resource(const char * oname, virtual_resource vr)
511 {
512  switch (owner_tag(virtual_resource_owner(vr)))
513  {
514  case is_owner_module:
515  // touch only available resources
516  if (db_resource_p(virtual_resource_name(vr), oname))
518  // ??? we should now touch the transitive closure of dependent resources
519  // forall all resources in the database
520  // if it is up to date because the resource is either preserved
521  // or up to date, then touch it, otherwise delete it?
522  // the problem is linked to the lazyness of pipsmake which keeps
523  // obsolete resources if no one asks about them.
524  break;
525  case is_owner_program:
526  case is_owner_main:
527  case is_owner_callees:
528  case is_owner_callers:
529  case is_owner_all:
530  case is_owner_select:
532  default:
533  pips_internal_error("not implemented");
534  }
535 }
536 
537 static void update_preserved_resources(const char* oname, rule ru)
538 {
539  list reals;
540 
541  /* We increment the logical time (kept by pipsdbm) */
543 
544  /* we build the list of modified real_resources */
545  reals = build_real_resources(oname, rule_modified(ru));
546 
547  /* we delete them from the up-to-date set */
548  FOREACH(real_resource, rr, reals)
549  {
550  string rron = real_resource_owner_name(rr);
551  string rrrn = real_resource_resource_name(rr);
552 
553  /* is it up to date ? */
554  // FI: this piece of code must have never been tested...
555  void * rr_id = db_get_resource_id(rrrn, rron);
556  if(make_cache_hit_p(rr_id))
557  {
559  /* GO 11/7/95: we need to del the resource from the data base
560  for a next call of pipsmake to find it unavailable */
561  db_unput_a_resource (rrrn, rron);
562  }
563  }
564 
565  gen_full_free_list (reals);
566 
567  /* handle resources that are marked as "preserved", with "="
568  */
570  preserve_virtual_resource(oname, vr);
571 
572  /* We increment the logical time again... (kept by pipsdbm)
573  * this seems necessary??? BC & FC
574  */
576 }
577 
578 static bool apply_a_rule(const char* oname, rule ru)
579 {
580  static int number_of_applications_of_a_rule = 0;
581  static bool checkpoint_workspace_being_done = false;
582 
583  double initial_memory_size = 0.;
584  string run = rule_phase(ru), rname, rowner;
585  bool first_time = true, success_p = true,
586  print_timing_p = get_bool_property("LOG_TIMINGS"),
587  print_memory_usage_p = get_bool_property("LOG_MEMORY_USAGE"),
588  check_res_use_p = get_bool_property("CHECK_RESOURCE_USAGE");
589  builder_func_t builder = get_builder(run);
590  int frequency = get_int_property("PIPSMAKE_CHECKPOINTS");
591  list lrp;
592 
593  /* periodically checkpoints the workspace if required.
594  */
595  number_of_applications_of_a_rule++;
596 
597  if (!checkpoint_workspace_being_done &&
598  frequency>0 && number_of_applications_of_a_rule>=frequency)
599  {
600  /* ??? FC 05/04/2002 quick fix because of a recursion loop:
601  apply_a_rule -> checkpoint_workspace -> delete_obsolete_resources ->
602  check_physical_resource_up_to_date -> build_real_resources -> rmake ->
603  apply_a_rule !
604  * maybe it would be better treated in checkpoint_workspace?
605  */
606  checkpoint_workspace_being_done = true;
608  checkpoint_workspace_being_done = false;
609  number_of_applications_of_a_rule = 0;
610  }
611 
612  /* output the message somewhere...
613  */
614  lrp = build_real_resources(oname, rule_produced(ru));
615  FOREACH(REAL_RESOURCE, rr, lrp)
616  {
617  list lr = build_real_resources(oname, rule_required(ru));
618  bool is_required = false;
619  rname = real_resource_resource_name(rr);
620  rowner = real_resource_owner_name(rr);
621 
622  FOREACH(REAL_RESOURCE, rrr, lr)
623  {
624  if (same_string_p(rname, real_resource_resource_name(rrr)) &&
626  {
627  is_required = true;
628  break;
629  }
630  }
631 
632  gen_full_free_list(lr);
633 
634  user_log(" %-30.60s %8s %s(%s)\n",
635  first_time == true ? (first_time = false,run) : "",
636  is_required == true ? "updating" : "building",
637  rname, rowner);
638  }
639 
640  gen_full_free_list(lrp);
641 
642  if (check_res_use_p)
644 
645  if (print_timing_p)
646  init_log_timers();
647 
648  if (print_memory_usage_p)
650 
651  /* DO IT HERE!
652  */
653  success_p = catch_user_error(builder, run, oname);
654 
655  if (print_timing_p)
656  {
657  string time_with_io,io_time;
658 
659  get_string_timers (&time_with_io, &io_time);
660 
661  user_log (" time ");
662  user_log (time_with_io);
663  user_log (" IO time ");
664  user_log (io_time);
665  }
666 
667  if (print_memory_usage_p) {
668  double final_memory_size = get_process_gross_heap_size();
669  user_log("\t\t\t\t memory size %10.3f, increase %10.3f\n",
670  final_memory_size,
671  final_memory_size-initial_memory_size);
672  }
673 
674  if (check_res_use_p)
675  do_resource_usage_check(oname, ru);
676 
678 
679  update_preserved_resources(oname, ru);
680 
681  if (run_pipsmake_callback() == false)
682  return false;
683 
685  return false;
686 
687  return success_p;
688 }
689 
690 
691 /* This function returns the active rule to produce resource rname. It
692  selects the first active rule in the database which produces the
693  resource but does not use/require it. */
694 rule find_rule_by_resource(const char* rname)
695 {
696  makefile m = parse_makefile();
697 
698  pips_debug(5, "searching rule for resource %s\n", rname);
699 
700  /* walking thru rules */
701  FOREACH(RULE, r, makefile_rules(m))
702  {
703  bool resource_required_p = false;
704 
705  /* walking thru resources required by this rule to eliminate rules
706  using and producing this resource, e.g. code transformations
707  for the CODE resource. */
709  {
710  string vrn = virtual_resource_name(vr);
711  owner vro = virtual_resource_owner(vr);
712 
713  // We do not check callers and callees
714  if ( owner_callers_p(vro) || owner_callees_p(vro) ) {}
715  // Is this resource required ??
716  else if (same_string_p(vrn, rname))
717  resource_required_p = true;
718  }
719 
720  // If this particular resource is not required by the current rule.
721  if (!resource_required_p)
722  {
723  // walking thru resources made by this particular rule
725  {
726  string vrn = virtual_resource_name(vr);
727 
728  if (same_string_p(vrn, rname)) {
729 
730  pips_debug(5, "made by phase %s\n", rule_phase(r));
731 
732  // Is this phase an active one ?
734  {
735  if (same_string_p(pps, rule_phase(r))) {
736  pips_debug(5, "active phase\n");
737  return r;
738  }
739  }
740 
741  pips_debug(5, "inactive phase\n");
742  }
743  }
744  }
745  }
746 
747  return rule_undefined;
748 }
749 
750 /* Always returns a defined rule */
751 static rule safe_find_rule_by_resource(const char* rname)
752 {
753  rule ru = rule_undefined;
754 
755  if ((ru = find_rule_by_resource(rname)) == rule_undefined) {
756  /* else */
757  pips_internal_error("could not find a rule for %s", rname);
758  }
759 
760  return ru;
761 }
762 
763 static bool make_pre_transformation(const char*, rule);
764 static bool make_post_transformation(const char*, rule);
765 static bool make_required(const char*, rule);
766 
767 /* Apply do NOT activate the rule applied.
768  *
769  * In the case of an interprocedural rule, the rules applied to the
770  * callees of the main will be the default rules. For instance,
771  * "apply PRINT_CALL_GRAPH_WITH_TRANSFORMERS" applies the rule
772  * PRINT_CALL_GRAPH to all callees of the main, leading to a core
773  * dump.
774  *
775  * Safe apply checks if the rule applied is activated and produces ressources
776  * that it requires (no transitive closure) --DB 8/96
777  */
779  const char* pname,
780  const char* oname)
781 {
782  rule ru;
783 
784  pips_debug(2, "apply %s on %s\n", pname, oname);
785 
786  // we look for the rule describing this phase
787  if ((ru = find_rule_by_phase(pname)) == rule_undefined) {
788  pips_user_warning("could not find rule %s\n", pname);
789  return false;
790  }
791 
792  if (!make_pre_transformation(oname, ru))
793  return false;
794 
795  if (!make_required(oname, ru))
796  return false;
797 
798  if (!apply_a_rule(oname, ru))
799  return false;
800 
801  return make_post_transformation(oname, ru);
802 }
803 
804 
805 /* compute all pre or post-transformations to apply a rule on an
806  object or activate a phase if owner is SELECT. The phase is not
807  necessarily a transformation anymore: analyses can be requested as
808  well although pipsmake may core dump as a consequence. The select
809  clauses are performed first.
810  */
811 static bool make_pre_post_transformation(const char* oname,
812  rule ru,
814 {
815  list reals;
816  bool success_p = true;
817 
818  /* we activate the requested rules if any */
819  /* FI: apparently, we do not stack up the current active phase and
820  we do not restore it once the requesting phase is completed. */
822  {
823  string vrn = virtual_resource_name(vr);
824  owner vro = virtual_resource_owner(vr);
825 
826  if (owner_select_p(vro))
827  {
828  pips_debug(3, "rule %s : selecting phase %s\n",
829  rule_phase(ru), vrn);
830 
831  if(!active_phase_p(vrn)) {
832  /* FI: activate() is part of the pipsmake API, debug_on() is
833  activated, pipsmake.rc is potentially parsed,... */
834  if (activate(vrn) == NULL) {
835  success_p = false;
836  break;
837  }
838  }
839  }
840  }
841 
842  if (success_p) {
843  /* we build the list of pre or post transformation real_resources */
844  reals = build_real_resources(oname, transformations);
845 
846  /* we recursively make the resources */
847  FOREACH(REAL_RESOURCE, rr, reals) {
848  string rron = real_resource_owner_name(rr);
849  /* actually the resource name is a phase name !! */
850  string rrpn = real_resource_resource_name(rr);
851 
852  pips_debug(3, "rule %s : applying %s to %s - recursive call\n",
853  rule_phase(ru), rrpn, rron);
854 
856  success_p = false; // FI: success_p is not returned
857 
858  /* now we must drop the up_to_date cache.
859  * maybe not that often? Or one should perform the transforms
860  * top-down to avoid recomputations, with ALL...
861  */
863  init_make_cache();
864  }
865  }
866  return true; // success_p
867 }
868 
869 /* FI: guard added to simplify debugging and to call
870  make_pre_post_transformation() only when it is useful. */
871 static bool make_pre_transformation(const char* oname, rule ru)
872 {
873  bool success_p = true;
874  if(!ENDP(rule_pre_transformation(ru)))
875  success_p = make_pre_post_transformation(oname,ru,
877  return success_p;
878 }
879 
880 /* FI: guard added to simplify debugging and to call
881  make_pre_post_transformation() only when it is useful. */
882 static bool make_post_transformation(const char* oname, rule ru)
883 {
884  bool success_p = true;
885  if(!ENDP(rule_post_transformation(ru))) {
887  init_make_cache();
888  success_p = make_pre_post_transformation(oname,ru,rule_post_transformation(ru));
889  }
890  return success_p;
891 }
892 
893 static bool make(const char* rname, const char* oname)
894 {
895  bool success_p = true;
896 
897  debug(1, "make", "%s(%s) - requested\n", rname, oname);
898 
899  init_make_cache();
900 
903  ifdebug(5)
905 
906  success_p = rmake(rname, oname);
907 
911 
912  pips_debug(1, "%s(%s) - %smade\n",
913  rname, oname, success_p? "": "could not be ");
914 
915  return success_p;
916 }
917 
918 /* recursive make resource. Should be static, but FI uses it in callgraph.c */
919 bool rmake(const char* rname, const char* oname)
920 {
921  rule ru;
922  char * res_id = NULL;
923 
924  pips_debug(2, "%s(%s) - requested\n", rname, oname);
925 
926  /* is it up to date ? */
927  if (db_resource_p(rname, oname))
928  {
929  res_id = db_get_resource_id(rname, oname);
930  if(make_cache_hit_p(res_id))
931  {
932  pips_debug(5, "resource %s(%s) found up_to_date, time stamp %d\n",
933  rname, oname, db_time_of_resource(rname, oname));
934  return true; /* YES, IT IS! */
935  }
936  else
937  {
938  /* this resource exists but may be up-to-date? */
939  res_id = NULL; /* NO, IT IS NOT. */
940  }
941  }
942  else if (db_resource_is_required_p(rname, oname))
943  {
944  /* the resource is already being required... this is bad */
946  pips_user_error("recursion on resource %s of %s\n", rname, oname);
947  }
948  else
949  {
950  /* Well, the resource does not exists, we have to build it. */
951  db_set_resource_as_required(rname, oname);
952 
953  // FC: YUK, this warning should not be here:-(
954  /* Let's check if the proper options have been selected. */
955  /* These conditions should not be hardwired here but managed by
956  the tpips script language. */
957  if(same_string_p(rname, "IN_REGIONS")
958  || same_string_p(rname, "OUT_REGIONS")) {
960  "MUST_REGIONS"))
961  pips_user_warning("\nMUST REGIONS not selected - "
962  "Do not expect interesting results.\n");
963  }
964  }
965 
966  /* we look for the active rule to produce this resource */
967  if ((ru = find_rule_by_resource(rname)) == rule_undefined)
968  pips_internal_error("could not find a rule for %s", rname);
969 
970  /* we recursively make the pre transformations. */
971  if (!make_pre_transformation(oname, ru))
972  return false;
973 
974  /* we recursively make required resources. */
975  if (!make_required(oname, ru))
976  return false;
977 
978  if (check_resource_up_to_date (rname, oname))
979  {
980  pips_debug(8,
981  "Resource %s(%s) becomes up-to-date after applying\n"
982  " pre-transformations and building required resources\n",
983  rname,oname);
984  }
985  else
986  {
987  bool success = false;
988  list lr;
989 
990  /* we build the resource */
991  db_set_resource_as_required(rname, oname);
992 
993  success = apply_a_rule(oname, ru);
994  if (!success) return false;
995 
996  lr = build_real_resources(oname, rule_produced(ru));
997 
998  /* set up-to-date all the produced resources for that rule */
999  FOREACH(REAL_RESOURCE, rr, lr) {
1000  string rron = real_resource_owner_name(rr);
1001  string rrrn = real_resource_resource_name(rr);
1002 
1003  if (db_resource_p(rrrn, rron))
1004  {
1005  res_id = db_get_resource_id(rrrn, rron);
1006  pips_debug(5, "resource %s(%s) added to up_to_date "
1007  "with time stamp %d\n",
1008  rrrn, rron, db_time_of_resource(rrrn, rron));
1010  }
1011  else {
1012  pips_internal_error("resource %s[%s] just built not found!",
1013  rrrn, rron);
1014  }
1015  }
1016 
1017  gen_full_free_list(lr);
1018  }
1019 
1020  /* we recursively make the post transformations. */
1021  if (!make_post_transformation(oname, ru))
1022  return false;
1023 
1024  return true;
1025 }
1026 
1027 
1028 static bool apply(const char* pname, const char* oname)
1029 {
1030  bool success_p = true;
1031 
1032  pips_debug(1, "%s.%s - requested\n", oname, pname);
1033 
1034  init_make_cache();
1037 
1038  success_p = apply_without_reseting_up_to_date_resources(pname, oname);
1039 
1040  reset_make_cache();
1042 
1043  pips_debug(1, "%s.%s - done\n", oname, pname);
1044  return success_p;
1045 }
1046 
1047 
1048 static bool concurrent_apply(
1049  const char* pname, /* phase to be applied */
1050  gen_array_t modules /* modules that must be computed */)
1051 {
1052  bool okay = true;
1053  rule ru = find_rule_by_phase(pname);
1054 
1055  init_make_cache();
1058 
1059  GEN_ARRAY_FOREACH(string, oname, modules)
1060  {
1061  if (!make_pre_transformation(oname, ru)) {
1062  okay = false;
1063  break;
1064  }
1065  }
1066 
1067  if (okay) {
1068  GEN_ARRAY_FOREACH(string, oname, modules)
1069  {
1070  if (!make_required(oname, ru)) {
1071  okay = false;
1072  break;
1073  }
1074  }
1075  }
1076 
1077  if (okay) {
1078  GEN_ARRAY_FOREACH(string, oname, modules)
1079  {
1080  if (!apply_a_rule(oname, ru)) {
1081  okay = false;
1082  break;
1083  }
1084  }
1085  }
1086 
1087  if(okay) {
1088  GEN_ARRAY_FOREACH(string, oname, modules)
1089  {
1090  if (!make_post_transformation(oname, ru)) {
1091  okay = false;
1092  break;
1093  }
1094  }
1095  }
1096 
1097  reset_make_cache();
1099  return okay;
1100 }
1101 
1102 /* compute all real resources needed to apply a rule "ru" on an object
1103  * related to owner "oname".
1104  *
1105  * Make sure that the first computation of the resources does not
1106  * require a recomputation either because the number of resources has
1107  * increased because new modules have been added for call sites to
1108  * missing library source codes or by the user, or because some
1109  * resource computation include pre- or post-actions which destroy
1110  * resources already considered up-to-date.
1111  *
1112  * If the processus does not converge with one retry, core dump. The
1113  * pre- and post-actions (a.k.a. transformations) must be checked for
1114  * consistency.
1115  */
1116 static bool make_required(const char* oname, rule ru)
1117 {
1118  list reals;
1119  bool success_p = true;
1120 
1121  /* we build the list of required real_resources */
1122  reals = build_real_resources(oname, rule_required(ru));
1123 
1124  /* we recursively make required resources */
1125  FOREACH(REAL_RESOURCE, rr, reals) {
1126  string rron = real_resource_owner_name(rr);
1127  string rrrn = real_resource_resource_name(rr);
1128 
1129  pips_debug(3, "rule %s : %s(%s) - recursive call\n",
1130  rule_phase(ru), rrrn, rron);
1131 
1132  if (!rmake(rrrn, rron)) {
1133  success_p = false;
1134  /* Want to free the list ... */
1135  break;
1136  }
1137 
1138  /* In french:
1139  ici nous devons tester si un des regles modified
1140  fait partie des required. Dans ce cas on la fabrique
1141  de suite. */
1142 
1143  }
1144 
1145  /* Two problems may occur: ALL has changed, for instance because
1146  * some code has been synthesized (issue for PROGAM.PRECONDITION),
1147  * or one pre-transformation may have destroyed a resource that
1148  * was available earlier (see Semantics-New/pointer02 with
1149  * pre-transformations !CALLEES.proper_effects_with_points_to and
1150  * !CALLEES.cumulated_effects_with_points_to)
1151  *
1152  * In the first case, list "reals" should be recomputed and
1153  * compared. In the second case, list "reals" should be compared
1154  * to the content of the make cache. The second test can be
1155  * performed first. The first test can be made conditional to code
1156  * synthesis.
1157  */
1158 
1159  /* Check that all required resources exist and are up-to-date. */
1160  if(success_p && make_cache_p()) {
1161  FOREACH(REAL_RESOURCE, rr, reals) {
1162  string rron = real_resource_owner_name(rr);
1163  string rrrn = real_resource_resource_name(rr);
1164  if(db_resource_p(rrrn, rron)) {
1165  void * rr_id = db_get_resource_id(rrrn, rron);
1166  /* file resources such as USER_FILEs, which are mostly
1167  generated by create_worspace, are not inserted as ready in
1168  the make cache... It it were requested again here, it would
1169  then be in the cache... FI: no idea why... */
1170  if(!make_cache_hit_p(rr_id) && strcmp(rrrn, DBR_USER_FILE)!=0) {
1171  pips_user_warning("Computed resource \"%s.%s\" is not up-to-date"
1172  " and must be recomputed\n",
1173  rron, rrrn);
1174  if (!rmake(rrrn, rron)) {
1175  success_p = false;
1176  break;
1177  }
1178  }
1179  }
1180  else {
1181  if (!rmake(rrrn, rron)) {
1182  success_p = false;
1183  break;
1184  }
1185  }
1186  }
1187  }
1188 
1189  /* We re-build the list of required real_resources in case ALL
1190  is used and modified because some code has been synthesized. */
1191  /* FI: In case ALL is updated and some bang rule is used, it would
1192  be better to fix ALL first. */
1193  if(success_p
1194  && (strcmp(get_string_property("PREPROCESSOR_MISSING_FILE_HANDLING"),
1195  "generate")==0
1196  || strcmp(get_string_property("PREPROCESSOR_MISSING_FILE_HANDLING"),
1197  "query")==0)) {
1198  list nreals = build_real_resources(oname, rule_required(ru));
1199  int c = (int) gen_length(reals);
1200  int nc = (int) gen_length(nreals);
1201  if(c!=nc) {
1202  pips_user_warning("More resources are now requested:"
1203  " %d instead of %d...\n", nc, c);
1204  /* The first resources must be removed from the make cache */
1205  FOREACH(REAL_RESOURCE, rr, reals) {
1206  string rron = real_resource_owner_name(rr);
1207  string rrrn = real_resource_resource_name(rr);
1208  void * rr_id = db_get_resource_id(rrrn, rron);
1210  }
1211  /* The new resources must be recomputed if necessary */
1212  FOREACH(REAL_RESOURCE, rr, nreals) {
1213  string rron = real_resource_owner_name(rr);
1214  string rrrn = real_resource_resource_name(rr);
1215 
1216  pips_debug(3, "rule %s : %s(%s) - recursive call (retry)\n",
1217  rule_phase(ru), rrrn, rron);
1218 
1219  if (!rmake(rrrn, rron)) {
1220  success_p = false;
1221  /* Want to free the list ... */
1222  break;
1223  }
1224  }
1225  }
1226  gen_full_free_list(nreals); // FI: why junk nreals rather than reals?
1227  }
1228 
1229  /* ALL should not be a problem anymore, but FI has no idea if
1230  pre-transformations have to converge in one step... */
1231 
1232  /* Check again that all required resources are up-to-date. */
1233  /* FI: should be as bugged as the initial previous test. The resource
1234  existence should be tested before its id is requested. */
1235  if(success_p && make_cache_p()) {
1236  FOREACH(REAL_RESOURCE, rr, reals) { // FI: why reals rather than nreals
1237  string rron = real_resource_owner_name(rr);
1238  string rrrn = real_resource_resource_name(rr);
1239  void * rr_id = db_get_resource_id(rrrn, rron);
1240  /* file resources such as USER_FILE are not cached the first time... */
1241  if(!make_cache_hit_p(rr_id) && strcmp(rrrn, DBR_USER_FILE)!=0) {
1242  pips_internal_error("Computed resource \"%s.%s\" is still not"
1243  " up-to-date after one recomputation.\n"
1244  "The rules involved and their pre- and "
1245  "post-actions must be checked",
1246  rron, rrrn);
1247  }
1248  }
1249  }
1250 
1251  gen_full_free_list (reals);
1252  return success_p;
1253 }
1254 
1255 /* returns whether resource is up to date.
1256  */
1258  const char* rname, const char* oname)
1259 {
1260  list real_required_resources = NIL;
1261  list real_modified_resources = NIL;
1262  rule ru = rule_undefined;
1263  bool result = true;
1264  void * res_id = db_get_resource_id(rname, oname);
1265 
1266  /* Maybe is has already been proved true */
1267  if (make_cache_hit_p(res_id))
1268  return true;
1269 
1270  /* Initial resources by definition are not associated to a rule.
1271  * FI: and they always are up-to-date?!? Even if somebody touched the file?
1272  * You mean you do not propagate modifications performed outside of
1273  * the workspace?
1274  */
1275  if (same_string_p(rname, DBR_USER_FILE))
1276  return true;
1277 
1278  /* We get the active rule to build this resource */
1279  ru = safe_find_rule_by_resource(rname);
1280 
1281  /* we build the list of required real_resources */
1282  /* Here we are sure (thanks to find_rule_by_resource) that the rule does
1283  not use a resource it produces. FI: OK, this does not rule out
1284  modified resources which should not be taken into account to avoid
1285  infinite recursion. */
1286 
1287  real_required_resources = build_real_resources(oname, rule_required(ru));
1288  real_modified_resources = build_real_resources(oname, rule_modified(ru));
1289 
1290  /* we are going to check if the required resources are
1291  - in the database or in the rule_modified list
1292  - proved up to date (recursively)
1293  - have timestamps older than the tested one
1294  */
1295  FOREACH(REAL_RESOURCE, rr, real_required_resources)
1296  {
1297  string rron = real_resource_owner_name(rr);
1298  string rrrn = real_resource_resource_name(rr);
1299 
1300  bool res_in_modified_list_p = false;
1301 
1302  // we build the list of modified real_resources
1303  FOREACH(REAL_RESOURCE, mod_rr, real_modified_resources)
1304  {
1305  string mod_rron = real_resource_owner_name(mod_rr);
1306  string mod_rrrn = real_resource_resource_name(mod_rr);
1307 
1308  if ((same_string_p(mod_rron, rron)) &&
1309  (same_string_p(mod_rrrn, rrrn))) {
1310  // we found it
1311  res_in_modified_list_p = true;
1312  pips_debug(3, "resource %s(%s) is in the rule_modified list",
1313  rrrn, rron);
1314  break;
1315  }
1316  }
1317 
1318  /* If the resource is in the modified list, then
1319  don't check anything */
1320  if (res_in_modified_list_p == false) {
1321  if (!db_resource_p(rrrn, rron)) {
1322  pips_debug(5, "resource %s(%s) is not there "
1323  "and not in the rule_modified list", rrrn, rron);
1324  result = false;
1325  break;
1326  } else {
1327  /* Check if this resource is up to date */
1328  long rest;
1329  long respt;
1330  if (check_resource_up_to_date(rrrn, rron) == false) {
1331  pips_debug(5, "resource %s(%s) is not up to date", rrrn, rron);
1332  result = false;
1333  break;
1334  }
1335  rest = db_time_of_resource(rname, oname);
1336  respt = db_time_of_resource(rrrn, rron);
1337  /* Check if the timestamp is OK */
1338  if (rest<respt)
1339  {
1340  pips_debug(5, "resource %s(%s) with time stamp %ld is newer "
1341  "than resource %s(%s) with time stamp %ld\n",
1342  rrrn, rron, respt, rname, oname, rest);
1343  result = false;
1344  break;
1345  }
1346  }
1347  }
1348  }
1349 
1350  gen_full_free_list (real_required_resources);
1351  gen_full_free_list (real_modified_resources);
1352 
1353  /* If the resource is up to date then add it in the set, as well as its
1354  siblings, if they are produced by the same rule. Think of callgraph
1355  with may produce literaly thousands of resources, three times the
1356  number of modules! */
1357  if (result == true)
1358  {
1359  list real_produced_resources =
1360  build_real_resources(oname, rule_produced(ru));
1361  bool res_found_p = false;
1362 
1363  pips_debug(5, "resource %s(%s) added to up_to_date with time stamp %d\n",
1364  rname, oname, db_time_of_resource(rname, oname));
1366 
1367  FOREACH(REAL_RESOURCE, rpr, real_produced_resources) {
1368  string srname = real_resource_resource_name(rpr);
1369  string soname = real_resource_owner_name(rpr);
1370  void * sres_id = (void *) db_get_resource_id(srname, soname);
1371  // real_resource sres_id = db_get_resource_id(srname, soname);
1372 
1373  if (sres_id != res_id) {
1374  if (same_string_p(rname, srname)) {
1375  // We would retrieve the same rule and the same required
1376  // resources. rpr is up-to-date.
1377 
1378  pips_debug(5, "sibling resource %s(%s) added to up_to_date "
1379  "with time stamp %d\n",
1380  srname, soname, db_time_of_resource(srname, soname));
1381  add_resource_to_make_cache(sres_id);
1382  }
1383  else {
1384  // Check that the sibling is currently obtained by the same rule,
1385  // because an activate might preempt it for some of the
1386  // produced resources?
1387  rule sru = find_rule_by_resource(srname);
1388  if (sru==ru) {
1389  // The rule does not have to be fired again, so its produced
1390  // resources are up-to-date.
1391  string soname = real_resource_owner_name(rpr);
1392 
1393  pips_debug(5, "sibling resource %s(%s) added to up_to_date "
1394  "with time stamp %d\n",
1395  srname, soname, db_time_of_resource(srname, soname));
1396  add_resource_to_make_cache(sres_id);
1397  }
1398  }
1399  }
1400  else {
1401  res_found_p = true;
1402  }
1403  }
1404 
1405  pips_assert("resource res is among the real resources produced by rule ru",
1406  res_found_p);
1407 
1408  gen_full_free_list (real_produced_resources);
1409  }
1410  else
1411  {
1412  /* well, if it is not okay, let us delete it!???
1413  * okay, this might be done later, but in some case it is not.
1414  * I'm not really sure this is the right fix, but at least it avoids
1415  * a coredump after touching some internal file (.f_initial) and
1416  * requesting the PRINTED_FILE for it.
1417  * FC, 22/07/1998
1418  *
1419  * FI: this may be costly and should be avoided on a quit!
1420  *
1421  * FC 2016-11-16: ??? this is a bad idea, because this function we are in
1422  * is called by db_delete_obsolete_resources by a hook, and changing
1423  * the datastructures while scanning them leads to inconsistencies and
1424  * random aborts... see tspear-17.
1425  */
1426  // db_delete_resource(rname, oname);
1427  }
1428 
1429  return result;
1430 }
1431 
1433 {
1434  bool cache_off = !make_cache_p();
1435  // FI: this test breaks the consistency of init() and reset() for
1436  // the make cache
1437  if (cache_off) init_make_cache();
1438  int ndeleted =
1440  if (cache_off) reset_make_cache();
1441  return ndeleted;
1442 }
1443 
1444 /* this is quite ugly, but I wanted to put the enumeration down to pipsdbm.
1445  */
1447 {
1448  const char* what = get_string_property("PIPSDBM_RESOURCES_TO_DELETE");
1450 
1451  user_log("Deletion of %s resources:\n", what);
1452 
1453  if (same_string_p(what, "obsolete"))
1454  {
1455  int ndeleted = delete_obsolete_resources();
1456  if (ndeleted>0) user_log("%d destroyed.\n", ndeleted);
1457  else user_log("none destroyed.\n");
1458  } else if (same_string_p(what, "all")) {
1460  user_log("done.\n");
1461  } else
1462  pips_internal_error("unexpected delete request %s", what);
1463 }
1464 
1465 /* To be used in a rule. use and update the up_to_dat list
1466  * created by makeapply
1467  */
1468 bool check_resource_up_to_date(const char* rname, const char* oname)
1469 {
1470  return db_resource_p(rname, oname)?
1471  check_physical_resource_up_to_date(rname, oname): false;
1472 }
1473 
1474 /* Delete from up_to_date_resources make cache all the resources with
1475  * a given resource name. There is no internal data structure in
1476  * pipsdbm to access these resources efficiently... The two-level
1477  * mapping of database.c must be inverted.
1478  *
1479  * FI: FC claims in an e-mail that this could be done more efficiently
1480  * but does not explain how.
1481  */
1482 void delete_named_resources(const char* rn)
1483 {
1484  pips_assert("make cache is consistent before deletion",
1486 
1487  // firstly, clean up the up-to-date cache if it exists
1488  int count = 0;
1489  if (make_cache_p()) {
1490  list rl = db_retrieve_resources(rn);
1491  FOREACH(STRING, r_id, rl) {
1492  if (make_cache_hit_p(r_id)) {
1494  count++;
1495  }
1496  }
1497  gen_free_list(rl);
1498  }
1499 
1500  pips_debug(8, "Number of resources no longer considered up-to-date: %d\n",
1501  count);
1502 
1503  // Then remove the resource
1504  // GO 29/6/95: many lines ... db_unput_resources_verbose (rn);
1505  int count2 = db_unput_resources(rn);
1506  pips_assert("The number of resources removed from the cache is smaller "
1507  "than the number of resources removed from te database\n",
1508  count<=count2);
1509  pips_assert("make cache is consistent before deletion",
1511 }
1512 
1514 {
1516  reset_make_cache();
1517  init_make_cache();
1518 }
1519 
1520 /* Should be able to handle Fortran applications, C applications and
1521  * mixed Fortran/C applications.
1522  *
1523  * This is a duplicate for pipsdbm function, get_main_entity_name()
1524  */
1526 {
1527  string dir_name = db_get_current_workspace_directory();
1528  string main_name;
1529  string name = string_undefined;
1530 
1531  debug_on("PIPSMAKE_DEBUG_LEVEL");
1532 
1533  // Let's look for a Fortran main
1534  main_name = strdup(concatenate(dir_name, "/", MAIN_FILE_NAMES, NULL));
1535 
1536  if (file_exists_p(main_name))
1537  {
1538  FILE * tmp_file = safe_fopen(main_name, "r");
1539  name = safe_readline(tmp_file);
1540  safe_fclose(tmp_file, main_name);
1541  }
1542  free(main_name);
1543 
1544  if(string_undefined_p(name)) {
1545  // Let's now look for a C main
1546  main_name = strdup(concatenate(dir_name, "/", MAIN_FILE_NAMES, NULL));
1547  if (file_exists_p(main_name))
1548  name = strdup("main");
1549  free(main_name);
1550  }
1551 
1552  free(dir_name);
1553  debug_off();
1554  return name;
1555 }
1556 
1557 /* check the usage of resources
1558  */
1559 void do_resource_usage_check(const char* oname, rule ru)
1560 {
1561  list reals;
1564 
1565  // Get the dbm sets
1567 
1568  // build the real required resrouces
1569  reals = build_real_resources(oname, rule_required (ru));
1570 
1571  // Delete then from the set of read resources
1572  FOREACH(real_resource, rr, reals)
1573  {
1574  string rron = real_resource_owner_name(rr);
1575  string rrrn = real_resource_resource_name(rr);
1576  string elem_name = strdup(concatenate(rron,".", rrrn, NULL));
1577 
1578  if (set_belong_p (res_read, elem_name)){
1579  pips_debug (5, "resource %s.%s has been read: ok\n", rron, rrrn);
1580  set_del_element(res_read, res_read, elem_name);
1581  }
1582  else
1583  user_log("resource %s.%s has not been read\n", rron, rrrn);
1584  }
1585 
1586  // Try to find an illegally read resource ... */
1587  SET_MAP(re, user_log("resource %s has been read\n", re), res_read);
1588  gen_full_free_list(reals);
1589 
1590  // build the real produced resources
1591  reals = build_real_resources(oname, rule_produced(ru));
1592 
1593  // Delete then from the set of written/generated resources
1594  FOREACH(real_resource, rr, reals /*res_write*/)
1595  {
1596  string rron = real_resource_owner_name(rr);
1597  string rrrn = real_resource_resource_name(rr);
1598  string elem_name = strdup(concatenate(rron,".", rrrn, NULL));
1599 
1600  if (set_belong_p (res_write, (void *) elem_name)){
1601  pips_debug (5, "resource %s.%s has been written: ok\n", rron, rrrn);
1602  set_del_element(res_write, res_write, elem_name);
1603  }
1604  else
1605  user_log ("resource %s.%s has not been written\n", rron, rrrn);
1606  }
1607 
1608  // Try to find an illegally written resource ...
1609  SET_MAP(re, user_log ("resource %s has been written\n", re), res_write);
1610 
1611  gen_full_free_list(reals);
1612 
1613  // not free!
1616 }
1617 
1618 
1619 /******************************************************** EXTERNAL INTERFACE */
1620 
1621 static double initial_memory_size;
1622 
1623 static void logs_on(void)
1624 {
1625  if (get_bool_property("LOG_TIMINGS"))
1627 
1628  if (get_bool_property("LOG_MEMORY_USAGE"))
1630 }
1631 
1632 static void logs_off(void)
1633 {
1634  if (get_bool_property("LOG_TIMINGS"))
1635  {
1636  string request_time, phase_time, dbm_time;
1638 
1639  user_log (" stime ");
1641  user_log (" phase time ");
1642  user_log (phase_time);
1643  user_log (" IO stime ");
1644  user_log (dbm_time);
1645  }
1646 
1647  if (get_bool_property("LOG_MEMORY_USAGE"))
1648  {
1649  double final_memory_size = get_process_gross_heap_size();
1650  user_log("\t\t\t\t memory size %10.3f, increase %10.3f\n",
1651  final_memory_size,
1652  final_memory_size-initial_memory_size);
1653  }
1654 }
1655 
1656 static bool safe_do_something(
1657  const char* name,
1658  const char* module_n,
1659  const char* what_it_is,
1660  rule (*find_rule)(const char*),
1661  bool (*doit)(const char*,const char*))
1662 {
1663  bool success = false;
1664 
1665  debug_on("PIPSMAKE_DEBUG_LEVEL");
1666 
1667  if (find_rule(name) == rule_undefined)
1668  {
1669  pips_user_warning("Unknown %s \"%s\"\n", what_it_is, name);
1670  success = false;
1671  debug_off();
1672  return success;
1673  }
1674 
1676 
1678  {
1679  // global variables that have to be reset after user-error
1680  reset_make_cache();
1684  pips_user_warning("Request aborted in pipsmake: "
1685  "build %s %s for module %s.\n",
1686  what_it_is, name, module_n);
1688  success = false;
1689  }
1690  TRY
1691  {
1692  user_log("Request: build %s %s for module %s.\n",
1693  what_it_is, name, module_n);
1694  logs_on();
1696 
1697  // DO IT HERE!
1698  success = doit(name, module_n);
1699 
1700  if(success)
1701  {
1702  user_log("%s made for %s.\n", name, module_n);
1703  logs_off();
1704  }
1705  else
1706  {
1707  pips_user_warning("Request aborted under pipsmake: "
1708  "build %s %s for module %s.\n",
1709  what_it_is, name, module_n);
1710  }
1712  }
1713  debug_off();
1714  return success;
1715 }
1716 
1717 bool safe_make(const char* res_n, const char* module_n)
1718 {
1719  return safe_do_something(res_n, module_n, "resource",
1721 }
1722 
1723 bool safe_apply(const char* phase_n, const char* module_n)
1724 {
1725  return safe_do_something(phase_n, module_n, "phase/rule",
1727 }
1728 
1730  const char* phase_n,
1731  gen_array_t modules)
1732 {
1733  bool ok = true;
1734  debug_on("PIPSMAKE_DEBUG_LEVEL");
1735 
1736  // Get a human being representation of the modules:
1737  string module_list = strdup(string_array_join(modules, ","));
1738 
1739  if (find_rule_by_phase(phase_n)==rule_undefined)
1740  {
1741  pips_user_warning("Unknown phase \"%s\"\n", phase_n);
1742  ok = false;
1743  }
1744  else
1745  {
1747  {
1748  reset_make_cache();
1750  pips_user_warning("Request aborted in pipsmake\n");
1751  ok = false;
1752 
1754  RETHROW();
1755  }
1756  TRY
1757  {
1758  logs_on();
1759  user_log("Request: capply %s for module [%s].\n", phase_n, module_list);
1760 
1761  ok = concurrent_apply(phase_n, modules);
1762 
1763  if (ok) {
1764  user_log("capply %s made for [%s].\n", phase_n, module_list);
1765  logs_off();
1766  }
1767  else {
1768  pips_user_warning("Request aborted under pipsmake: "
1769  "capply %s for module [%s].\n",
1770  phase_n, module_list);
1771  }
1773  }
1774  }
1775 
1776  free(module_list);
1777  debug_off();
1778  return ok;
1779 }
1780 
1781 bool safe_set_property(const char* propname, const char* value)
1782 {
1783  size_t len = strlen(propname) + strlen(value) + 2;
1784  char* line = calloc(len, sizeof(char));
1785  strcat(line, propname);
1786  strcat(line, " ");
1787  strcat(line, value);
1788  user_log("set %s\n", line);
1789  parse_properties_string(line, false);
1790  free(line);
1791  // parse_properties_string() doesn't return whether it succeeded
1792  return true;
1793 }
1794 
1795 /* Get all the callers of the specified module.
1796  The returned value is allocated dynamically
1797  and needs to be freed by the caller of this function
1798 */
1800 {
1801  callees caller_modules;
1802 
1803  if (!safe_make(DBR_CALLERS, module))
1804  pips_internal_error("Cannot make callers for %s", module);
1805 
1806  caller_modules = (callees)
1807  db_get_memory_resource(DBR_CALLERS, module,true);
1808 
1809  return gen_array_from_list(callees_callees(caller_modules));
1810 }
1811 
1812 /* Get all the callers of the specified module.
1813  The returned value is allocated dynamically
1814  and needs to be freed by the caller of this function
1815 */
1817 {
1818  callees callee_modules;
1819 
1820  if (!safe_make(DBR_CALLEES, module))
1821  pips_internal_error("Cannot make callees for %s", module);
1822 
1823  callee_modules = (callees)
1824  db_get_memory_resource(DBR_CALLEES, module,true);
1825 
1826  return gen_array_from_list(callees_callees(callee_modules));
1827 }
int get_int_property(const string)
void user_log(const char *format,...)
Definition: message.c:234
void set_pips_current_computation(const char *rname, const char *oname)
message.c
Definition: message.c:65
void reset_pips_current_computation(void)
Definition: message.c:87
string db_resource_name(void *dbr)
To be used for debugging.
Definition: database.c:1000
bool db_resource_is_required_p(const char *rname, const char *oname)
true if exists and in required state.
Definition: database.c:512
void db_print_all_required_resources(FILE *file)
Definition: database.c:421
void db_clean_all_required_resources(void)
Definition: database.c:460
list db_retrieve_resources(const char *rname)
Retrieve all the db resources of a given resource type, "rname".
Definition: database.c:943
int db_time_of_resource(const char *rname, const char *oname)
Definition: database.c:603
bool db_resource_p(const char *rname, const char *oname)
true if exists and in loaded or stored state.
Definition: database.c:524
void db_set_resource_as_required(const char *rname, const char *oname)
Definition: database.c:797
bool db_touch_resource(const char *rname, const char *oname)
touch logical time for resource[owner], possibly behind the back of pipsdbm.
Definition: database.c:538
int db_delete_obsolete_resources(bool(*keep_p)(const char *, const char *))
delete all obsolete resources before a close.
Definition: database.c:1076
void db_delete_all_resources(void)
FC: I added this function to clean all resources, hence avoiding to save them.
Definition: database.c:1030
int db_unput_resources(const char *rname)
Delete all the resources of a given type "rname".
Definition: database.c:915
string db_get_resource_id(const char *rname, const char *oname)
some way to identify a resource...
Definition: database.c:704
string db_resource_owner_name(void *dbr)
To be used for debugging.
Definition: database.c:1006
static int count
Definition: SDG.c:519
bool active_phase_p(const char *phase)
Definition: activate.c:80
const char * activate(const char *phase)
Definition: activate.c:214
void save_active_phases(void)
activate.c
Definition: activate.c:49
void retrieve_active_phases(void)
Definition: activate.c:58
#define CATCH(what)
@ timeout_error
@ any_exception_error
catch all
#define UNCATCH(what)
#define RETHROW()
#define TRY
void const char const char const int
linear_exception_t the_last_just_thrown_exception
void linear_reset_error_counters(void)
reset linear counters
Definition: errors.c:75
void linear_get_error_counts(unsigned int *, unsigned int *, unsigned int *)
return various errors counts through unsigned int pointer overflow, simplex & misc (aka others) NULL ...
Definition: errors.c:94
bool linear_require_gmp(void)
whether linear is asked to use gmp if possible (env variable)
Definition: errors.c:446
unsigned int linear_error_count(void)
return number of linear errors may be used as a test after a reset to know whether new errors occured...
Definition: errors.c:85
bool linear_with_gmp(void)
whether linear can use gmp (i.e.
Definition: errors.c:435
void gen_array_full_free(gen_array_t a)
Definition: array.c:77
string string_array_join(gen_array_t array, string separator)
Join a string array with a string separator.
Definition: array.c:198
gen_array_t gen_array_from_list(list ls)
Definition: array.c:170
string compilation_unit_name
cproto-generated files
Definition: c_parser.c:49
bool run_pipsmake_callback()
Definition: callback.c:59
string compilation_unit_of_module(const char *)
The output is undefined if the module is referenced but not defined in the workspace,...
Definition: module.c:350
void error_reset_cumulated_rw_effects(void)
void proper_effects_error_handler(void)
void error_reset_invariant_rw_effects(void)
void error_reset_proper_rw_effects(void)
void error_reset_rw_effects(void)
bool compilation_unit_p(const char *module_name)
The names of PIPS entities carry information about their nature.
Definition: entity_names.c:56
FILE * safe_fopen(const char *filename, const char *what)
Definition: file.c:67
bool file_exists_p(const char *name)
Definition: file.c:321
char * get_string_property(const char *)
int safe_fclose(FILE *stream, const char *filename)
Definition: file.c:77
char * safe_readline(FILE *file)
returns the allocated line read, whatever its length.
Definition: file.c:497
bool get_bool_property(const string)
FC 2015-07-20: yuk, moved out to prevent an include cycle dependency include "properties....
#define STRING(x)
Definition: genC.h:87
void gen_full_free_list(list l)
Definition: genClib.c:1023
void free(void *)
bool success
Definition: gpips-local.h:59
#define ENDP(l)
Test if a list is empty.
Definition: newgen_list.h:66
list gen_nreverse(list cp)
reverse a list in place
Definition: list.c:304
#define NIL
The empty list (nil in Lisp)
Definition: newgen_list.h:47
size_t gen_length(const list l)
Definition: list.c:150
void gen_free_string_list(list ls)
Definition: list.c:564
#define CAR(pcons)
Get the value of the first element of a list.
Definition: newgen_list.h:92
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 CDR(pcons)
Get the list less its first element.
Definition: newgen_list.h:111
list gen_copy_string_list(list ls)
of string
Definition: list.c:556
string db_get_memory_resource(const char *rname, const char *oname, bool pure)
Return the pointer to the resource, whatever it is.
Definition: database.c:755
gen_array_t db_get_module_list(void)
Get an array of all the modules (functions, procedures and compilation units) of a workspace.
Definition: database.c:1266
#define rule_modified(x)
Definition: makefile.h:252
#define rule_post_transformation(x)
Definition: makefile.h:256
#define rule_phase(x)
Definition: makefile.h:244
#define REAL_RESOURCE(x)
REAL_RESOURCE.
Definition: makefile.h:173
#define RULE(x)
RULE.
Definition: makefile.h:209
#define virtual_resource_owner(x)
Definition: makefile.h:292
#define rule_pre_transformation(x)
Definition: makefile.h:254
#define real_resource_owner_name(x)
Definition: makefile.h:205
#define owner_tag(x)
Definition: makefile.h:145
#define rule_required(x)
Definition: makefile.h:246
#define owner_callers_p(x)
Definition: makefile.h:158
#define rule_undefined
Definition: makefile.h:215
#define rule_preserved(x)
Definition: makefile.h:250
#define virtual_resource_name(x)
Definition: makefile.h:290
#define makefile_active_phases(x)
Definition: makefile.h:84
@ is_owner_main
Definition: makefile.h:111
@ is_owner_callees
Definition: makefile.h:112
@ is_owner_select
Definition: makefile.h:115
@ is_owner_compilation_unit
Definition: makefile.h:116
@ is_owner_module
Definition: makefile.h:110
@ is_owner_callers
Definition: makefile.h:113
@ is_owner_all
Definition: makefile.h:114
@ is_owner_program
Definition: makefile.h:109
#define real_resource_resource_name(x)
Definition: makefile.h:203
#define rule_produced(x)
Definition: makefile.h:248
#define owner_callees_p(x)
Definition: makefile.h:155
#define VIRTUAL_RESOURCE(x)
VIRTUAL_RESOURCE.
Definition: makefile.h:260
#define owner_select_p(x)
Definition: makefile.h:164
#define makefile_rules(x)
Definition: makefile.h:82
void pips_malloc_debug()
include <sys/stdtypes.h>
Definition: malloc_debug.c:34
#define debug_on(env)
Definition: misc-local.h:157
#define pips_debug
these macros use the GNU extensions that allow variadic macros, including with an empty list.
Definition: misc-local.h:145
#define pips_user_warning
Definition: misc-local.h:146
#define pips_assert(what, predicate)
common macros, two flavors depending on NDEBUG
Definition: misc-local.h:172
#define pips_internal_error
Definition: misc-local.h:149
#define debug_off()
Definition: misc-local.h:160
#define pips_user_error
Definition: misc-local.h:147
void set_debug_stack_pointer(const int i)
Definition: debug.c:97
void debug(const int the_expected_debug_level, const char *calling_function_name, const char *a_message_format,...)
ARARGS0.
Definition: debug.c:189
double get_process_gross_heap_size(void)
Definition: debug.c:254
_int get_debug_stack_pointer(void)
The pair get_ and set_debug_stack_pointer() should never be used except to clean up the stack after a...
Definition: debug.c:92
void reset_hooks_is_empty(void)
check that the stack was cleaned.
Definition: reset_hooks.c:66
void reset_hooks_call(void)
this function is expected to be called when catching an exception.
Definition: reset_hooks.c:53
#define GEN_ARRAY_FOREACH(type, s, array)
Definition: newgen_array.h:50
string concatenate(const char *,...)
Return the concatenation of the given strings.
Definition: string.c:183
#define same_string_p(s1, s2)
set set_del_element(set, const set, const void *)
Definition: set.c:265
#define set_undefined
Definition: newgen_set.h:48
#define SET_MAP(element, code, the_set)
Definition: newgen_set.h:54
#define SET_FOREACH(type_name, the_item, the_set)
enumerate set elements in their internal order.
Definition: newgen_set.h:78
void set_free(set)
Definition: set.c:332
set set_clear(set)
Assign the empty set to s s := {}.
Definition: set.c:326
bool set_belong_p(const set, const void *)
Definition: set.c:194
@ set_pointer
Definition: newgen_set.h:44
#define set_undefined_p(s)
Definition: newgen_set.h:49
set set_make(set_type)
Create an empty set of any type but hash_private.
Definition: set.c:102
set set_add_element(set, const set, const void *)
Definition: set.c:152
int tag
TAG.
Definition: newgen_types.h:92
#define string_undefined
Definition: newgen_types.h:40
char * string
STRING.
Definition: newgen_types.h:39
#define string_undefined_p(s)
Definition: newgen_types.h:41
intptr_t _int
_INT
Definition: newgen_types.h:53
void checkpoint_workspace(void)
checkpoint the current workspace, i.e.
Definition: openclose.c:129
static char * module
Definition: pips.c:74
#define db_unput_a_resource(r, o)
#define MAIN_FILE_NAMES
Name of the file containing the names of the main procedures.
Definition: pipsdbm-local.h:41
void get_request_string_timers(string *global, string *phases, string *dbm)
compute times elapsed since init_request_log_timers(), i.e.
Definition: misc.c:196
static set res_read
Sets of the readwrite resources by pipsdbm.
Definition: misc.c:236
void init_request_timers()
Functions for timing one request.
Definition: misc.c:106
static struct tms dbm_time
Definition: misc.c:81
static set res_write
Definition: misc.c:237
static struct tms request_time
Timing of one request.
Definition: misc.c:68
void get_string_timers(string *with_io, string *io)
compute times elapsed since init_log_timers(), i.e.
Definition: misc.c:155
void get_logged_resources(set *sr, set *sw)
Get the made sets.
Definition: misc.c:268
void init_log_timers()
Functions for timing one phase.
Definition: misc.c:122
bool interrupt_pipsmake_asap_p()
Definition: misc.c:58
void init_resource_usage_check()
init variables
Definition: misc.c:240
void dont_interrupt_pipsmake_asap()
Definition: misc.c:53
static struct tms phase_time
Timing of one phase.
Definition: misc.c:78
int db_inc_logical_time(void)
0 means not set...
Definition: workspace.c:107
string db_get_current_workspace_directory(void)
Definition: workspace.c:96
rule find_rule_by_phase(const char *)
this function returns the rule that defines builder pname
makefile parse_makefile(void)
static bool apply_a_rule(const char *oname, rule ru)
Definition: pipsmake.c:578
void delete_some_resources(void)
this is quite ugly, but I wanted to put the enumeration down to pipsdbm.
Definition: pipsmake.c:1446
gen_array_t get_callers(string module)
Get all the callers of the specified module.
Definition: pipsmake.c:1799
rule find_rule_by_resource(const char *rname)
This function returns the active rule to produce resource rname.
Definition: pipsmake.c:694
void add_resource_to_make_cache(void *res_id)
Definition: pipsmake.c:225
void reset_static_phase_variables()
Static variables used by phases must be reset on error although pipsmake does not know which ones are...
Definition: pipsmake.c:298
bool make_cache_p()
Can the make cache be used?
Definition: pipsmake.c:207
bool check_resource_up_to_date(const char *rname, const char *oname)
To be used in a rule.
Definition: pipsmake.c:1468
static bool make_required(const char *, rule)
compute all real resources needed to apply a rule "ru" on an object related to owner "oname".
Definition: pipsmake.c:1116
static bool check_physical_resource_up_to_date(const char *rname, const char *oname)
returns whether resource is up to date.
Definition: pipsmake.c:1257
static bool apply_without_reseting_up_to_date_resources(const char *pname, const char *oname)
Apply do NOT activate the rule applied.
Definition: pipsmake.c:778
gen_array_t get_callees(string module)
Get all the callers of the specified module.
Definition: pipsmake.c:1816
static void logs_on(void)
Definition: pipsmake.c:1623
int delete_obsolete_resources(void)
Definition: pipsmake.c:1432
bool make_cache_consistent_p()
Debug function: make sure that up-to-date resources do exist in the resource database.
Definition: pipsmake.c:275
void remove_resource_from_make_cache(void *res_id)
Definition: pipsmake.c:239
string get_first_main_module(void)
Should be able to handle Fortran applications, C applications and mixed Fortran/C applications.
Definition: pipsmake.c:1525
static void logs_off(void)
Definition: pipsmake.c:1632
static rule safe_find_rule_by_resource(const char *rname)
Always returns a defined rule.
Definition: pipsmake.c:751
void set_current_phase_context(const char *rname, const char *oname)
cproto-generated files
Definition: pipsmake.c:89
static bool safe_do_something(const char *name, const char *module_n, const char *what_it_is, rule(*find_rule)(const char *), bool(*doit)(const char *, const char *))
Definition: pipsmake.c:1656
void print_make_cache()
Debug function, to be tested...
Definition: pipsmake.c:251
static bool concurrent_apply(const char *pname, gen_array_t modules)
Definition: pipsmake.c:1048
void init_make_cache(void)
Definition: pipsmake.c:199
bool safe_make(const char *res_n, const char *module_n)
Definition: pipsmake.c:1717
static builder_func_t get_builder(const char *name)
Definition: pipsmake.c:163
static bool make_pre_post_transformation(const char *oname, rule ru, list transformations)
compute all pre or post-transformations to apply a rule on an object or activate a phase if owner is ...
Definition: pipsmake.c:811
#define DECLARE_ERROR_HANDLER(name)
static bool make_pre_transformation(const char *, rule)
FI: guard added to simplify debugging and to call make_pre_post_transformation() only when it is usef...
Definition: pipsmake.c:871
void delete_named_resources(const char *rn)
Delete from up_to_date_resources make cache all the resources with a given resource name.
Definition: pipsmake.c:1482
void reset_current_phase_context(void)
Definition: pipsmake.c:96
void reset_make_cache(void)
Definition: pipsmake.c:191
static list build_real_resources(const char *oname, list lvr)
Translate and expand a list of virtual resources into a potentially much longer list of real resource...
Definition: pipsmake.c:355
static bool make(const char *rname, const char *oname)
Definition: pipsmake.c:893
static set up_to_date_resources
FI: pipsmmake is very slow when interprocedural analyzes have been selected; some memoization has bee...
Definition: pipsmake.c:189
bool safe_concurrent_apply(const char *phase_n, gen_array_t modules)
Definition: pipsmake.c:1729
void delete_all_resources(void)
Definition: pipsmake.c:1513
static double initial_memory_size
Definition: pipsmake.c:1621
bool make_cache_hit_p(void *rr_id)
Definition: pipsmake.c:219
void do_resource_usage_check(const char *oname, rule ru)
check the usage of resources
Definition: pipsmake.c:1559
static void update_preserved_resources(const char *oname, rule ru)
Definition: pipsmake.c:537
void reinit_make_cache_if_necessary(void)
Definition: pipsmake.c:212
static bool apply(const char *pname, const char *oname)
Definition: pipsmake.c:1028
#define add_res(vrn, on)
Apply an instantiated rule with a given ressource owner.
Definition: pipsmake.c:337
bool rmake(const char *rname, const char *oname)
recursive make resource.
Definition: pipsmake.c:919
static bool make_post_transformation(const char *, rule)
FI: guard added to simplify debugging and to call make_pre_post_transformation() only when it is usef...
Definition: pipsmake.c:882
bool safe_set_property(const char *propname, const char *value)
Definition: pipsmake.c:1781
bool safe_apply(const char *phase_n, const char *module_n)
Definition: pipsmake.c:1723
static void preserve_virtual_resource(const char *oname, virtual_resource vr)
touch the resource if it exits this is currently an experimental and partial implementation
Definition: pipsmake.c:510
static bool catch_user_error(builder_func_t builder, const char *rname, const char *oname)
call builder to build a resource for something.
Definition: pipsmake.c:106
static list called_modules
list of called subroutines or functions
Definition: procedure.c:57
void parse_properties_string(char *s, bool processing_p)
properties.c
Definition: properties.c:823
entity local_name_to_top_level_entity(const char *n)
This function try to find a top-level entity from a local name.
Definition: entity.c:1450
bool entity_main_module_p(entity e)
Definition: entity.c:700
void reset_std_static_entities()
Definition: entity.c:138
void error_reset_current_module_statement(void)
To be called by an error management routine only.
Definition: static.c:234
void entity_basic_concrete_types_init(void)
Definition: type.c:3507
void error_reset_current_module_entity(void)
To be called by an error management routine only.
Definition: static.c:109
void entity_basic_concrete_types_reset(void)
Definition: type.c:3513
struct _newgen_struct_callees_ * callees
Definition: ri.h:55
#define callees_callees(x)
Definition: ri.h:675
char * strdup()
int printf()
static int line
FLEX_SCANNER.
Definition: scanner.c:852
void reset_total_precondition_map(void)
void reset_precondition_map(void)
void reset_transformer_map(void)
#define ifdebug(n)
Definition: sg.c:47
static bool ok
FI: I do not understand why the type is duplicated at the set level.
Definition: set.c:59
The structure used to build lists in NewGen.
Definition: newgen_list.h:41
static list transformations
transformation>
Definition: vectransform.c:41