Add overflow detection
[openscop.git] / source / extensions / loop.c
blob2c7bb8e9f867750eeb1ad2468acd5cbe10bd8d73
2 /*+-----------------------------------------------------------------**
3 ** OpenScop Library **
4 **-----------------------------------------------------------------**
5 ** extensions/loop.c **
6 **-----------------------------------------------------------------**
7 ** First version: 03/06/2013 **
8 **-----------------------------------------------------------------**
11 *****************************************************************************
12 * OpenScop: Structures and formats for polyhedral tools to talk together *
13 *****************************************************************************
14 * ,___,,_,__,,__,,__,,__,,_,__,,_,__,,__,,___,_,__,,_,__, *
15 * / / / // // // // / / / // // / / // / /|,_, *
16 * / / / // // // // / / / // // / / // / / / /\ *
17 * |~~~|~|~~~|~~~|~~~|~~~|~|~~~|~|~~~|~~~|~~~|~|~~~|~|~~~|/_/ \ *
18 * | G |C| P | = | L | P |=| = |C| = | = | = |=| = |=| C |\ \ /\ *
19 * | R |l| o | = | e | l |=| = |a| = | = | = |=| = |=| L | \# \ /\ *
20 * | A |a| l | = | t | u |=| = |n| = | = | = |=| = |=| o | |\# \ \ *
21 * | P |n| l | = | s | t |=| = |d| = | = | = | | |=| o | | \# \ \ *
22 * | H | | y | | e | o | | = |l| | | = | | | | G | | \ \ \ *
23 * | I | | | | e | | | | | | | | | | | | | \ \ \ *
24 * | T | | | | | | | | | | | | | | | | | \ \ \ *
25 * | E | | | | | | | | | | | | | | | | | \ \ \ *
26 * | * |*| * | * | * | * |*| * |*| * | * | * |*| * |*| * | / \* \ \ *
27 * | O |p| e | n | S | c |o| p |-| L | i | b |r| a |r| y |/ \ \ / *
28 * '---'-'---'---'---'---'-'---'-'---'---'---'-'---'-'---' '--' *
29 * *
30 * Copyright (C) 2008 University Paris-Sud 11 and INRIA *
31 * *
32 * (3-clause BSD license) *
33 * Redistribution and use in source and binary forms, with or without *
34 * modification, are permitted provided that the following conditions *
35 * are met: *
36 * *
37 * 1. Redistributions of source code must retain the above copyright notice, *
38 * this list of conditions and the following disclaimer. *
39 * 2. Redistributions in binary form must reproduce the above copyright *
40 * notice, this list of conditions and the following disclaimer in the *
41 * documentation and/or other materials provided with the distribution. *
42 * 3. The name of the author may not be used to endorse or promote products *
43 * derived from this software without specific prior written permission. *
44 * *
45 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR *
46 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES *
47 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. *
48 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, *
49 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT *
50 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, *
51 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY *
52 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT *
53 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF *
54 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
55 * *
56 * OpenScop Library, a library to manipulate OpenScop formats and data *
57 * structures. Written by: *
58 * Cedric Bastoul <Cedric.Bastoul@u-psud.fr> and *
59 * Louis-Noel Pouchet <Louis-Noel.pouchet@inria.fr> *
60 * *
61 *****************************************************************************/
63 #include <stdlib.h>
64 #include <stdio.h>
65 #include <string.h>
66 #include <ctype.h>
68 #include <osl/macros.h>
69 #include <osl/util.h>
70 #include <osl/strings.h>
71 #include <osl/interface.h>
72 #include <osl/extensions/loop.h>
75 /*+***************************************************************************
76 * Structure display function *
77 *****************************************************************************/
80 /**
81 * osl_loop_idump function:
82 * this function displays an osl_loop_t structure (loop) into a file
83 * (file, possibly stdout) in a way that trends to be understandable. It
84 * includes an indentation level (level) in order to work with others
85 * idump functions.
87 * \param[in] file The file where the information has to be printed.
88 * \param[in] loop The loop structure to print.
89 * \param[in] level Number of spaces before printing, for each line.
91 void osl_loop_idump(FILE * file, osl_loop_p loop, int level) {
92 int i, j, first = 1, number=1;
94 // Go to the right level.
95 for (j = 0; j < level; j++)
96 fprintf(file, "|\t");
98 if (loop != NULL)
99 fprintf(file, "+-- osl_loop_t\n");
100 else
101 fprintf(file, "+-- NULL loop\n");
103 while (loop != NULL) {
104 // Go to the right level.
105 if (!first) {
106 // Go to the right level.
107 for (j = 0; j < level; j++)
108 fprintf(file, "|\t");
110 fprintf(file, "| osl_loop_t (node %d)\n", number);
111 } else {
112 first = 0;
115 // A blank line.
116 for (j = 0; j <= level+1; j++)
117 fprintf(file, "|\t");
118 fprintf(file, "\n");
120 // Display the number of names.
121 for (j = 0; j <= level; j++)
122 fprintf(file, "|\t");
123 fprintf(file, "+--iterator: %s\n", loop->iter);
125 for (j = 0; j <= level; j++)
126 fprintf(file, "|\t");
127 fprintf(file, "+--nb_stmts: %d\n", loop->nb_stmts);
129 // Display the id/name.
130 for (j = 0; j <= level; j++)
131 fprintf(file, "|\t");
132 fprintf(file, "+--stmt_ids:");
133 for(i = 0; i < loop->nb_stmts; i++) {
134 // Go to the right level.
135 fprintf(file, "%2d, ", loop->stmt_ids[i]);
137 fprintf(file, "\n");
140 for (j = 0; j <= level; j++)
141 fprintf(file, "|\t");
142 fprintf(file, "+--private_vars: %s\n", loop->private_vars);
144 for (j = 0; j <= level; j++)
145 fprintf(file, "|\t");
146 fprintf(file, "+--directive: %d\n", loop->directive);
148 loop = loop->next;
149 number++;
151 // Next line.
152 if (loop != NULL) {
153 for (j = 0; j <= level; j++)
154 fprintf(file, "|\t");
155 fprintf(file, "V\n");
159 // The last line.
160 for (j = 0; j <= level; j++)
161 fprintf(file, "|\t");
162 fprintf(file, "\n");
167 * osl_loop_dump function:
168 * this function prints the content of an osl_loop_t structure
169 * (*loop) into a file (file, possibly stdout).
171 * \param[in] file The file where the information has to be printed.
172 * \param[in] loop The loop structure to print.
174 void osl_loop_dump(FILE * file, osl_loop_p loop) {
175 osl_loop_idump(file, loop, 0);
180 * osl_loop_sprint function:
181 * this function prints the content of an osl_loop_t structure
182 * (*loop) into a string (returned) in the OpenScop textual format.
183 * \param[in] loop The loop structure to print.
184 * \return A string containing the OpenScop dump of the loop structure.
186 char * osl_loop_sprint(osl_loop_p loop) {
187 int i;
188 int nloop = 0;
189 int high_water_mark = OSL_MAX_STRING;
190 char *string = NULL;
191 char buffer[OSL_MAX_STRING];
193 OSL_malloc(string, char *, high_water_mark * sizeof(char));
194 string[0] = '\0';
196 sprintf(buffer, "# Number of loops\n%d\n",osl_loop_count(loop));
197 osl_util_safe_strcat(&string, buffer, &high_water_mark);
199 while (loop != NULL) {
200 sprintf(buffer, "# ===========================================\n");
201 osl_util_safe_strcat(&string, buffer, &high_water_mark);
203 sprintf(buffer, "# Loop number %d \n", ++nloop);
204 osl_util_safe_strcat(&string, buffer, &high_water_mark);
206 sprintf(buffer, "# Iterator name\n");
207 osl_util_safe_strcat(&string, buffer, &high_water_mark);
208 sprintf(buffer, "%s\n", loop->iter);
209 osl_util_safe_strcat(&string, buffer, &high_water_mark);
211 sprintf(buffer, "# Number of stmts\n");
212 osl_util_safe_strcat(&string, buffer, &high_water_mark);
213 sprintf(buffer, "%d\n", loop->nb_stmts);
214 osl_util_safe_strcat(&string, buffer, &high_water_mark);
216 if (loop->nb_stmts) {
217 sprintf(buffer, "# Statement identifiers\n");
218 osl_util_safe_strcat(&string, buffer, &high_water_mark);
220 for (i = 0; i < loop->nb_stmts; i++) {
221 sprintf(buffer, "%d\n", loop->stmt_ids[i]);
222 osl_util_safe_strcat(&string, buffer, &high_water_mark);
225 sprintf(buffer, "# Private variables\n");
226 osl_util_safe_strcat(&string, buffer, &high_water_mark);
227 sprintf(buffer, "%s\n", loop->private_vars);
228 osl_util_safe_strcat(&string, buffer, &high_water_mark);
230 sprintf(buffer, "# Directive\n");
231 osl_util_safe_strcat(&string, buffer, &high_water_mark);
232 sprintf(buffer, "%d\n", loop->directive);
233 osl_util_safe_strcat(&string, buffer, &high_water_mark);
235 loop = loop->next;
238 OSL_realloc(string, char *, (strlen(string) + 1) * sizeof(char));
239 return string;
243 /*****************************************************************************
244 * Reading function *
245 *****************************************************************************/
249 * osl_loop_sread function:
250 * this function reads a loop structure from a string complying to the
251 * OpenScop textual format and returns a pointer to this loop structure.
252 * The input parameter is updated to the position in the input string this
253 * function reaches right after reading the comment structure.
255 * \param[in,out] input The input string where to find an loop structure.
256 * Updated to the position after what has been read.
257 * \return A pointer to the loop structure that has been read.
259 osl_loop_p osl_loop_sread(char **input) {
260 int i;
261 int nb_loops;
262 osl_loop_p head;
263 osl_loop_p loop;
265 if (input == NULL) {
266 OSL_debug("no loop optional tag");
267 return NULL;
270 // Find the number of names provided.
271 nb_loops = osl_util_read_int(NULL, input);
272 if(nb_loops == 0)
273 return NULL;
275 // Allocate the array of id and names.
276 head = loop = osl_loop_malloc();
278 while (nb_loops != 0) {
280 loop->iter = osl_util_read_string(NULL, input);
281 loop->nb_stmts = osl_util_read_int(NULL, input);
283 OSL_malloc(loop->stmt_ids, int *, loop->nb_stmts * sizeof(int));
284 for (i = 0; i < loop->nb_stmts; i++)
285 loop->stmt_ids[i] = osl_util_read_int(NULL, input);
287 loop->private_vars = osl_util_read_line(NULL, input);
288 if (!strcmp(loop->private_vars, "(null)")) {
289 free(loop->private_vars);
290 loop->private_vars=NULL;
293 loop->directive = osl_util_read_int(NULL, input);
295 nb_loops--;
296 if (nb_loops != 0) {
297 loop->next = osl_loop_malloc ();
298 loop = loop->next;
302 return head;
306 /*+***************************************************************************
307 * Memory allocation/deallocation function *
308 *****************************************************************************/
312 * osl_loop_malloc function:
313 * this function allocates the memory space for an osl_loop_t
314 * structure and sets its fields with default values. Then it returns a
315 * pointer to the allocated space.
317 * \return A pointer to an empty loop structure with fields set to
318 * default values.
320 osl_loop_p osl_loop_malloc() {
321 osl_loop_p loop;
323 OSL_malloc(loop, osl_loop_p, sizeof(osl_loop_t));
324 loop->iter = NULL;
325 loop->nb_stmts = 0;
326 loop->stmt_ids = NULL;
327 loop->private_vars = NULL;
328 loop->directive = 0;
329 loop->next = NULL;
331 return loop;
336 * osl_loop_free function:
337 * this function frees the allocated memory for an loop structure.
339 * \param[in,out] loop The pointer to the loop structure we want to free.
341 void osl_loop_free(osl_loop_p loop) {
343 while (loop != NULL) {
344 osl_loop_p tmp = loop;
346 if (loop->iter) free(loop->iter);
347 if (loop->stmt_ids) free(loop->stmt_ids);
348 if (loop->private_vars) free(loop->private_vars);
350 loop = loop->next;
352 free(tmp);
357 /*+***************************************************************************
358 * Processing functions *
359 *****************************************************************************/
363 * osl_loop_clone_one function:
364 * this function builds and returns a "hard copy" (not a pointer copy) of
365 * "one" (and not the whole list) osl_loop_t data structure.
367 * \param[in] loop The pointer to the loop structure to clone.
368 * \return A pointer to the clone of the loop structure.
370 osl_loop_p osl_loop_clone_one(osl_loop_p loop) {
371 int i;
372 osl_loop_p clone;
374 if (loop == NULL)
375 return NULL;
377 clone = osl_loop_malloc();
378 OSL_strdup(clone->iter, loop->iter);
379 clone->nb_stmts = loop->nb_stmts;
380 OSL_malloc(clone->stmt_ids, int *, loop->nb_stmts * sizeof(int));
382 for (i = 0; i < loop->nb_stmts; i++) {
383 clone->stmt_ids[i] = loop->stmt_ids[i];
386 clone->directive = loop->directive;
388 if(loop->private_vars != NULL)
389 OSL_strdup(clone->private_vars, loop->private_vars);
391 return clone;
395 * osl_loop_clone function:
396 * this function builds and returns a "hard copy" (not a pointer copy) of a
397 * list of osl_loop_t data structures.
399 * \param[in] loop The pointer to the list of loop structure to clone.
400 * \return A pointer to the clone of list of the loop structure.
402 osl_loop_p osl_loop_clone(osl_loop_p loop) {
403 osl_loop_p clone = NULL;
404 osl_loop_p head = NULL;
406 if (loop == NULL)
407 return NULL;
409 while (loop) {
411 if (clone==NULL) {
412 head = clone = osl_loop_clone_one(loop);
414 else {
415 clone->next = osl_loop_clone_one(loop);
416 clone = clone->next;
419 loop = loop->next;
422 return head;
426 * osl_loop_equal_one function:
427 * this function returns true if the two loop structures are the same
428 * (content-wise), false otherwise. This functions considers two loop
429 * structures as equal if the order of the array names differ, however
430 * the identifiers and names must be the same.
432 * \param[in] a1 The first loop structure.
433 * \param[in] a2 The second loop structure.
434 * \return 1 if a1 and a2 are the same (content-wise), 0 otherwise.
436 int osl_loop_equal_one(osl_loop_p a1, osl_loop_p a2) {
437 int i, j, found;
439 if (a1 == a2)
440 return 1;
442 if (((a1 == NULL) && (a2 != NULL)) || ((a1 != NULL) && (a2 == NULL))) {
443 //OSL_info("loops are not the same (compare with NULL)");
444 return 0;
447 // Check whether the number of names is the same.
448 if (a1->nb_stmts != a2->nb_stmts) {
449 //OSL_info("loops are not the same (nb_stmts)");
450 return 0;
453 if (strcmp(a1->iter, a2->iter)) {
454 //OSL_info("loops are not the same (iter name)");
455 return 0;
457 // We accept a different order of the names, as long as the identifiers
458 // are the same.
459 for (i = 0; i < a1->nb_stmts; i++) {
460 found = 0;
461 for (j = 0; j < a2->nb_stmts; j++) {
462 if (a1->stmt_ids[i] == a2->stmt_ids[j]) {
463 found = 1;
464 break;
467 if (found != 1) {
468 //OSL_info("loop are not the same (stmt ids)");
469 return 0;
473 //TODO: necessarily same ???
474 if (a1->private_vars != a2->private_vars) { // NULL check
475 if (strcmp(a1->private_vars, a2->private_vars)) {
476 //OSL_info("loops are not the same (private vars)");
477 return 0;
481 //TODO: necessarily same ???
482 if (a1->directive != a2->directive) {
483 //OSL_info("loops are not the same (directive)");
484 return 0;
487 return 1;
491 * osl_loop_equal function:
492 * this function returns true if the two loop lists are the same
493 * (content-wise), false otherwise. Two lists are equal if one contains
494 * all the elements of the other and vice versa. The exact order of the
495 * nodes is not taken into account by this function.
497 * \param[in] a1 The first loop list.
498 * \param[in] a2 The second loop list.
499 * \return 1 if a1 and a2 are the same (content-wise), 0 otherwise.
501 int osl_loop_equal(osl_loop_p a1, osl_loop_p a2) {
502 int found = 0;
504 if (a1 == a2)
505 return 1;
507 if (((a1 == NULL) && (a2 != NULL)) || ((a1 != NULL) && (a2 == NULL))) {
508 OSL_info("lists of loops are not the same (compare with NULL)");
509 return 0;
512 if (osl_loop_count(a1) != osl_loop_count(a2)) {
513 OSL_info("list of loops are not the same");
514 return 0;
517 while (a1) {
518 found = 0;
519 osl_loop_p temp = a2;
521 while (temp) {
522 if(osl_loop_equal_one(a1, temp)==1){
523 found= 1;
524 break;
526 temp = temp->next;
529 if(found!=1){
530 OSL_info("list of loops are not the same");
531 return 0;
533 a1 = a1->next;
536 return 1;
541 * osl_loop_interface function:
542 * this function creates an interface structure corresponding to the loop
543 * extension and returns it.
545 * \return An interface structure for the loop extension.
547 osl_interface_p osl_loop_interface() {
548 osl_interface_p interface = osl_interface_malloc();
550 OSL_strdup(interface->URI, OSL_URI_LOOP);
551 interface->idump = (osl_idump_f)osl_loop_idump;
552 interface->sprint = (osl_sprint_f)osl_loop_sprint;
553 interface->sread = (osl_sread_f)osl_loop_sread;
554 interface->malloc = (osl_malloc_f)osl_loop_malloc;
555 interface->free = (osl_free_f)osl_loop_free;
556 interface->clone = (osl_clone_f)osl_loop_clone;
557 interface->equal = (osl_equal_f)osl_loop_equal;
559 return interface;
564 * osl_loop_add function:
565 * this function adds a loop structure at the end of the list
567 * \param[in,out] ll Pointer to a list of loops.
568 * \param[in] loop Pointer to the loop structure to be added.
570 void osl_loop_add(osl_loop_p loop, osl_loop_p *ll) {
572 while (*ll != NULL)
573 ll = &(*ll)->next;
575 *ll = loop;
580 * osl_loop_count:
581 * this function returns the number of elements in the list
583 * \param[in] ll Pointer to a list of loops.
584 * \return Number of elements in the list
586 int osl_loop_count(osl_loop_p ll) {
587 int count = 0;
588 while (ll) {
589 count++;
590 ll = ll->next;
593 return count;