Merge branch 'master' of github.com:periscop/openscop
[openscop.git] / source / extensions / loop.c
blob2e6cf66f7aab50f606679d63a0eeea9bd94f2137
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 for (j = 0; j <= level; j++)
149 fprintf(file, "|\t");
150 fprintf(file, "+--user: %s\n", loop->user);
152 loop = loop->next;
153 number++;
155 // Next line.
156 if (loop != NULL) {
157 for (j = 0; j <= level; j++)
158 fprintf(file, "|\t");
159 fprintf(file, "V\n");
163 // The last line.
164 for (j = 0; j <= level; j++)
165 fprintf(file, "|\t");
166 fprintf(file, "\n");
171 * osl_loop_dump function:
172 * this function prints the content of an osl_loop_t structure
173 * (*loop) into a file (file, possibly stdout).
175 * \param[in] file The file where the information has to be printed.
176 * \param[in] loop The loop structure to print.
178 void osl_loop_dump(FILE * file, osl_loop_p loop) {
179 osl_loop_idump(file, loop, 0);
184 * osl_loop_sprint function:
185 * this function prints the content of an osl_loop_t structure
186 * (*loop) into a string (returned) in the OpenScop textual format.
187 * \param[in] loop The loop structure to print.
188 * \return A string containing the OpenScop dump of the loop structure.
190 char * osl_loop_sprint(osl_loop_p loop) {
191 int i;
192 int nloop = 0;
193 int high_water_mark = OSL_MAX_STRING;
194 char *string = NULL;
195 char buffer[OSL_MAX_STRING];
197 OSL_malloc(string, char *, high_water_mark * sizeof(char));
198 string[0] = '\0';
200 sprintf(buffer, "# Number of loops\n%d\n",osl_loop_count(loop));
201 osl_util_safe_strcat(&string, buffer, &high_water_mark);
203 while (loop != NULL) {
204 sprintf(buffer, "# ===========================================\n");
205 osl_util_safe_strcat(&string, buffer, &high_water_mark);
207 sprintf(buffer, "# Loop number %d \n", ++nloop);
208 osl_util_safe_strcat(&string, buffer, &high_water_mark);
210 sprintf(buffer, "# Iterator name\n");
211 osl_util_safe_strcat(&string, buffer, &high_water_mark);
212 sprintf(buffer, "%s\n", loop->iter);
213 osl_util_safe_strcat(&string, buffer, &high_water_mark);
215 sprintf(buffer, "# Number of stmts\n");
216 osl_util_safe_strcat(&string, buffer, &high_water_mark);
217 sprintf(buffer, "%d\n", loop->nb_stmts);
218 osl_util_safe_strcat(&string, buffer, &high_water_mark);
220 if (loop->nb_stmts) {
221 sprintf(buffer, "# Statement identifiers\n");
222 osl_util_safe_strcat(&string, buffer, &high_water_mark);
224 for (i = 0; i < loop->nb_stmts; i++) {
225 sprintf(buffer, "%d\n", loop->stmt_ids[i]);
226 osl_util_safe_strcat(&string, buffer, &high_water_mark);
229 sprintf(buffer, "# Private variables\n");
230 osl_util_safe_strcat(&string, buffer, &high_water_mark);
231 sprintf(buffer, "%s\n", loop->private_vars);
232 osl_util_safe_strcat(&string, buffer, &high_water_mark);
234 sprintf(buffer, "# Directive\n");
235 osl_util_safe_strcat(&string, buffer, &high_water_mark);
236 sprintf(buffer, "%d", loop->directive);
237 osl_util_safe_strcat(&string, buffer, &high_water_mark);
239 // special case for OSL_LOOP_DIRECTIVE_USER
240 if (loop->directive == OSL_LOOP_DIRECTIVE_USER) {
241 sprintf(buffer, " %s", loop->user);
242 osl_util_safe_strcat(&string, buffer, &high_water_mark);
244 sprintf(buffer, "\n");
245 osl_util_safe_strcat(&string, buffer, &high_water_mark);
247 loop = loop->next;
250 OSL_realloc(string, char *, (strlen(string) + 1) * sizeof(char));
251 return string;
255 /*****************************************************************************
256 * Reading function *
257 *****************************************************************************/
261 * osl_loop_sread function:
262 * this function reads a loop structure from a string complying to the
263 * OpenScop textual format and returns a pointer to this loop structure.
264 * The input parameter is updated to the position in the input string this
265 * function reaches right after reading the comment structure.
267 * \param[in,out] input The input string where to find an loop structure.
268 * Updated to the position after what has been read.
269 * \return A pointer to the loop structure that has been read.
271 osl_loop_p osl_loop_sread(char **input) {
272 int i;
273 int nb_loops;
274 osl_loop_p head;
275 osl_loop_p loop;
277 if (input == NULL) {
278 OSL_debug("no loop optional tag");
279 return NULL;
282 // Find the number of names provided.
283 nb_loops = osl_util_read_int(NULL, input);
284 if(nb_loops == 0)
285 return NULL;
287 // Allocate the array of id and names.
288 head = loop = osl_loop_malloc();
290 while (nb_loops != 0) {
292 loop->iter = osl_util_read_string(NULL, input);
293 loop->nb_stmts = osl_util_read_int(NULL, input);
295 OSL_malloc(loop->stmt_ids, int *, loop->nb_stmts * sizeof(int));
296 for (i = 0; i < loop->nb_stmts; i++)
297 loop->stmt_ids[i] = osl_util_read_int(NULL, input);
299 loop->private_vars = osl_util_read_line(NULL, input);
300 if (!strcmp(loop->private_vars, "(null)")) {
301 free(loop->private_vars);
302 loop->private_vars=NULL;
305 loop->directive = osl_util_read_int(NULL, input);
307 // special case for OSL_LOOP_DIRECTIVE_USER
308 if (loop->directive == OSL_LOOP_DIRECTIVE_USER) {
309 loop->user = osl_util_read_line(NULL, input);
310 if (!strcmp(loop->user, "(null)")) {
311 free(loop->user);
312 loop->user=NULL;
316 nb_loops--;
317 if (nb_loops != 0) {
318 loop->next = osl_loop_malloc ();
319 loop = loop->next;
323 return head;
327 /*+***************************************************************************
328 * Memory allocation/deallocation function *
329 *****************************************************************************/
333 * osl_loop_malloc function:
334 * this function allocates the memory space for an osl_loop_t
335 * structure and sets its fields with default values. Then it returns a
336 * pointer to the allocated space.
338 * \return A pointer to an empty loop structure with fields set to
339 * default values.
341 osl_loop_p osl_loop_malloc() {
342 osl_loop_p loop;
344 OSL_malloc(loop, osl_loop_p, sizeof(osl_loop_t));
345 loop->iter = NULL;
346 loop->nb_stmts = 0;
347 loop->stmt_ids = NULL;
348 loop->private_vars = NULL;
349 loop->directive = 0;
350 loop->user = NULL;
351 loop->next = NULL;
353 return loop;
358 * osl_loop_free function:
359 * this function frees the allocated memory for an loop structure.
361 * \param[in,out] loop The pointer to the loop structure we want to free.
363 void osl_loop_free(osl_loop_p loop) {
365 while (loop != NULL) {
366 osl_loop_p tmp = loop;
368 if (loop->iter) free(loop->iter);
369 if (loop->stmt_ids) free(loop->stmt_ids);
370 if (loop->private_vars) free(loop->private_vars);
371 if (loop->user) free(loop->user);
373 loop = loop->next;
375 free(tmp);
380 /*+***************************************************************************
381 * Processing functions *
382 *****************************************************************************/
386 * osl_loop_clone_one function:
387 * this function builds and returns a "hard copy" (not a pointer copy) of
388 * "one" (and not the whole list) osl_loop_t data structure.
390 * \param[in] loop The pointer to the loop structure to clone.
391 * \return A pointer to the clone of the loop structure.
393 osl_loop_p osl_loop_clone_one(osl_loop_p loop) {
394 int i;
395 osl_loop_p clone;
397 if (loop == NULL)
398 return NULL;
400 clone = osl_loop_malloc();
401 OSL_strdup(clone->iter, loop->iter);
402 clone->nb_stmts = loop->nb_stmts;
403 OSL_malloc(clone->stmt_ids, int *, loop->nb_stmts * sizeof(int));
405 for (i = 0; i < loop->nb_stmts; i++) {
406 clone->stmt_ids[i] = loop->stmt_ids[i];
409 clone->directive = loop->directive;
411 if(loop->private_vars != NULL)
412 OSL_strdup(clone->private_vars, loop->private_vars);
414 if(loop->user != NULL)
415 OSL_strdup(clone->user, loop->user);
417 return clone;
421 * osl_loop_clone function:
422 * this function builds and returns a "hard copy" (not a pointer copy) of a
423 * list of osl_loop_t data structures.
425 * \param[in] loop The pointer to the list of loop structure to clone.
426 * \return A pointer to the clone of list of the loop structure.
428 osl_loop_p osl_loop_clone(osl_loop_p loop) {
429 osl_loop_p clone = NULL;
430 osl_loop_p head = NULL;
432 if (loop == NULL)
433 return NULL;
435 while (loop) {
437 if (clone==NULL) {
438 head = clone = osl_loop_clone_one(loop);
440 else {
441 clone->next = osl_loop_clone_one(loop);
442 clone = clone->next;
445 loop = loop->next;
448 return head;
452 * osl_loop_equal_one function:
453 * this function returns true if the two loop structures are the same
454 * (content-wise), false otherwise. This functions considers two loop
455 * structures as equal if the order of the array names differ, however
456 * the identifiers and names must be the same.
458 * \param[in] a1 The first loop structure.
459 * \param[in] a2 The second loop structure.
460 * \return 1 if a1 and a2 are the same (content-wise), 0 otherwise.
462 int osl_loop_equal_one(osl_loop_p a1, osl_loop_p a2) {
463 int i, j, found;
465 if (a1 == a2)
466 return 1;
468 if (((a1 == NULL) && (a2 != NULL)) || ((a1 != NULL) && (a2 == NULL))) {
469 //OSL_info("loops are not the same (compare with NULL)");
470 return 0;
473 // Check whether the number of names is the same.
474 if (a1->nb_stmts != a2->nb_stmts) {
475 //OSL_info("loops are not the same (nb_stmts)");
476 return 0;
479 if (strcmp(a1->iter, a2->iter)) {
480 //OSL_info("loops are not the same (iter name)");
481 return 0;
483 // We accept a different order of the names, as long as the identifiers
484 // are the same.
485 for (i = 0; i < a1->nb_stmts; i++) {
486 found = 0;
487 for (j = 0; j < a2->nb_stmts; j++) {
488 if (a1->stmt_ids[i] == a2->stmt_ids[j]) {
489 found = 1;
490 break;
493 if (found != 1) {
494 //OSL_info("loop are not the same (stmt ids)");
495 return 0;
499 //TODO: necessarily same ???
500 if (a1->private_vars != a2->private_vars) { // NULL check
501 if (strcmp(a1->private_vars, a2->private_vars)) {
502 //OSL_info("loops are not the same (private vars)");
503 return 0;
507 //TODO: necessarily same ???
508 if (a1->directive != a2->directive) {
509 //OSL_info("loops are not the same (directive)");
510 return 0;
513 if (a1->user != a2->user) { // NULL check
514 if (strcmp(a1->user, a2->user)) {
515 return 0;
519 return 1;
523 * osl_loop_equal function:
524 * this function returns true if the two loop lists are the same
525 * (content-wise), false otherwise. Two lists are equal if one contains
526 * all the elements of the other and vice versa. The exact order of the
527 * nodes is not taken into account by this function.
529 * \param[in] a1 The first loop list.
530 * \param[in] a2 The second loop list.
531 * \return 1 if a1 and a2 are the same (content-wise), 0 otherwise.
533 int osl_loop_equal(osl_loop_p a1, osl_loop_p a2) {
534 int found = 0;
536 if (a1 == a2)
537 return 1;
539 if (((a1 == NULL) && (a2 != NULL)) || ((a1 != NULL) && (a2 == NULL))) {
540 OSL_info("lists of loops are not the same (compare with NULL)");
541 return 0;
544 if (osl_loop_count(a1) != osl_loop_count(a2)) {
545 OSL_info("list of loops are not the same");
546 return 0;
549 while (a1) {
550 found = 0;
551 osl_loop_p temp = a2;
553 while (temp) {
554 if(osl_loop_equal_one(a1, temp)==1){
555 found= 1;
556 break;
558 temp = temp->next;
561 if(found!=1){
562 OSL_info("list of loops are not the same");
563 return 0;
565 a1 = a1->next;
568 return 1;
573 * osl_loop_interface function:
574 * this function creates an interface structure corresponding to the loop
575 * extension and returns it.
577 * \return An interface structure for the loop extension.
579 osl_interface_p osl_loop_interface() {
580 osl_interface_p interface = osl_interface_malloc();
582 OSL_strdup(interface->URI, OSL_URI_LOOP);
583 interface->idump = (osl_idump_f)osl_loop_idump;
584 interface->sprint = (osl_sprint_f)osl_loop_sprint;
585 interface->sread = (osl_sread_f)osl_loop_sread;
586 interface->malloc = (osl_malloc_f)osl_loop_malloc;
587 interface->free = (osl_free_f)osl_loop_free;
588 interface->clone = (osl_clone_f)osl_loop_clone;
589 interface->equal = (osl_equal_f)osl_loop_equal;
591 return interface;
596 * osl_loop_add function:
597 * this function adds a loop structure at the end of the list
599 * \param[in,out] ll Pointer to a list of loops.
600 * \param[in] loop Pointer to the loop structure to be added.
602 void osl_loop_add(osl_loop_p loop, osl_loop_p *ll) {
604 while (*ll != NULL)
605 ll = &(*ll)->next;
607 *ll = loop;
612 * osl_loop_count:
613 * this function returns the number of elements in the list
615 * \param[in] ll Pointer to a list of loops.
616 * \return Number of elements in the list
618 int osl_loop_count(osl_loop_p ll) {
619 int count = 0;
620 while (ll) {
621 count++;
622 ll = ll->next;
625 return count;