PIPS
identification.c
Go to the documentation of this file.
1 /*
2 
3  $Id: identification.c 23495 2018-10-24 09:19:47Z coelho $
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 #include "safescale.h"
28 
29 
30 /**
31 
32  */
33 static void search_sequence_containing(statement s, void* a_context)
34 {
37 
39  {
40  MAP(STATEMENT, s2, {
41  if (s2 == context->searched_statement)
42  {
43  context->found_sequence_statement = s;
44  }
46  }
47 }
48 
49 
50 /**
51 
52 */
53 static statement sequence_statement_containing(statement root_statement, statement searched_stat)
54 {
56 
57  context.searched_statement = searched_stat;
58  context.found_sequence_statement = NULL;
59 
61 
62  return context.found_sequence_statement;
63 }
64 
65 
66 /**
67 
68  */
69 static bool statement_is_contained_in_a_sequence_p(statement root_statement, statement searched_stat)
70 {
71  return (sequence_statement_containing(root_statement, searched_stat) != NULL);
72 }
73 
74 
75 /**
76  Add in the statement containing comments in the list of statements
77  */
78 static void check_if_statement_contains_comment(statement s, void* a_context)
79 {
81  string comments;
82 
84  {
85  comments = statement_comments(s);
86 
87  if (strstr(comments, context->searched_string) != NULL)
88  {
89  context->list_of_statements = CONS(STATEMENT, s, context->list_of_statements);
90  }
91  }
92 }
93 
94 
95 /**
96  Build a list with statements containing comments
97  */
98 static list get_statements_with_comments_containing(string comment_portion, statement stat)
99 {
100  string percent;
102 
103  ifdebug(5)
104  {
105  pips_debug(5, "Comment portion: %s\n", comment_portion);
106  pips_debug(5, "Statement:\n");
107  print_statement(stat);
108  }
109 
110  /* Set searched string */
111  context.searched_string = strdup(comment_portion);
112  percent = strstr(context.searched_string, "%s");
113 
114  pips_debug(5, "Percent: %s\n", percent);
115 
116  if (percent == NULL)
117  pips_user_error("Malformed statement comment to search. Should be of the form 'BLAH_%%s'\n");
118 
119  *percent = '\0';
120 
121  /* Reset and get list of statements */
122  context.list_of_statements = NIL;
123 
124  ifdebug(5)
125  {
126  pips_debug(5, "Searching statements with comments: %s\n", context.searched_string);
127  pips_debug(5, "In statement:\n");
128  print_statement(stat);
129  }
130 
132 
133  free(context.searched_string);
134 
135  return context.list_of_statements;
136 }
137 
138 
139 /**
140  Return the identified function name of the externalized portion of code by searching comment matching tag
141  */
143 {
144  string comments = NULL;
145  string searched_string;
146  string comment_portion = strdup(tag);
147  char* function_name = NULL;
148  char* next_line;
150 
151  pips_debug(5, "BEGIN get_function_name_by_searching_tag [%s] on \n", tag);
152 
153  ifdebug(5)
154  {
155  print_statement(stat);
156  }
157 
159  {
161  }
162 
163  if (!statement_with_empty_comment_p(stat))
164  {
165  searched_string = strdup(comment_portion);
166  searched_string[strcspn(comment_portion, "%s")] = '\0';
167  comments = strdup(statement_comments(stat));
168  next_line = strtok(comments, "\n");
169 
170  if (next_line != NULL)
171  {
172  do
173  {
174  string first_occurence = strstr(next_line, searched_string);
175 
176  if (first_occurence != NULL)
177  {
178  function_name = malloc(256);
179  sscanf(first_occurence, comment_portion, function_name);
180  pips_debug(5, "Found function: [%s]\n", function_name);
181  }
182 
183  next_line = strtok(NULL, "\n");
184  }
185  while (next_line != NULL);
186  }
187  }
188 
189  free(comment_portion);
190  if (comments)
191  free(comments);
192 
193  pips_debug(5, "END get_function_name_by_searching_tag [%s] on \n", tag);
194 
195  return function_name;
196 }
197 
198 
199 /**
200 
201  */
202 static void clean_statement_from_tags(string comment_portion, statement stat)
203 {
204  if (!statement_with_empty_comment_p(stat))
205  {
206  string new_comments = NULL;
207 
208  string searched_string = strdup(comment_portion);
209  searched_string[strcspn(comment_portion, "%s")] = '\0';
210  string comments = strdup(statement_comments(stat));
211  char * next_line = strtok(comments, "\n");
212 
213  if (next_line != NULL)
214  {
215  do
216  {
217  if (strstr(next_line, searched_string) == NULL)
218  {
219  if (new_comments != NULL)
220  {
221  new_comments = strdup(concatenate(new_comments, next_line, "\n", NULL));
222  }
223  else
224  {
225  new_comments = strdup(concatenate("", next_line, "\n", NULL));
226  }
227  }
228 
229  next_line = strtok(NULL, "\n");
230  }
231  while (next_line != NULL);
232  }
233 
234  if (new_comments != NULL)
235  {
236  statement_comments(stat) = new_comments;
237  }
238  else
239  {
241  free(new_comments);
242  }
243  free(searched_string);
244  free(comments);
245  }
246 }
247 
248 
249 /**
250  Remove begin tag for a given statement and function
251  */
252 static void remove_begin_tag(statement stat, string function_name)
253 {
254  char* removed_tag = malloc(256);
255 
256  sprintf(removed_tag, EXTERNALIZED_CODE_PRAGMA_BEGIN, function_name);
257  pips_debug(2, "REMOVE %s from\n", removed_tag);
258  print_statement(stat);
259  clean_statement_from_tags(removed_tag, stat);
260 }
261 
262 
263 /**
264  Remove end tag for given statement and function
265  */
266 static void remove_end_tag(statement stat, string function_name)
267 {
268  char* removed_tag = malloc(256);
269 
270  sprintf(removed_tag, EXTERNALIZED_CODE_PRAGMA_END, function_name);
271  pips_debug(2, "REMOVE %s from\n", removed_tag);
272  print_statement(stat);
273  clean_statement_from_tags(removed_tag, stat);
274 }
275 
276 
277 /**
278  Transform a statement in a sequence statement with a single statement which is the embedded statement that will be distributed
279  */
280 static statement isolate_code_portion(statement begin_tag_statement, statement end_tag_statement, statement sequence_statement)
281 {
282  instruction i = statement_instruction(sequence_statement);
284  list new_seq_stats = NIL;
285  list isolated_seq_stats = NIL;
286  bool statement_to_isolate = false;
287  int nb_of_statements_to_isolate = 0;
288  string function_name = get_function_name_by_searching_tag(begin_tag_statement, EXTERNALIZED_CODE_PRAGMA_BEGIN);
289 
290  pips_assert("sequence_statement is a sequence", instruction_tag(i) == is_instruction_sequence);
291  pips_assert("function_name is not NULL", function_name != NULL);
292 
293  /* Count the number of statements to isolate in a single statement */
294  MAP(STATEMENT, s, {
295  if ((statement_to_isolate && (s != end_tag_statement)) || ((!statement_to_isolate) && (s == begin_tag_statement)))
296  {
297  nb_of_statements_to_isolate++;
298  isolated_seq_stats = CONS(STATEMENT, s, isolated_seq_stats);
299  }
300 
301  if (statement_to_isolate && (s == end_tag_statement))
302  {
303  statement_to_isolate = false;
304  }
305 
306  if ((!statement_to_isolate) && (s == begin_tag_statement))
307  {
308  statement_to_isolate = true;
309  }
310  }, seq_stats);
311 
312  remove_begin_tag(begin_tag_statement, function_name);
313  remove_end_tag(end_tag_statement, function_name);
314 
315  /* Insert an analyzed tag */
316  {
317  char *new_tag = malloc(256);
318 
319  sprintf(new_tag, strdup(concatenate("\n", EXTERNALIZED_CODE_PRAGMA_ANALYZED_PREFIX_TOP, EXTERNALIZED_CODE_PRAGMA_ANALYZED_TOP, "\n", NULL)), function_name, nb_of_statements_to_isolate);
320  insert_comments_to_statement(begin_tag_statement, new_tag);
321  }
322 
323  pips_debug(5, "Found %d statement to isolate\n", nb_of_statements_to_isolate);
324 
325  if (nb_of_statements_to_isolate > 1)
326  {
327  /* Build a new isolated sequence statement */
328  sequence new_sequence = make_sequence(gen_nreverse(isolated_seq_stats));
329  instruction sequence_instruction = make_instruction(is_instruction_sequence, new_sequence);
330  statement returned_statement = make_statement (entity_empty_label(),
331  statement_number(sequence_statement),
332  statement_ordering(sequence_statement),
334  sequence_instruction,
335  NIL,
336  NULL,
337  statement_extensions (sequence_statement), make_synchronization_none());
338  bool isolated_seq_stats_is_inserted = false;
339 
340  /* Build a new sequence containing isolated sequence statement */
341  MAP(STATEMENT, s, {
342  if ((statement_to_isolate && (s != end_tag_statement)) || ((!statement_to_isolate) && (s == begin_tag_statement)))
343  {
344  if (!isolated_seq_stats_is_inserted)
345  {
346  new_seq_stats = CONS(STATEMENT, returned_statement, new_seq_stats);
347  isolated_seq_stats_is_inserted = true;
348  }
349  }
350  else
351  {
352  new_seq_stats = CONS(STATEMENT, s, new_seq_stats);
353  }
354 
355  if (statement_to_isolate && (s == end_tag_statement))
356  {
357  statement_to_isolate = false;
358  }
359 
360  if ((!statement_to_isolate) && (s == begin_tag_statement))
361  {
362  statement_to_isolate = true;
363  }
364  }, seq_stats);
365 
366  /* Rebuild the sequence in the good order */
368 
369  ifdebug(5)
370  {
371  pips_debug(5,"Isolating and returning statement:\n");
372  print_statement(returned_statement);
373  }
374 
375  return returned_statement;
376  }
377  else if (nb_of_statements_to_isolate == 1)
378  {
379  /* Nothing to do, the code is already isolated ! */
380  ifdebug(5)
381  {
382  pips_debug(5,"Isolating and returning statement:\n");
383  print_statement(begin_tag_statement);
384  }
385 
386  return begin_tag_statement;
387  }
388  else
389  {
390  pips_user_warning("Malformed externalized code portion identified. No operation to do. Ignored.\n");
391  return NULL;
392  }
393 }
394 
395 
396 /**
397  Return a list of statements that are marked for externalization
398  */
400 {
401  list statements_containing_begin_tag;
402  list statements_contained_in_a_sequence = NIL;
403  list statements_to_distribute = NIL;
404 
405  /* Restructure code to avoid imbricated sequences if some portions are found to allow more than one INIT */
406  simple_restructure_statement(module_stat);
407 
408  /* Identify statements containing a begin tag */
409  statements_containing_begin_tag = get_statements_with_comments_containing(EXTERNALIZED_CODE_PRAGMA_BEGIN, module_stat);
410 
411  /* Check all statements are contained in a sequence */
412  MAP(STATEMENT, s, {
413  ifdebug(5)
414  {
415  pips_debug(5, "Potential externalizable statement:\n");
416  print_statement(s);
417  }
418 
419  if (statement_is_contained_in_a_sequence_p(module_stat,s))
420  {
421  statements_contained_in_a_sequence = CONS(STATEMENT, s, statements_contained_in_a_sequence);
422  }
423  else
424  {
425  pips_user_warning("Malformed externalized code portion identified. Ignored.\n");
426  }
427  }, statements_containing_begin_tag);
428 
429  /* */
430  MAP(STATEMENT, s, {
431  statement sequence_statement;
432  string function_name;
433  list potential_end_statement = NIL;
434 
435  sequence_statement = sequence_statement_containing(module_stat, s);
436 
437  pips_debug(5, "Potential externalizable statement contained in a sequence \n");
438  print_statement(s);
439 
441 
442  if (function_name != NULL)
443  {
444  pips_debug(5, "Name: [%s] \n", function_name);
445 
446  potential_end_statement = get_statements_with_comments_containing(EXTERNALIZED_CODE_PRAGMA_END, sequence_statement);
447 
448  if (gen_length(potential_end_statement) == 1)
449  {
450  statement begin_tag_statement = s;
451  statement end_tag_statement = STATEMENT(gen_nth(0, potential_end_statement));
452  statement container_of_end_tag_statement = sequence_statement_containing(sequence_statement, end_tag_statement);
453 
454  if (container_of_end_tag_statement == sequence_statement)
455  {
456  statement externalized_code = isolate_code_portion(begin_tag_statement, end_tag_statement, sequence_statement);
457 
458  statements_to_distribute = CONS(STATEMENT, externalized_code, statements_to_distribute);
459  }
460  else
461  {
462  pips_user_warning("Malformed externalized code portion identified [%s]. End tag found at a bad place!!!. Ignored.\n", function_name);
463  }
464  }
465  else
466  {
467  pips_user_warning("Malformed externalized code portion identified [%s]. %d end tags found!!!. Ignored.\n", function_name, gen_length(potential_end_statement));
468  }
469  }
470  else
471  {
472  pips_user_warning("Malformed externalized code portion identified [Unnamed]!!!. Ignored.\n");
473  }
474  }, statements_contained_in_a_sequence);
475 
476  return statements_to_distribute;
477 }
478 
479 
480 /**
481  Main phase for block code detection
482 */
484 {
485  /* Get the resources */
486  statement stat = (statement) db_get_memory_resource(DBR_CODE, module_name, true);
487 
488 
491 
492  debug_on("SAFESCALE_DISTRIBUTOR_DEBUG_LEVEL");
493 
494  /* Doi the job */
495  pips_debug(2, "BEGIN of SAFESCALE_DISTRIBUTOR_INIT\n");
497  pips_debug(2, "END of SAFESCALE_DISTRIBUTOR_INIT\n");
498 
499  pips_assert("Statement structure is consistent after SAFESCALE_DISTRIBUTOR_INIT", gen_consistent_p((gen_chunk*) stat));
500  pips_assert("Statement is consistent after SAFESCALE_DISTRIBUTOR_INIT", statement_consistent_p(stat));
501 
502  /* Reorder the module because new statements have been added */
503  module_reorder(stat);
504  DB_PUT_MEMORY_RESOURCE(DBR_CODE, module_name, stat);
506 
507  /* Update/release resources */
510 
511  debug_off();
512 
513  return true;
514 }
bool statement_consistent_p(statement p)
Definition: ri.c:2195
statement make_statement(entity a1, intptr_t a2, intptr_t a3, string a4, instruction a5, list a6, string a7, extensions a8, synchronization a9)
Definition: ri.c:2222
instruction make_instruction(enum instruction_utype tag, void *val)
Definition: ri.c:1166
synchronization make_synchronization_none(void)
Definition: ri.c:2424
sequence make_sequence(list a)
Definition: ri.c:2125
callees compute_callees(const statement stat)
Recompute the callees of a module statement.
Definition: callgraph.c:355
struct _newgen_struct_statement_ * statement
Definition: cloning.h:21
void simple_restructure_statement(statement)
A simple cleaning of the control graph without major topological restructuring.
const char * module_name(const char *s)
Return the module part of an entity name.
Definition: entity_names.c:296
#define gen_context_recurse(start, ctxt, domain_number, flt, rwt)
Definition: genC.h:285
int gen_consistent_p(gen_chunk *obj)
GEN_CONSISTENT_P dynamically checks the type correctness of OBJ.
Definition: genClib.c:2398
void * malloc(YYSIZE_T)
void free(void *)
void reset_current_module_entity(void)
Reset the current module entity.
Definition: static.c:97
void reset_current_module_statement(void)
Reset the current module statement.
Definition: static.c:221
statement set_current_module_statement(statement)
Set the current module statement.
Definition: static.c:165
entity set_current_module_entity(entity)
static.c
Definition: static.c:66
bool gen_true2(__attribute__((unused)) gen_chunk *u1, __attribute__((unused)) void *u2)
Definition: genClib.c:2785
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
#define CONS(_t_, _i_, _l_)
List element cell constructor (insert an element at the beginning of a list)
Definition: newgen_list.h:150
gen_chunk gen_nth(int n, const list l)
to be used as ENTITY(gen_nth(3, l))...
Definition: list.c:710
#define MAP(_map_CASTER, _map_item, _map_code, _map_list)
Apply/map an instruction block on all the elements of a list (old fashioned)
Definition: newgen_list.h:226
string db_get_memory_resource(const char *rname, const char *oname, bool pure)
Return the pointer to the resource, whatever it is.
Definition: database.c:755
#define DB_PUT_MEMORY_RESOURCE(res_name, own_name, res_val)
conform to old interface.
Definition: pipsdbm-local.h:66
void insert_comments_to_statement(statement, const char *)
Insert a comment string (if non empty) at the beginning of the comments of a statement.
Definition: statement.c:1916
bool statement_with_empty_comment_p(statement)
Return true if the statement has an empty statement:
Definition: statement.c:126
static void check_if_statement_contains_comment(statement s, void *a_context)
Add in the statement containing comments in the list of statements.
static void remove_end_tag(statement stat, string function_name)
Remove end tag for given statement and function.
static list get_statements_with_comments_containing(string comment_portion, statement stat)
Build a list with statements containing comments.
static void clean_statement_from_tags(string comment_portion, statement stat)
static string get_function_name_by_searching_tag(statement stat, string tag)
Return the identified function name of the externalized portion of code by searching comment matching...
static list identify_statements_to_distribute(statement module_stat)
Return a list of statements that are marked for externalization.
static bool statement_is_contained_in_a_sequence_p(statement root_statement, statement searched_stat)
bool safescale_distributor_init(const char *module_name)
Main phase for block code detection.
static void search_sequence_containing(statement s, void *a_context)
static void remove_begin_tag(statement stat, string function_name)
Remove begin tag for a given statement and function.
static statement isolate_code_portion(statement begin_tag_statement, statement end_tag_statement, statement sequence_statement)
Transform a statement in a sequence statement with a single statement which is the embedded statement...
static statement sequence_statement_containing(statement root_statement, statement searched_stat)
#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 debug_off()
Definition: misc-local.h:160
#define pips_user_error
Definition: misc-local.h:147
string concatenate(const char *,...)
Return the concatenation of the given strings.
Definition: string.c:183
int tag
TAG.
Definition: newgen_types.h:92
#define EXTERNALIZED_CODE_PRAGMA_BEGIN
#define EXTERNALIZED_CODE_PRAGMA_END
void print_statement(statement)
Print a statement on stderr.
Definition: statement.c:98
bool module_reorder(statement body)
Reorder a module and recompute order to statement if any.
Definition: reorder.c:244
#define empty_comments
Empty comments (i.e.
entity module_name_to_entity(const char *mn)
This is an alias for local_name_to_top_level_entity.
Definition: entity.c:1479
entity entity_empty_label(void)
Definition: entity.c:1105
#define statement_ordering(x)
Definition: ri.h:2454
#define statement_domain
newgen_sizeofexpression_domain_defined
Definition: ri.h:362
@ is_instruction_sequence
Definition: ri.h:1469
#define instruction_tag(x)
Definition: ri.h:1511
#define sequence_statements(x)
Definition: ri.h:2360
#define statement_extensions(x)
Definition: ri.h:2464
#define instruction_sequence(x)
Definition: ri.h:1514
#define statement_instruction(x)
Definition: ri.h:2458
#define statement_comments(x)
Definition: ri.h:2456
#define statement_number(x)
Definition: ri.h:2452
#define STATEMENT(x)
STATEMENT.
Definition: ri.h:2413
#define EXTERNALIZED_CODE_PRAGMA_ANALYZED_PREFIX_TOP
#define EXTERNALIZED_CODE_PRAGMA_ANALYZED_TOP
char * strdup()
#define ifdebug(n)
Definition: sg.c:47
The structure used to build lists in NewGen.
Definition: newgen_list.h:41
Definition: delay.c:253
A gen_chunk is used to store every object.
Definition: genC.h:58