OpenScop
0.9.0
|
00001 00002 /*+-----------------------------------------------------------------** 00003 ** OpenScop Library ** 00004 **-----------------------------------------------------------------** 00005 ** statement.c ** 00006 **-----------------------------------------------------------------** 00007 ** First version: 30/04/2008 ** 00008 **-----------------------------------------------------------------** 00009 00010 00011 ***************************************************************************** 00012 * OpenScop: Structures and formats for polyhedral tools to talk together * 00013 ***************************************************************************** 00014 * ,___,,_,__,,__,,__,,__,,_,__,,_,__,,__,,___,_,__,,_,__, * 00015 * / / / // // // // / / / // // / / // / /|,_, * 00016 * / / / // // // // / / / // // / / // / / / /\ * 00017 * |~~~|~|~~~|~~~|~~~|~~~|~|~~~|~|~~~|~~~|~~~|~|~~~|~|~~~|/_/ \ * 00018 * | G |C| P | = | L | P |=| = |C| = | = | = |=| = |=| C |\ \ /\ * 00019 * | R |l| o | = | e | l |=| = |a| = | = | = |=| = |=| L | \# \ /\ * 00020 * | A |a| l | = | t | u |=| = |n| = | = | = |=| = |=| o | |\# \ \ * 00021 * | P |n| l | = | s | t |=| = |d| = | = | = | | |=| o | | \# \ \ * 00022 * | H | | y | | e | o | | = |l| | | = | | | | G | | \ \ \ * 00023 * | I | | | | e | | | | | | | | | | | | | \ \ \ * 00024 * | T | | | | | | | | | | | | | | | | | \ \ \ * 00025 * | E | | | | | | | | | | | | | | | | | \ \ \ * 00026 * | * |*| * | * | * | * |*| * |*| * | * | * |*| * |*| * | / \* \ \ * 00027 * | O |p| e | n | S | c |o| p |-| L | i | b |r| a |r| y |/ \ \ / * 00028 * '---'-'---'---'---'---'-'---'-'---'---'---'-'---'-'---' '--' * 00029 * * 00030 * Copyright (C) 2008 University Paris-Sud 11 and INRIA * 00031 * * 00032 * (3-clause BSD license) * 00033 * Redistribution and use in source and binary forms, with or without * 00034 * modification, are permitted provided that the following conditions * 00035 * are met: * 00036 * * 00037 * 1. Redistributions of source code must retain the above copyright notice, * 00038 * this list of conditions and the following disclaimer. * 00039 * 2. Redistributions in binary form must reproduce the above copyright * 00040 * notice, this list of conditions and the following disclaimer in the * 00041 * documentation and/or other materials provided with the distribution. * 00042 * 3. The name of the author may not be used to endorse or promote products * 00043 * derived from this software without specific prior written permission. * 00044 * * 00045 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * 00046 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * 00047 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * 00048 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * 00049 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * 00050 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * 00051 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * 00052 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * 00053 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * 00054 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * 00055 * * 00056 * OpenScop Library, a library to manipulate OpenScop formats and data * 00057 * structures. Written by: * 00058 * Cedric Bastoul <Cedric.Bastoul@u-psud.fr> and * 00059 * Louis-Noel Pouchet <Louis-Noel.pouchet@inria.fr> * 00060 * * 00061 *****************************************************************************/ 00062 00063 00064 #include <stdlib.h> 00065 #include <stdio.h> 00066 #include <string.h> 00067 #include <ctype.h> 00068 00069 #include <osl/macros.h> 00070 #include <osl/util.h> 00071 #include <osl/strings.h> 00072 #include <osl/body.h> 00073 #include <osl/relation.h> 00074 #include <osl/relation_list.h> 00075 #include <osl/names.h> 00076 #include <osl/interface.h> 00077 #include <osl/generic.h> 00078 #include <osl/statement.h> 00079 00080 00081 /*+*************************************************************************** 00082 * Structure display functions * 00083 *****************************************************************************/ 00084 00085 00096 void osl_statement_idump(FILE * file, osl_statement_p statement, int level) { 00097 int j, first = 1, number = 1; 00098 00099 // Go to the right level. 00100 for (j = 0; j < level; j++) 00101 fprintf(file, "|\t"); 00102 00103 if (statement != NULL) 00104 fprintf(file, "+-- osl_statement_t (S%d)\n", number); 00105 else 00106 fprintf(file, "+-- NULL statement\n"); 00107 00108 while (statement != NULL) { 00109 if (!first) { 00110 // Go to the right level. 00111 for (j = 0; j < level; j++) 00112 fprintf(file, "|\t"); 00113 fprintf(file, "| osl_statement_t (S%d)\n", number); 00114 } 00115 else 00116 first = 0; 00117 00118 // A blank line. 00119 for (j = 0; j <= level + 1; j++) 00120 fprintf(file, "|\t"); 00121 fprintf(file, "\n"); 00122 00123 // Print the domain of the statement. 00124 osl_relation_idump(file, statement->domain, level + 1); 00125 00126 // Print the scattering of the statement. 00127 osl_relation_idump(file, statement->scattering, level + 1); 00128 00129 // Print the array access information of the statement. 00130 osl_relation_list_idump(file, statement->access, level + 1); 00131 00132 // Print the original body expression. 00133 osl_generic_idump(file, statement->extension, level + 1); 00134 00135 statement = statement->next; 00136 number++; 00137 00138 // Next line. 00139 if (statement != NULL) { 00140 for (j = 0; j <= level; j++) 00141 fprintf(file, "|\t"); 00142 fprintf(file, "V\n"); 00143 } 00144 } 00145 00146 // The last line. 00147 for (j = 0; j <= level; j++) 00148 fprintf(file, "|\t"); 00149 fprintf(file, "\n"); 00150 } 00151 00152 00160 void osl_statement_dump(FILE * file, osl_statement_p statement) { 00161 osl_statement_idump(file, statement, 0); 00162 } 00163 00164 00172 static 00173 osl_names_p osl_statement_names(osl_statement_p statement) { 00174 int nb_parameters = OSL_UNDEFINED; 00175 int nb_iterators = OSL_UNDEFINED; 00176 int nb_scattdims = OSL_UNDEFINED; 00177 int nb_localdims = OSL_UNDEFINED; 00178 int array_id = OSL_UNDEFINED; 00179 00180 osl_statement_get_attributes(statement, &nb_parameters, &nb_iterators, 00181 &nb_scattdims, &nb_localdims, &array_id); 00182 00183 return osl_names_generate("P", nb_parameters, 00184 "i", nb_iterators, 00185 "c", nb_scattdims, 00186 "l", nb_localdims, 00187 "A", array_id); 00188 } 00189 00190 00199 void osl_statement_pprint(FILE * file, osl_statement_p statement, 00200 osl_names_p names) { 00201 size_t nb_relations; 00202 int number = 1; 00203 int generated_names = 0; 00204 int iterators_backedup = 0; 00205 int nb_ext = 0; 00206 osl_body_p body = NULL; 00207 osl_strings_p iterators_backup = NULL; 00208 00209 // Generate the dimension names if necessary and replace iterators with 00210 // statement iterators if possible. 00211 if (names == NULL) { 00212 generated_names = 1; 00213 names = osl_statement_names(statement); 00214 } 00215 00216 while (statement != NULL) { 00217 // If possible, replace iterator names with statement iterator names. 00218 body = (osl_body_p)osl_generic_lookup(statement->extension, OSL_URI_BODY); 00219 if (body && body->iterators != NULL) { 00220 iterators_backedup = 1; 00221 iterators_backup = names->iterators; 00222 names->iterators = body->iterators; 00223 } 00224 00225 nb_relations = 0; 00226 00227 fprintf(file, "# =============================================== "); 00228 fprintf(file, "Statement %d\n", number); 00229 00230 fprintf(file, "# Number of relations describing the statement:\n"); 00231 00232 if (statement->domain != NULL) 00233 nb_relations ++; 00234 if (statement->scattering != NULL) 00235 nb_relations ++; 00236 nb_relations += osl_relation_list_count(statement->access); 00237 00238 fprintf(file, "%lu\n\n", nb_relations); 00239 00240 fprintf(file, "# ---------------------------------------------- "); 00241 fprintf(file, "%2d.1 Domain\n", number); 00242 osl_relation_pprint(file, statement->domain, names); 00243 fprintf(file, "\n"); 00244 00245 fprintf(file, "# ---------------------------------------------- "); 00246 fprintf(file, "%2d.2 Scattering\n", number); 00247 osl_relation_pprint(file, statement->scattering, names); 00248 fprintf(file, "\n"); 00249 00250 fprintf(file, "# ---------------------------------------------- "); 00251 fprintf(file, "%2d.3 Access\n", number); 00252 osl_relation_list_pprint_elts(file, statement->access, names); 00253 fprintf(file, "\n"); 00254 00255 fprintf(file, "# ---------------------------------------------- "); 00256 fprintf(file, "%2d.4 Statement Extensions\n", number); 00257 fprintf(file, "# Number of Statement Extensions\n"); 00258 nb_ext = osl_generic_number(statement->extension); 00259 fprintf(file, "%d\n", nb_ext); 00260 if(nb_ext>0) 00261 osl_generic_print(file, statement->extension); 00262 00263 fprintf(file, "\n"); 00264 00265 // If necessary, switch back iterator names. 00266 if (iterators_backedup) { 00267 iterators_backedup = 0; 00268 names->iterators = iterators_backup; 00269 } 00270 00271 statement = statement->next; 00272 number++; 00273 } 00274 00275 if (generated_names) 00276 osl_names_free(names); 00277 } 00278 00279 00288 void osl_statement_pprint_scoplib(FILE * file, osl_statement_p statement, 00289 osl_names_p names) { 00290 int number = 1; 00291 int generated_names = 0; 00292 int iterators_backedup = 0; 00293 osl_body_p body = NULL; 00294 osl_strings_p iterators_backup = NULL; 00295 int add_fakeiter; 00296 00297 // Generate the dimension names if necessary and replace iterators with 00298 // statement iterators if possible. 00299 if (names == NULL) { 00300 generated_names = 1; 00301 names = osl_statement_names(statement); 00302 } 00303 00304 while (statement != NULL) { 00305 // If possible, replace iterator names with statement iterator names. 00306 body = (osl_body_p)osl_generic_lookup(statement->extension, OSL_URI_BODY); 00307 if (body && body->iterators != NULL) { 00308 iterators_backedup = 1; 00309 iterators_backup = names->iterators; 00310 names->iterators = body->iterators; 00311 } 00312 00313 add_fakeiter = statement->domain->nb_rows == 0 && 00314 statement->scattering->nb_rows == 1; 00315 00316 fprintf(file, "# =============================================== "); 00317 fprintf(file, "Statement %d\n", number); 00318 00319 fprintf(file, "# ---------------------------------------------- "); 00320 fprintf(file, "%2d.1 Domain\n", number); 00321 fprintf(file, "# Iteration domain\n"); 00322 osl_relation_pprint_scoplib(file, statement->domain, names, 1, add_fakeiter); 00323 fprintf(file, "\n"); 00324 00325 fprintf(file, "# ---------------------------------------------- "); 00326 fprintf(file, "%2d.2 Scattering\n", number); 00327 fprintf(file,"# Scattering function is provided\n1\n"); 00328 osl_relation_pprint_scoplib(file, statement->scattering, names, 0, 00329 add_fakeiter); 00330 fprintf(file, "\n"); 00331 00332 fprintf(file, "# ---------------------------------------------- "); 00333 fprintf(file, "%2d.3 Access\n", number); 00334 fprintf(file,"# Access informations are provided\n1\n"); 00335 00336 osl_relation_list_pprint_access_array_scoplib(file, statement->access, 00337 names, add_fakeiter); 00338 fprintf(file, "\n"); 00339 00340 fprintf(file, "# ---------------------------------------------- "); 00341 fprintf(file, "%2d.4 Body\n", number); 00342 if (body != NULL) { 00343 fprintf(file, "# Statement body is provided\n1\n"); 00344 osl_body_print_scoplib(file, body); 00345 body = NULL; //re-initialize for next statement 00346 } 00347 else { 00348 fprintf(file, "# Statement body is not provided\n0\n"); 00349 } 00350 00351 fprintf(file, "\n"); 00352 00353 // If necessary, switch back iterator names. 00354 if (iterators_backedup) { 00355 iterators_backedup = 0; 00356 names->iterators = iterators_backup; 00357 } 00358 00359 statement = statement->next; 00360 number++; 00361 } 00362 00363 if (generated_names) 00364 osl_names_free(names); 00365 } 00366 00367 00375 void osl_statement_print(FILE * file, osl_statement_p statement) { 00376 00377 osl_statement_pprint(file, statement, NULL); 00378 } 00379 00380 00381 /***************************************************************************** 00382 * Reading function * 00383 *****************************************************************************/ 00384 00385 00395 static 00396 void osl_statement_dispatch(osl_statement_p stmt, osl_relation_list_p list) { 00397 osl_relation_list_p domain_list; 00398 osl_relation_list_p scattering_list; 00399 size_t nb_domains, nb_scattering, nb_accesses; 00400 00401 // Domain. 00402 domain_list = osl_relation_list_filter(list, OSL_TYPE_DOMAIN); 00403 nb_domains = osl_relation_list_count(domain_list); 00404 if (nb_domains > 1) 00405 OSL_error("more than one domain for a statement"); 00406 00407 if (domain_list != NULL) { 00408 stmt->domain = domain_list->elt; 00409 domain_list->elt = NULL; 00410 osl_relation_list_free(domain_list); 00411 } 00412 else { 00413 stmt->domain = NULL; 00414 } 00415 00416 // Scattering. 00417 scattering_list=osl_relation_list_filter(list,OSL_TYPE_SCATTERING); 00418 nb_scattering = osl_relation_list_count(scattering_list); 00419 if (nb_scattering > 1) 00420 OSL_error("more than one scattering relation for a statement"); 00421 00422 if (scattering_list != NULL) { 00423 stmt->scattering = scattering_list->elt; 00424 scattering_list->elt = NULL; 00425 osl_relation_list_free(scattering_list); 00426 } 00427 else { 00428 stmt->scattering = NULL; 00429 } 00430 00431 // Access. 00432 stmt->access = osl_relation_list_filter(list, OSL_TYPE_ACCESS); 00433 nb_accesses = osl_relation_list_count(stmt->access); 00434 00435 if ((nb_domains + nb_scattering + nb_accesses) != 00436 (osl_relation_list_count(list))) 00437 OSL_error("unexpected relation type to define a statement"); 00438 00439 osl_relation_list_free(list); 00440 } 00441 00442 00452 osl_statement_p osl_statement_pread(FILE * file, osl_interface_p registry, 00453 int precision) { 00454 osl_statement_p stmt = osl_statement_malloc(); 00455 osl_relation_list_p list; 00456 osl_generic_p new = NULL; 00457 int i, nb_ext = 0; 00458 00459 if (file) { 00460 // Read all statement relations. 00461 list = osl_relation_list_pread(file, precision); 00462 00463 // Store relations at the right place according to their type. 00464 osl_statement_dispatch(stmt, list); 00465 00466 // Read the Extensions 00467 nb_ext = osl_util_read_int(file, NULL); 00468 for (i=0; i<nb_ext; i++) { 00469 new = osl_generic_read_one(file, registry); 00470 osl_generic_add(&stmt->extension, new); 00471 } 00472 } 00473 00474 return stmt; 00475 } 00476 00477 00486 osl_statement_p osl_statement_read(FILE * foo) { 00487 int precision = osl_util_get_precision(); 00488 osl_interface_p registry = osl_interface_get_default_registry(); 00489 osl_statement_p statement = osl_statement_pread(foo, registry, precision); 00490 00491 osl_interface_free(registry); 00492 return statement; 00493 } 00494 00495 00496 /*+*************************************************************************** 00497 * Memory allocation/deallocation functions * 00498 *****************************************************************************/ 00499 00500 00508 osl_statement_p osl_statement_malloc() { 00509 osl_statement_p statement; 00510 00511 OSL_malloc(statement, osl_statement_p, sizeof(osl_statement_t)); 00512 statement->domain = NULL; 00513 statement->scattering = NULL; 00514 statement->access = NULL; 00515 statement->extension = NULL; 00516 statement->next = NULL; 00517 00518 return statement; 00519 } 00520 00521 00528 void osl_statement_free(osl_statement_p statement) { 00529 osl_statement_p next; 00530 00531 while (statement != NULL) { 00532 next = statement->next; 00533 osl_relation_free(statement->domain); 00534 osl_relation_free(statement->scattering); 00535 osl_relation_list_free(statement->access); 00536 osl_generic_free(statement->extension); 00537 00538 free(statement); 00539 statement = next; 00540 } 00541 } 00542 00543 00544 /*+*************************************************************************** 00545 * Processing functions * 00546 *****************************************************************************/ 00547 00548 00556 void osl_statement_add(osl_statement_p * location, 00557 osl_statement_p statement) { 00558 while (*location != NULL) 00559 location = &((*location)->next); 00560 00561 *location = statement; 00562 } 00563 00564 00572 int osl_statement_number(osl_statement_p statement) { 00573 int number = 0; 00574 00575 while (statement != NULL) { 00576 number++; 00577 statement = statement->next; 00578 } 00579 return number; 00580 } 00581 00582 00591 osl_statement_p osl_statement_nclone(osl_statement_p statement, int n) { 00592 int first = 1, i = 0; 00593 osl_statement_p clone = NULL, node, previous = NULL; 00594 00595 while ((statement != NULL) && ((n == -1) || (i < n))) { 00596 node = osl_statement_malloc(); 00597 node->domain = osl_relation_clone(statement->domain); 00598 node->scattering = osl_relation_clone(statement->scattering); 00599 node->access = osl_relation_list_clone(statement->access); 00600 node->extension = osl_generic_clone(statement->extension); 00601 node->next = NULL; 00602 00603 if (first) { 00604 first = 0; 00605 clone = node; 00606 previous = node; 00607 } 00608 else { 00609 previous->next = node; 00610 previous = previous->next; 00611 } 00612 00613 i++; 00614 statement = statement->next; 00615 } 00616 00617 return clone; 00618 } 00619 00620 00628 osl_statement_p osl_statement_clone(osl_statement_p statement) { 00629 return osl_statement_nclone(statement, -1); 00630 } 00631 00632 00641 int osl_statement_equal(osl_statement_p s1, osl_statement_p s2) { 00642 00643 if (s1 == s2) 00644 return 1; 00645 00646 if (((s1->next != NULL) && (s2->next == NULL)) || 00647 ((s1->next == NULL) && (s2->next != NULL))) { 00648 OSL_info("statements are not the same"); 00649 return 0; 00650 } 00651 00652 if ((s1->next != NULL) && (s2->next != NULL)) { 00653 if (!osl_statement_equal(s1->next, s2->next)) { 00654 OSL_info("number of statements is not the same"); 00655 return 0; 00656 } 00657 } 00658 00659 if (!osl_relation_equal(s1->domain, s2->domain)) { 00660 OSL_info("statement domains are not the same"); 00661 return 0; 00662 } 00663 00664 if (!osl_relation_equal(s1->scattering, s2->scattering)) { 00665 OSL_info("statement scatterings are not the same"); 00666 return 0; 00667 } 00668 00669 if (!osl_relation_list_equal(s1->access, s2->access)) { 00670 OSL_info("statement accesses are not the same"); 00671 return 0; 00672 } 00673 00674 if (!osl_generic_equal(s1->extension, s2->extension)) { 00675 OSL_info("statement bodies are not the same"); 00676 return 0; 00677 } 00678 00679 return 1; 00680 } 00681 00682 00693 int osl_statement_integrity_check(osl_statement_p statement, 00694 int expected_nb_parameters) { 00695 int expected_nb_iterators; 00696 osl_body_p body = NULL; 00697 00698 while (statement != NULL) { 00699 // Check the domain. 00700 if (!osl_relation_integrity_check(statement->domain, 00701 OSL_TYPE_DOMAIN, 00702 OSL_UNDEFINED, 00703 0, 00704 expected_nb_parameters)) { 00705 return 0; 00706 } 00707 00708 // Get the number of iterators. 00709 if (statement->domain != NULL) 00710 expected_nb_iterators = statement->domain->nb_output_dims; 00711 else 00712 expected_nb_iterators = OSL_UNDEFINED; 00713 00714 // Check the scattering relation. 00715 if (!osl_relation_integrity_check(statement->scattering, 00716 OSL_TYPE_SCATTERING, 00717 OSL_UNDEFINED, 00718 expected_nb_iterators, 00719 expected_nb_parameters)) { 00720 return 0; 00721 } 00722 00723 // Check the access relations. 00724 if (!osl_relation_list_integrity_check(statement->access, 00725 OSL_TYPE_ACCESS, 00726 OSL_UNDEFINED, 00727 expected_nb_iterators, 00728 expected_nb_parameters)) { 00729 return 0; 00730 } 00731 00732 // Check the statement body. 00733 body = (osl_body_p)osl_generic_lookup(statement->extension, OSL_URI_BODY); 00734 if ((expected_nb_iterators != OSL_UNDEFINED) && 00735 body && body->iterators != NULL && 00736 ((size_t)expected_nb_iterators != osl_strings_size(body->iterators))) { 00737 OSL_warning("unexpected number of original iterators"); 00738 return 0; 00739 } 00740 00741 statement = statement->next; 00742 } 00743 00744 return 1; 00745 } 00746 00747 00755 int osl_statement_get_nb_iterators(osl_statement_p statement) { 00756 00757 if (statement->domain == NULL) { 00758 OSL_warning("no statement domain, assuming 0 iterators"); 00759 return 0; 00760 } 00761 else { 00762 return statement->domain->nb_output_dims; 00763 } 00764 } 00765 00766 00785 void osl_statement_get_attributes(osl_statement_p statement, 00786 int * nb_parameters, 00787 int * nb_iterators, 00788 int * nb_scattdims, 00789 int * nb_localdims, 00790 int * array_id) { 00791 int local_nb_parameters = OSL_UNDEFINED; 00792 int local_nb_iterators = OSL_UNDEFINED; 00793 int local_nb_scattdims = OSL_UNDEFINED; 00794 int local_nb_localdims = OSL_UNDEFINED; 00795 int local_array_id = OSL_UNDEFINED; 00796 00797 while (statement != NULL) { 00798 osl_relation_get_attributes(statement->domain, 00799 &local_nb_parameters, 00800 &local_nb_iterators, 00801 &local_nb_scattdims, 00802 &local_nb_localdims, 00803 &local_array_id); 00804 00805 osl_relation_get_attributes(statement->scattering, 00806 &local_nb_parameters, 00807 &local_nb_iterators, 00808 &local_nb_scattdims, 00809 &local_nb_localdims, 00810 &local_array_id); 00811 00812 osl_relation_list_get_attributes(statement->access, 00813 &local_nb_parameters, 00814 &local_nb_iterators, 00815 &local_nb_scattdims, 00816 &local_nb_localdims, 00817 &local_array_id); 00818 // Update. 00819 *nb_parameters = OSL_max(*nb_parameters, local_nb_parameters); 00820 *nb_iterators = OSL_max(*nb_iterators, local_nb_iterators); 00821 *nb_scattdims = OSL_max(*nb_scattdims, local_nb_scattdims); 00822 *nb_localdims = OSL_max(*nb_localdims, local_nb_localdims); 00823 *array_id = OSL_max(*array_id, local_array_id); 00824 statement = statement->next; 00825 } 00826 } 00827 00828 00835 osl_body_p osl_statement_get_body(osl_statement_p statement) { 00836 osl_body_p body; 00837 osl_extbody_p ebody; 00838 00839 if (statement == NULL || statement->extension == NULL) { 00840 return NULL; 00841 } 00842 00843 body = (osl_body_p)osl_generic_lookup(statement->extension, OSL_URI_BODY); 00844 if (body != NULL) 00845 return body; 00846 ebody = (osl_extbody_p)osl_generic_lookup(statement->extension, 00847 OSL_URI_EXTBODY); 00848 if (ebody != NULL) 00849 return ebody->body; 00850 return NULL; 00851 }