1
2    /*+-----------------------------------------------------------------**
3     **                       OpenScop Library                          **
4     **-----------------------------------------------------------------**
5     **                            scop.c                               **
6     **-----------------------------------------------------------------**
7     **                   First version: 30/04/2008                     **
8     **-----------------------------------------------------------------**
9
10
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 *****************************************************************************/
62
63# include <stdlib.h>
64# include <stdio.h>
65# include <ctype.h>
66# include <string.h>
67
68#include <osl/macros.h>
69#include <osl/util.h>
70#include <osl/extensions/arrays.h>
71#include <osl/extensions/textual.h>
72#include <osl/strings.h>
73#include <osl/relation.h>
74#include <osl/interface.h>
75#include <osl/generic.h>
76#include <osl/statement.h>
77#include <osl/scop.h>
78
79
80/*+***************************************************************************
81 *                         Structure display functions                       *
82 *****************************************************************************/
83
84
85/**
86 * osl_scop_idump function:
87 * this function displays an osl_scop_t structure (*scop) into a
88 * file (file, possibly stdout) in a way that trends to be understandable. It
89 * includes an indentation level (level) in order to work with others
90 * idump functions.
91 * \param file  The file where the information has to be printed.
92 * \param scop  The scop structure whose information has to be printed.
93 * \param level Number of spaces before printing, for each line.
94 */
95void osl_scop_idump(FILE * file, osl_scop_p scop, int level) {
96  int j, first = 1;
97
98  // Go to the right level.
99  for (j = 0; j < level; j++)
100    fprintf(file, "|\t");
101
102  if (scop != NULL)
103    fprintf(file, "+-- osl_scop_t\n");
104  else
105    fprintf(file, "+-- NULL scop\n");
106
107  while (scop != NULL) {
108    if (!first) {
109      // Go to the right level.
110      for (j = 0; j < level; j++)
111        fprintf(file, "|\t");
112      fprintf(file, "|   osl_scop_t\n");
113    }
114    else
115      first = 0;
116
117    // A blank line.
118    for (j = 0; j <= level+1; j++)
119      fprintf(file, "|\t");
120    fprintf(file, "\n");
121
122    // Print the version.
123    for (j = 0; j < level; j++)
124      fprintf(file, "|\t");
125    fprintf(file, "|\tVersion: %d\n", scop->version);
126
127    // A blank line.
128    for (j = 0; j <= level+1; j++)
129      fprintf(file, "|\t");
130    fprintf(file, "\n");
131
132    // Print the language.
133    for (j = 0; j < level; j++)
134      fprintf(file, "|\t");
135    fprintf(file, "|\tLanguage: %s\n", scop->language);
136
137    // A blank line.
138    for (j = 0; j <= level+1; j++)
139      fprintf(file, "|\t");
140    fprintf(file, "\n");
141
142    // Print the context of the scop.
143    osl_relation_idump(file, scop->context, level+1);
144
145    // Print the parameters.
146    osl_generic_idump(file, scop->parameters, level+1);
147
148    // Print the statements.
149    osl_statement_idump(file, scop->statement, level+1);
150
151    // Print the registered extension interfaces.
152    osl_interface_idump(file, scop->registry, level+1);
153
154    // Print the extensions.
155    osl_generic_idump(file, scop->extension, level+1);
156
157    scop = scop->next;
158
159    // Next line.
160    if (scop != NULL) {
161      for (j = 0; j <= level; j++)
162        fprintf(file, "|\t");
163      fprintf(file, "V\n");
164    }
165  }
166
167  // The last line.
168  for (j = 0; j <= level; j++)
169    fprintf(file, "|\t");
170  fprintf(file, "\n");
171}
172
173
174/**
175 * osl_scop_dump function:
176 * this function prints the content of an osl_scop_t structure (*scop)
177 * into a file (file, possibly stdout).
178 * \param file The file where the information has to be printed.
179 * \param scop The scop structure whose information has to be printed.
180 */
181void osl_scop_dump(FILE * file, osl_scop_p scop) {
182  osl_scop_idump(file, scop, 0);
183}
184
185
186/**
187 * osl_scop_names function:
188 * this function generates as set of names for all the dimensions
189 * involved in a given scop.
190 * \param[in] scop The scop (list) we have to generate names for.
191 * \return A set of generated names for the input scop dimensions.
192 */
193static
194osl_names_p osl_scop_names(osl_scop_p scop) {
195  int nb_parameters = OSL_UNDEFINED;
196  int nb_iterators  = OSL_UNDEFINED;
197  int nb_scattdims  = OSL_UNDEFINED;
198  int nb_localdims  = OSL_UNDEFINED;
199  int array_id      = OSL_UNDEFINED;
200
201  osl_scop_get_attributes(scop, &nb_parameters, &nb_iterators,
202                          &nb_scattdims,  &nb_localdims, &array_id);
203
204  return osl_names_generate("P", nb_parameters,
205                            "i", nb_iterators,
206                            "c", nb_scattdims,
207                            "l", nb_localdims,
208                            "A", array_id);
209}
210
211
212/**
213 * osl_scop_print function:
214 * this function prints the content of an osl_scop_t structure (*scop)
215 * into a file (file, possibly stdout) in the OpenScop textual format.
216 * \param file The file where the information has to be printed.
217 * \param scop The scop structure whose information has to be printed.
218 */
219void osl_scop_print(FILE * file, osl_scop_p scop) {
220  int parameters_backedup = 0;
221  int arrays_backedup = 0;
222  osl_strings_p parameters_backup = NULL;
223  osl_strings_p arrays_backup = NULL;
224  osl_names_p names;
225  osl_arrays_p arrays;
226
227  if (scop == NULL) {
228    fprintf(file, "# NULL scop\n");
229    return;
230  }
231  else {
232    fprintf(file, "# [File generated by the OpenScop Library %s]\n",
233            OSL_RELEASE);
234  }
235
236  if (osl_scop_integrity_check(scop) == 0)
237    OSL_warning("OpenScop integrity check failed. Something may go wrong.");
238
239  // Generate the names for the various dimensions.
240  names = osl_scop_names(scop);
241
242  while (scop != NULL) {
243    // If possible, replace parameter names with scop parameter names.
244    if (osl_generic_has_URI(scop->parameters, OSL_URI_STRINGS)) {
245      parameters_backedup = 1;
246      parameters_backup = names->parameters;
247      names->parameters = scop->parameters->data;
248    }
249
250    // If possible, replace array names with arrays extension names.
251    arrays = osl_generic_lookup(scop->extension, OSL_URI_ARRAYS);
252    if (arrays != NULL) {
253      arrays_backedup = 1;
254      arrays_backup = names->arrays;
255      names->arrays = osl_arrays_to_strings(arrays);
256    }
257
258    fprintf(file, "\n"OSL_TAG_START_SCOP"\n\n");
259    fprintf(file, "# =============================================== "
260                  "Global\n");
261    fprintf(file, "# Language\n");
262    fprintf(file, "%s\n\n", scop->language);
263
264    fprintf(file, "# Context\n");
265    osl_relation_pprint(file, scop->context, names);
266    fprintf(file, "\n");
267
268    osl_util_print_provided(file,
269        osl_generic_has_URI(scop->parameters, OSL_URI_STRINGS),
270        "Parameters are");
271    osl_generic_print(file, scop->parameters);
272
273    fprintf(file, "\n# Number of statements\n");
274    fprintf(file, "%d\n\n",osl_statement_number(scop->statement));
275
276    osl_statement_pprint(file, scop->statement, names);
277
278    if (scop->extension) {
279      fprintf(file, "# =============================================== "
280                    "Extensions\n");
281      osl_generic_print(file, scop->extension);
282    }
283    fprintf(file, "\n"OSL_TAG_END_SCOP"\n\n");
284
285    // If necessary, switch back parameter names.
286    if (parameters_backedup) {
287      parameters_backedup = 0;
288      names->parameters = parameters_backup;
289    }
290
291    // If necessary, switch back array names.
292    if (arrays_backedup) {
293      arrays_backedup = 0;
294      osl_strings_free(names->arrays);
295      names->arrays = arrays_backup;
296    }
297
298    scop = scop->next;
299  }
300
301  osl_names_free(names);
302}
303
304
305/*****************************************************************************
306 *                               Reading function                            *
307 *****************************************************************************/
308
309
310/**
311 * osl_scop_pread function ("precision read"):
312 * this function reads a list of scop structures from a file (possibly stdin)
313 * complying to the OpenScop textual format and returns a pointer to this
314 * scop list. If some relation properties (number of input/output/local
315 * dimensions and number of parameters) are undefined, it will define them
316 * according to the available information.
317 * \param[in] file      The file where the scop has to be read.
318 * \param[in] registry  The list of known interfaces (others are ignored).
319 * \param[in] precision The precision of the relation elements.
320 * \return A pointer to the scop structure that has been read.
321 */
322osl_scop_p osl_scop_pread(FILE * file, osl_interface_p registry,
323                          int precision) {
324  osl_scop_p list = NULL, current = NULL, scop;
325  osl_statement_p stmt = NULL;
326  osl_statement_p prev = NULL;
327  osl_strings_p language;
328  int nb_statements;
329  char * tmp;
330  int first = 1;
331  int i;
332
333  if (file == NULL)
334    return NULL;
335
336  while(1) {
337    //
338    // I. START TAG
339    //
340    tmp = osl_util_read_uptotag(file, OSL_TAG_START_SCOP);
341    if (tmp == NULL) {
342      OSL_debug("no more scop in the file");
343      break;
344    }
345    else {
346      free(tmp);
347    }
348
349    scop = osl_scop_malloc();
350    scop->registry = osl_interface_clone(registry);
351
352    //
353    // II. CONTEXT PART
354    //
355
356    // Read the language.
357    language = osl_strings_read(file);
358    if (osl_strings_size(language) == 0)
359      OSL_error("no language (backend) specified");
360
361    if (osl_strings_size(language) > 1)
362      OSL_warning("uninterpreted information (after language)");
363
364    if (language != NULL) {
365      scop->language = strdup(language->string[0]);
366      osl_strings_free(language);
367    }
368
369    // Read the context domain.
370    scop->context = osl_relation_pread(file, precision);
371
372    // Read the parameters.
373    if (osl_util_read_int(file, NULL) > 0)
374      scop->parameters = osl_generic_read_one(file, scop->registry);
375
376    //
377    // III. STATEMENT PART
378    //
379
380    // Read the number of statements.
381    nb_statements = osl_util_read_int(file, NULL);
382
383    for (i = 0; i < nb_statements; i++) {
384      // Read each statement.
385      stmt = osl_statement_pread(file, scop->registry, precision);
386      if (scop->statement == NULL)
387        scop->statement = stmt;
388      else
389        prev->next = stmt;
390      prev = stmt;
391    }
392
393    //
394    // IV. EXTENSION PART (TO THE END TAG)
395    //
396
397    // Read up the end tag (if any), and store extensions.
398    scop->extension = osl_generic_read(file, scop->registry);
399
400    // Add the new scop to the list.
401    if (first) {
402      list = scop;
403      first = 0;
404    }
405    else {
406      current->next = scop;
407    }
408    current = scop;
409  }
410
411  if (!osl_scop_integrity_check(list))
412    OSL_warning("scop integrity check failed");
413
414  return list;
415}
416
417
418/**
419 * osl_scop_read function:
420 * this function is equivalent to osl_scop_pread() except that
421 * (1) the precision corresponds to the precision environment variable or
422 *     to the highest available precision if it is not defined, and
423 * (2) the list of known interface is set to the default one.
424 * \see{osl_scop_pread}
425 */
426osl_scop_p osl_scop_read(FILE * foo) {
427  int precision = osl_util_get_precision();
428  osl_interface_p registry = osl_interface_get_default_registry();
429  osl_scop_p scop = osl_scop_pread(foo, registry, precision);
430
431  osl_interface_free(registry);
432  return scop;
433}
434
435
436/*+***************************************************************************
437 *                   Memory allocation/deallocation functions                *
438 *****************************************************************************/
439
440
441/**
442 * osl_scop_malloc function:
443 * this function allocates the memory space for a osl_scop_t structure and
444 * sets its fields with default values. Then it returns a pointer to the
445 * allocated space.
446 * \return A pointer to an empty scop with fields set to default values.
447 */
448osl_scop_p osl_scop_malloc() {
449  osl_scop_p scop;
450
451  OSL_malloc(scop, osl_scop_p, sizeof(osl_scop_t));
452  scop->version        = 1;
453  scop->language       = NULL;
454  scop->context        = NULL;
455  scop->parameters     = NULL;
456  scop->statement      = NULL;
457  scop->registry       = NULL;
458  scop->extension      = NULL;
459  scop->usr            = NULL;
460  scop->next           = NULL;
461
462  return scop;
463}
464
465
466/**
467 * osl_scop_free function:
468 * This function frees the allocated memory for a osl_scop_t structure.
469 * \param scop The pointer to the scop we want to free.
470 */
471void osl_scop_free(osl_scop_p scop) {
472  osl_scop_p tmp;
473
474  while (scop != NULL) {
475    if (scop->language != NULL)
476      free(scop->language);
477    osl_generic_free(scop->parameters);
478    osl_relation_free(scop->context);
479    osl_statement_free(scop->statement);
480    osl_interface_free(scop->registry);
481    osl_generic_free(scop->extension);
482
483    tmp = scop->next;
484    free(scop);
485    scop = tmp;
486  }
487}
488
489
490/*+***************************************************************************
491 *                            Processing functions                           *
492 *****************************************************************************/
493
494
495/**
496 * osl_scop_add function:
497 * this function adds a scop "scop" at the end of the scop list pointed
498 * by "location".
499 * \param[in,out] location  Address of the first element of the scop list.
500 * \param[in]     scop      The scop to add to the list.
501 */
502void osl_scop_add(osl_scop_p * location, osl_scop_p scop) {
503  while (*location != NULL)
504    location = &((*location)->next);
505
506  *location = scop;
507}
508
509
510/**
511 * osl_scop_clone function:
512 * This functions builds and returns a "hard copy" (not a pointer copy)
513 * of a osl_statement_t data structure provided as parameter.
514 * Note that the usr field is not touched by this function.
515 * \param scop The pointer to the scop we want to clone.
516 * \return A pointer to the full clone of the scop provided as parameter.
517 */
518osl_scop_p osl_scop_clone(osl_scop_p scop) {
519  osl_scop_p clone = NULL, node, previous = NULL;
520  int first = 1;
521
522  while (scop != NULL) {
523    node                 = osl_scop_malloc();
524    node->version        = scop->version;
525    if (scop->language != NULL)
526      node->language     = strdup(scop->language);
527    node->context        = osl_relation_clone(scop->context);
528    node->parameters     = osl_generic_clone(scop->parameters);
529    node->statement      = osl_statement_clone(scop->statement);
530    node->registry       = osl_interface_clone(scop->registry);
531    node->extension      = osl_generic_clone(scop->extension);
532
533    if (first) {
534      first = 0;
535      clone = node;
536      previous = node;
537    }
538    else {
539      previous->next = node;
540      previous = previous->next;
541    }
542
543    scop = scop->next;
544  }
545
546  return clone;
547}
548
549
550/**
551 * osl_scop_equal function:
552 * this function returns true if the two scops are the same, false
553 * otherwise (the usr field is not tested).
554 * \param s1 The first scop.
555 * \param s2 The second scop.
556 * \return 1 if s1 and s2 are the same (content-wise), 0 otherwise.
557 */
558int osl_scop_equal(osl_scop_p s1, osl_scop_p s2) {
559
560  while ((s1 != NULL) && (s2 != NULL)) {
561    if (s1 == s2)
562      return 1;
563
564    if (s1->version != s2->version) {
565      OSL_info("versions are not the same");
566      return 0;
567    }
568
569    if (strcmp(s1->language, s2->language) != 0) {
570      OSL_info("languages are not the same");
571      return 0;
572    }
573
574    if (!osl_relation_equal(s1->context, s2->context)) {
575      OSL_info("contexts are not the same");
576      return 0;
577    }
578
579    if (!osl_generic_equal(s1->parameters, s2->parameters)) {
580      OSL_info("parameters are not the same");
581      return 0;
582    }
583
584    if (!osl_statement_equal(s1->statement, s2->statement)) {
585      OSL_info("statements are not the same");
586      return 0;
587    }
588
589    if (!osl_interface_equal(s1->registry, s2->registry)) {
590      OSL_info("registries are not the same");
591      return 0;
592    }
593
594    if (!osl_generic_equal(s1->extension, s2->extension)) {
595      OSL_info("extensions are not the same");
596      return 0;
597    }
598
599    s1 = s1->next;
600    s2 = s2->next;
601  }
602
603  if (((s1 == NULL) && (s2 != NULL)) || ((s1 != NULL) && (s2 == NULL)))
604    return 0;
605
606  return 1;
607}
608
609
610/**
611 * osl_scop_integrity_check function:
612 * This function checks that a scop is "well formed". It returns 0 if the
613 * check failed or 1 if no problem has been detected.
614 * \param scop  The scop we want to check.
615 * \return 0 if the integrity check fails, 1 otherwise.
616 */
617int osl_scop_integrity_check(osl_scop_p scop) {
618  int expected_nb_parameters;
619
620
621  while (scop != NULL) {
622    // Check the language.
623    if ((scop->language != NULL) &&
624        (!strcmp(scop->language, "caml")  || !strcmp(scop->language, "Caml") ||
625         !strcmp(scop->language, "ocaml") || !strcmp(scop->language, "OCaml")))
626      fprintf(stderr, "[OpenScop] Alert: What ?! Caml ?! Are you sure ?!?!\n");
627
628    // Check the context.
629    if (!osl_relation_integrity_check(scop->context,
630                                      OSL_TYPE_CONTEXT,
631                                      OSL_UNDEFINED,
632                                      OSL_UNDEFINED,
633                                      OSL_UNDEFINED))
634      return 0;
635
636    // Get the number of parameters.
637    if (scop->context != NULL)
638      expected_nb_parameters = scop->context->nb_parameters;
639    else
640      expected_nb_parameters = OSL_UNDEFINED;
641
642    // TODO : check the number of parameter strings.
643
644    if (!osl_statement_integrity_check(scop->statement,
645                                       expected_nb_parameters))
646      return 0;
647
648    scop = scop->next;
649  }
650
651  return 1;
652}
653
654
655/**
656 * osl_scop_get_nb_parameters function:
657 * this function returns the number of global parameters of a given SCoP.
658 * \param scop The scop we want to know the number of global parameters.
659 * \return The number of global parameters in the scop.
660 */
661int osl_scop_get_nb_parameters(osl_scop_p scop) {
662
663  if (scop->context == NULL) {
664    OSL_debug("no context domain, assuming 0 parameters");
665    return 0;
666  }
667  else {
668    return scop->context->nb_parameters;
669  }
670}
671
672
673/**
674 * osl_scop_register_extension function:
675 * this function registers a list of extension interfaces to a scop, i.e., it
676 * adds them to the scop registry. In addition, it will extract extensions
677 * corresponding to those interfaces from the textual form of the extensions
678 * (if any) and add them to the scop extension list.
679 * \param scop      The scop for which an extension has to be registered.
680 * \param interface The extension interface to register within the scop.
681 */
682void osl_scop_register_extension(osl_scop_p scop, osl_interface_p interface) {
683  osl_generic_p textual, new;
684  char * extension_string;
685
686  if ((interface != NULL) && (scop != NULL)) {
687    osl_interface_add(&scop->registry, interface);
688
689    textual = osl_generic_lookup(scop->extension, interface->URI);
690    if (textual != NULL) {
691      extension_string = ((osl_textual_p)textual->data)->textual;
692      new = osl_generic_sread(extension_string, interface);
693      osl_generic_add(&scop->extension, new);
694    }
695  }
696}
697
698
699/**
700 * osl_scop_get_attributes function:
701 * this function returns, through its parameters, the maximum values of the
702 * relation attributes (nb_iterators, nb_parameters etc) in the scop.
703 * HOWEVER, it updates the parameter value iff the attribute is greater than
704 * the input parameter value. Hence it may be used to get the attributes as
705 * well as to find the maximum attributes for several scop lists. The array
706 * identifier 0 is used when there is no array identifier (AND this is OK),
707 * OSL_UNDEFINED is used to report it is impossible to provide the property
708 * while it should. This function is not intended for checking, the input
709 * scop should be correct.
710 * \param[in]     scop          The scop to extract attributes values.
711 * \param[in,out] nb_parameters Number of parameter attribute.
712 * \param[in,out] nb_iterators  Number of iterators attribute.
713 * \param[in,out] nb_scattdims  Number of scattering dimensions attribute.
714 * \param[in,out] nb_localdims  Number of local dimensions attribute.
715 * \param[in,out] array_id      Maximum array identifier attribute.
716 */
717void osl_scop_get_attributes(osl_scop_p scop,
718                             int * nb_parameters,
719                             int * nb_iterators,
720                             int * nb_scattdims,
721                             int * nb_localdims,
722                             int * array_id) {
723  int local_nb_parameters = OSL_UNDEFINED;
724  int local_nb_iterators  = OSL_UNDEFINED;
725  int local_nb_scattdims  = OSL_UNDEFINED;
726  int local_nb_localdims  = OSL_UNDEFINED;
727  int local_array_id      = OSL_UNDEFINED;
728
729  while (scop != NULL) {
730    osl_relation_get_attributes(scop->context,
731                                &local_nb_parameters,
732                                &local_nb_iterators,
733                                &local_nb_scattdims,
734                                &local_nb_localdims,
735                                &local_array_id);
736
737    osl_statement_get_attributes(scop->statement,
738                                &local_nb_parameters,
739                                &local_nb_iterators,
740                                &local_nb_scattdims,
741                                &local_nb_localdims,
742                                &local_array_id);
743    // Update.
744    *nb_parameters = OSL_max(*nb_parameters, local_nb_parameters);
745    *nb_iterators  = OSL_max(*nb_iterators,  local_nb_iterators);
746    *nb_scattdims  = OSL_max(*nb_scattdims,  local_nb_scattdims);
747    *nb_localdims  = OSL_max(*nb_localdims,  local_nb_localdims);
748    *array_id      = OSL_max(*array_id,      local_array_id);
749    scop = scop->next;
750  }
751}
752
753
754/**
755 * osl_scop_normalize_scattering function:
756 * this function modifies a scop such that all scattering relation have
757 * the same number of output dimensions (additional output dimensions are
758 * set as being equal to zero).
759 * \param[in,out] scop The scop to nomalize the scattering functions.
760 */
761void osl_scop_normalize_scattering(osl_scop_p scop) {
762  int max_scattering_dims = 0;
763  osl_statement_p statement;
764  osl_relation_p extended;
765
766  if ((scop != NULL) && (scop->statement != NULL)) {
767    // Get the max number of scattering dimensions.
768    statement = scop->statement;
769    while (statement != NULL) {
770      if (statement->scattering != NULL) {
771        max_scattering_dims = OSL_max(max_scattering_dims,
772                                      statement->scattering->nb_output_dims);
773      }
774      statement = statement->next;
775    }
776
777    // Normalize.
778    statement = scop->statement;
779    while (statement != NULL) {
780      if (statement->scattering != NULL) {
781        extended = osl_relation_extend_output(statement->scattering,
782                                              max_scattering_dims);
783        osl_relation_free(statement->scattering);
784        statement->scattering = extended;
785      }
786      statement = statement->next;
787    }
788  }
789}
790
791