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