1 /* 2 * Copyright 2016, 2017 Tobias Grosser. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 11 * 2. Redistributions in binary form must reproduce the above 12 * copyright notice, this list of conditions and the following 13 * disclaimer in the documentation and/or other materials provided 14 * with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY TOBIAS GROSSER ''AS IS'' AND ANY 17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL TOBIAS GROSSER OR 20 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 21 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 22 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 23 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * 28 * The views and conclusions contained in the software and documentation 29 * are those of the authors and should not be interpreted as 30 * representing official policies, either expressed or implied, of 31 * Tobias Grosser. 32 */ 33 34 #include <iostream> 35 #include <string> 36 #include <vector> 37 38 #include "cpp.h" 39 #include "isl_config.h" 40 41 /* Determine the isl types from which the given class can be implicitly 42 * constructed using a unary constructor. 43 * 44 * Look through all constructors for implicit conversion constructors that take 45 * an isl type and add those types, along with the corresponding 46 * constructor argument. 47 */ 48 void cpp_generator::set_class_construction_types(isl_class &clazz) 49 { 50 for (const auto &cons : clazz.constructors) { 51 ParmVarDecl *param; 52 QualType type; 53 std::string arg_type; 54 55 if (!is_implicit_conversion(Method(clazz, cons))) 56 continue; 57 58 param = cons->getParamDecl(0); 59 type = param->getOriginalType(); 60 arg_type = extract_type(type); 61 clazz.construction_types.emplace(arg_type, param); 62 } 63 } 64 65 /* Determine the isl types from which any (proper) class can be constructed 66 * using a unary constructor. 67 */ 68 void cpp_generator::set_construction_types() 69 { 70 for (auto &kvp : classes) { 71 auto &clazz = kvp.second; 72 set_class_construction_types(clazz); 73 } 74 } 75 76 /* Construct a generator for C++ bindings. 77 * 78 * The classes and methods are extracted by the constructor 79 * of the generator superclass. 80 * 81 * Additionally extract information about types 82 * that can be converted to a class and copy all methods 83 * from superclasses that can be converted to a given class 84 * to that class. 85 */ 86 cpp_generator::cpp_generator(SourceManager &SM, 87 set<RecordDecl *> &exported_types, 88 set<FunctionDecl *> exported_functions, set<FunctionDecl *> functions) : 89 generator(SM, exported_types, exported_functions, functions) 90 { 91 set_construction_types(); 92 copy_super_methods(); 93 } 94 95 /* Copy the method called "name" described by "fd" from "super" to "clazz" 96 * with the distance to the original ancestor given by "depth". 97 * 98 * In particular, keep track of "fd" as well as the superclass 99 * from which it was copied and the distance to the original ancestor. 100 */ 101 static void copy_method(isl_class &clazz, const isl_class &super, 102 const std::string &name, FunctionDecl *fd, int depth) 103 { 104 clazz.methods[name].insert(fd); 105 clazz.copied_from.emplace(fd, super); 106 clazz.copy_depth.emplace(fd, depth); 107 } 108 109 /* Do "fd1" and "fd2" have the same signature (ignoring the first argument 110 * which represents the object class on which the corresponding method 111 * gets called). 112 */ 113 static bool same_signature(FunctionDecl *fd1, FunctionDecl *fd2) 114 { 115 int n1 = fd1->getNumParams(); 116 int n2 = fd2->getNumParams(); 117 118 if (n1 != n2) 119 return false; 120 121 for (int i = 1; i < n1; ++i) { 122 ParmVarDecl *p1 = fd1->getParamDecl(i); 123 ParmVarDecl *p2 = fd2->getParamDecl(i); 124 125 if (p1->getOriginalType() != p2->getOriginalType()) 126 return false; 127 } 128 129 return true; 130 } 131 132 /* Return the distance between "clazz" and the ancestor 133 * from which "fd" got copied. 134 * If no distance was recorded, then the method has not been copied 135 * but appears in "clazz" itself and so the distance is zero. 136 */ 137 static int copy_depth(const isl_class &clazz, FunctionDecl *fd) 138 { 139 if (clazz.copy_depth.count(fd) == 0) 140 return 0; 141 return clazz.copy_depth.at(fd); 142 } 143 144 /* Is the method derived from "fd", with method name "name" and 145 * with distance to the original ancestor "depth", 146 * overridden by a method already in "clazz"? 147 * 148 * A method is considered to have been overridden if there 149 * is a method with the same name in "clazz" that has the same signature and 150 * that comes from an ancestor closer to "clazz", 151 * where an ancestor is closer if the distance in the class hierarchy 152 * is smaller or the distance is the same and the ancestor appears 153 * closer in the declaration of the type (in which case it gets added first). 154 * 155 * If a method with the same signature has already been added, 156 * but it does not override the method derived from "fd", 157 * then this method is removed since it is overridden by "fd". 158 */ 159 static bool is_overridden(FunctionDecl *fd, isl_class &clazz, 160 const std::string &name, int depth) 161 { 162 if (clazz.methods.count(name) == 0) 163 return false; 164 165 for (const auto &m : clazz.methods.at(name)) { 166 if (!same_signature(fd, m)) 167 continue; 168 if (copy_depth(clazz, m) <= depth) 169 return true; 170 clazz.methods[name].erase(m); 171 return false; 172 } 173 return false; 174 } 175 176 /* Add the methods "methods" with method name "name" from "super" to "clazz" 177 * provided they have not been overridden by a method already in "clazz". 178 * 179 * Methods that are static in their original class are not copied. 180 */ 181 void cpp_generator::copy_methods(isl_class &clazz, const std::string &name, 182 const isl_class &super, const function_set &methods) 183 { 184 for (auto fd : methods) { 185 int depth; 186 187 if (method2class(fd)->is_static(fd)) 188 continue; 189 depth = copy_depth(super, fd) + 1; 190 if (is_overridden(fd, clazz, name, depth)) 191 continue; 192 copy_method(clazz, super, name, fd, depth); 193 } 194 } 195 196 /* Add all methods from "super" to "clazz" that have not been overridden 197 * by a method already in "clazz". 198 * 199 * Look through all groups of methods with the same name. 200 */ 201 void cpp_generator::copy_super_methods(isl_class &clazz, const isl_class &super) 202 { 203 for (const auto &kvp : super.methods) { 204 const auto &name = kvp.first; 205 const auto &methods = kvp.second; 206 207 copy_methods(clazz, name, super, methods); 208 } 209 } 210 211 /* Copy methods from the superclasses of "clazz" 212 * if an object of this class can be implicitly converted to an object 213 * from the superclass, keeping track 214 * of the classes that have already been handled in "done". 215 * 216 * Make sure the superclasses have copied methods from their superclasses first 217 * since those methods could be copied further down to this class. 218 * 219 * Consider the superclass that appears closest to the subclass first. 220 */ 221 void cpp_generator::copy_super_methods(isl_class &clazz, set<string> &done) 222 { 223 auto supers = find_superclasses(clazz.type); 224 225 for (const auto &super : supers) 226 if (done.count(super) == 0) 227 copy_super_methods(classes[super], done); 228 done.insert(clazz.name); 229 230 for (const auto &super_name : supers) { 231 const auto &super = classes[super_name]; 232 233 if (super.construction_types.count(clazz.name) == 0) 234 continue; 235 copy_super_methods(clazz, super); 236 } 237 } 238 239 /* For each (proper) class, copy methods from its superclasses, 240 * if an object from the class can be converted to an object 241 * from the superclass. 242 * 243 * Type based subclasses are not considered for now since 244 * they do not have any explicit superclasses. 245 * 246 * Iterate through all (proper) classes and copy methods 247 * from their superclasses, 248 * unless they have already been determined by a recursive call. 249 */ 250 void cpp_generator::copy_super_methods() 251 { 252 set<string> done; 253 254 for (auto &kvp : classes) { 255 auto &clazz = kvp.second; 256 257 if (clazz.is_type_subclass()) 258 continue; 259 if (done.count(clazz.name) != 0) 260 continue; 261 copy_super_methods(clazz, done); 262 } 263 } 264 265 /* Print declarations or implementations of constructors. 266 * 267 * For each isl function that is marked as __isl_constructor, 268 * add a corresponding C++ constructor. 269 * 270 * Example of declarations: 271 * 272 * inline /\* implicit *\/ union_set(basic_set bset); 273 * inline /\* implicit *\/ union_set(set set); 274 * inline explicit val(ctx ctx, long i); 275 * inline explicit val(ctx ctx, const std::string &str); 276 */ 277 void cpp_generator::class_printer::print_constructors() 278 { 279 for (const auto &cons : clazz.constructors) 280 print_method(Method(clazz, cons)); 281 } 282 283 /* Print declarations or definitions for methods in the class. 284 */ 285 void cpp_generator::class_printer::print_methods() 286 { 287 for (const auto &kvp : clazz.methods) 288 print_method_group(kvp.second, kvp.first); 289 } 290 291 /* Print declarations or implementations for the methods derived from "fd", 292 * which sets an enum. 293 * 294 * A method is generated for each value in the enum, setting 295 * the enum to that value. 296 */ 297 void cpp_generator::class_printer::print_set_enums(FunctionDecl *fd) 298 { 299 for (const auto &set : clazz.set_enums.at(fd)) { 300 EnumMethod method(clazz, fd, set.method_name, set.name); 301 302 print_method(method); 303 } 304 } 305 306 /* Print declarations or implementations for methods derived from functions 307 * that set an enum. 308 */ 309 void cpp_generator::class_printer::print_set_enums() 310 { 311 for (const auto &kvp : clazz.set_enums) 312 print_set_enums(kvp.first); 313 } 314 315 /* Update "convert" to reflect the next combination of automatic conversions 316 * for the arguments of "fd", 317 * returning false if there are no more combinations. 318 * 319 * In particular, find the last argument for which an automatic 320 * conversion function is available mapping to the type of this argument and 321 * that is not already marked for conversion. 322 * Mark this argument, if any, for conversion and clear the markings 323 * of all subsequent arguments. 324 * Repeated calls to this method therefore run through 325 * all possible combinations. 326 * 327 * Note that the first function argument is never considered 328 * for automatic conversion since this is the argument 329 * from which the isl_ctx used in the conversion is extracted. 330 */ 331 bool cpp_generator::class_printer::next_variant(FunctionDecl *fd, 332 std::vector<bool> &convert) 333 { 334 size_t n = convert.size(); 335 336 for (int i = n - 1; i >= 1; --i) { 337 ParmVarDecl *param = fd->getParamDecl(i); 338 const Type *type = param->getOriginalType().getTypePtr(); 339 340 if (generator.conversions.count(type) == 0) 341 continue; 342 if (convert[i]) 343 continue; 344 convert[i] = true; 345 for (size_t j = i + 1; j < n; ++j) 346 convert[j] = false; 347 return true; 348 } 349 350 return false; 351 } 352 353 /* Print a declaration or definition for a method called "name" 354 * derived from "fd". 355 * 356 * If the method was copied from a superclass, then print a definition 357 * that calls the corresponding method in the superclass. 358 * Otherwise, for methods that are identified as "get" methods, also 359 * print a declaration or definition for the method 360 * using a name that includes the "get_" prefix. 361 * 362 * If the generated method is an object method, then check 363 * whether any of its arguments can be automatically converted 364 * from something else, and, if so, generate a method 365 * for each combination of converted arguments. 366 * Do so by constructing a ConversionMethod that changes the converted arguments 367 * to those of the sources of the conversions. 368 * 369 * Note that a method may be both copied from a superclass and 370 * have arguments that can be automatically converted. 371 * In this case, the conversion methods for the arguments 372 * call the corresponding method in this class, which 373 * in turn will call the method in the superclass. 374 */ 375 void cpp_generator::class_printer::print_method_variants(FunctionDecl *fd, 376 const std::string &name) 377 { 378 Method method(clazz, fd, name); 379 std::vector<bool> convert(method.num_params()); 380 381 if (method.clazz.copied_from.count(method.fd) == 0) { 382 print_method(method); 383 if (clazz.is_get_method(fd)) 384 print_get_method(fd); 385 } else { 386 auto super = method.clazz.copied_from.at(method.fd); 387 print_method(ConversionMethod(method, super.name)); 388 } 389 if (method.kind != Method::Kind::member_method) 390 return; 391 while (next_variant(fd, convert)) { 392 print_method(ConversionMethod(method, [&] (int pos) { 393 return get_param(fd, pos, convert); 394 })); 395 } 396 } 397 398 /* Given a function declaration representing a method, 399 * does this method have a single argument (beyond the object 400 * on which the method is called) that corresponds to 401 * an isl object? 402 */ 403 static bool has_single_isl_argument(FunctionDecl *fd) 404 { 405 ParmVarDecl *param; 406 407 if (fd->getNumParams() != 2) 408 return false; 409 410 param = fd->getParamDecl(1); 411 return generator::is_isl_type(param->getOriginalType()); 412 } 413 414 /* Does the set "methods" contain exactly one function declaration 415 * that corresponds to a method of "clazz" itself (i.e., that 416 * was not copied from an ancestor)? 417 */ 418 static FunctionDecl *single_local(const isl_class &clazz, 419 const function_set &methods) 420 { 421 int count = 0; 422 FunctionDecl *local; 423 424 for (const auto &fn : methods) { 425 if (!clazz.first_arg_matches_class(fn)) 426 continue; 427 ++count; 428 local = fn; 429 } 430 431 return count == 1 ? local : NULL; 432 } 433 434 /* Given a function declaration "fd" for a method called "name" 435 * with a single argument representing an isl object, 436 * generate declarations or definitions for methods with the same name, 437 * but with as argument an isl object of a class that can be implicitly 438 * converted to that of the original argument. 439 * In particular, generate methods for converting this argument. 440 */ 441 void cpp_generator::class_printer::print_descendent_overloads( 442 FunctionDecl *fd, const std::string &name) 443 { 444 Method method(clazz, fd, name); 445 ParmVarDecl *param = fd->getParamDecl(1); 446 QualType type = param->getOriginalType(); 447 std::string arg = type->getPointeeType().getAsString(); 448 449 for (const auto &kvp : generator.classes[arg].construction_types) { 450 const auto sub = kvp.second; 451 print_method(ConversionMethod(method, [&] (int pos) { 452 return sub; 453 })); 454 } 455 } 456 457 /* Print declarations or definitions for methods called "name" 458 * derived from "methods". 459 * 460 * If want_descendent_overloads signals that variants should be added that take 461 * as arguments those types that can be converted to the original argument type 462 * through a unary constructor and if only one of the methods in the group 463 * was originally defined in "clazz", then effectively add those variants. 464 * Only do this for methods with a single (isl object) argument. 465 */ 466 void cpp_generator::class_printer::print_method_group( 467 const function_set &methods, const std::string &name) 468 { 469 FunctionDecl *local; 470 471 for (const auto &fd : methods) 472 print_method_variants(fd, name); 473 if (!want_descendent_overloads(methods)) 474 return; 475 local = single_local(clazz, methods); 476 if (!local) 477 return; 478 if (!has_single_isl_argument(local)) 479 return; 480 print_descendent_overloads(local, name); 481 } 482 483 /* Print the use of the argument at position "pos" to "os". 484 * 485 * Member methods pass the isl object corresponding to "this" 486 * as first argument (at position 0). 487 * Any other arguments are passed along from the method arguments. 488 * 489 * If the argument value is loaded from a this pointer, the original 490 * value must be preserved and must consequently be copied. Values that are 491 * loaded from method parameters do not need to be preserved, as such values 492 * will already be copies of the actual parameters. It is consequently possible 493 * to directly take the pointer from these values, which saves 494 * an unnecessary copy. 495 * 496 * In case the parameter is a callback function, two parameters get printed, 497 * a wrapper for the callback function and a pointer to the actual 498 * callback function. The wrapper is expected to be available 499 * in a previously declared variable <name>_lambda, while 500 * the actual callback function is expected to be stored 501 * in a structure called <name>_data. 502 * The caller of this function must ensure that these variables exist. 503 */ 504 void Method::print_param_use(ostream &os, int pos) const 505 { 506 ParmVarDecl *param = fd->getParamDecl(pos); 507 bool load_from_this_ptr = pos == 0 && kind == member_method; 508 string name = param->getName().str(); 509 QualType type = param->getOriginalType(); 510 511 if (type->isIntegerType()) { 512 os << name; 513 return; 514 } 515 516 if (generator::is_string(type)) { 517 os << name << ".c_str()"; 518 return; 519 } 520 521 if (generator::is_callback(type)) { 522 os << name << "_lambda, "; 523 os << "&" << name << "_data"; 524 return; 525 } 526 527 if (!load_from_this_ptr) 528 os << name << "."; 529 530 if (generator::keeps(param)) { 531 os << "get()"; 532 } else { 533 if (load_from_this_ptr) 534 os << "copy()"; 535 else 536 os << "release()"; 537 } 538 } 539 540 /* Does the isl function from which this method is derived 541 * modify an object of a subclass based on a type function? 542 */ 543 bool Method::is_subclass_mutator() const 544 { 545 return clazz.is_type_subclass() && generator::is_mutator(clazz, fd); 546 } 547 548 /* Return the C++ return type of the method "method". 549 * 550 * If the corresponding function modifies an object of a subclass, then return 551 * the type of this subclass. 552 * Otherwise, return the C++ counterpart of the actual return type. 553 */ 554 std::string cpp_type_printer::return_type(const Method &method) const 555 { 556 if (method.is_subclass_mutator()) 557 return cpp_generator::type2cpp(method.clazz); 558 else 559 return param(-1, method.fd->getReturnType()); 560 } 561 562 /* Return the formal parameter at position "pos" of "fd". 563 * However, if this parameter should be converted, as indicated 564 * by "convert", then return the second formal parameter 565 * of the conversion function instead. 566 */ 567 ParmVarDecl *cpp_generator::class_printer::get_param(FunctionDecl *fd, 568 int pos, const std::vector<bool> &convert) 569 { 570 ParmVarDecl *param = fd->getParamDecl(pos); 571 572 if (!convert[pos]) 573 return param; 574 return generator.conversions[param->getOriginalType().getTypePtr()]; 575 } 576 577 /* Print the header for "method", without newline or semicolon, 578 * using "type_printer" to print argument and return types. 579 * 580 * Print the header of a declaration if this->declarations is set, 581 * otherwise print the header of a method definition. 582 * 583 * This function prints headers for member methods, static methods, and 584 * constructors, either for their declaration or definition. 585 * 586 * Member functions are declared as "const", as they do not change the current 587 * object, but instead create a new object. They always retrieve the first 588 * parameter of the original isl function from the this-pointer of the object, 589 * such that only starting at the second parameter the parameters of the 590 * original function become part of the method's interface. 591 * 592 * A function 593 * 594 * __isl_give isl_set *isl_set_intersect(__isl_take isl_set *s1, 595 * __isl_take isl_set *s2); 596 * 597 * is translated into: 598 * 599 * inline set intersect(set set2) const 600 * 601 * For static functions and constructors all parameters of the original isl 602 * function are exposed. 603 * 604 * Parameters of which no copy is required, are passed 605 * as const reference, which allows the compiler to optimize the parameter 606 * transfer. 607 * 608 * Constructors are marked as explicit using the C++ keyword 'explicit' or as 609 * implicit using a comment in place of the explicit keyword. By annotating 610 * implicit constructors with a comment, users of the interface are made 611 * aware of the potential danger that implicit construction is possible 612 * for these constructors, whereas without a comment not every user would 613 * know that implicit construction is allowed in absence of an explicit keyword. 614 * 615 * Note that in case "method" is a ConversionMethod, the argument returned 616 * by Method::get_param may be different from the original argument. 617 * The name of the argument is, however, derived from the original 618 * function argument. 619 */ 620 void cpp_generator::class_printer::print_method_header( 621 const Method &method, const cpp_type_printer &type_printer) 622 { 623 string rettype_str = type_printer.return_type(method); 624 625 if (declarations) { 626 os << " "; 627 628 if (method.kind == Method::Kind::static_method) 629 os << "static "; 630 631 os << "inline "; 632 633 if (method.kind == Method::Kind::constructor) { 634 if (generator.is_implicit_conversion(method)) 635 os << "/* implicit */ "; 636 else 637 os << "explicit "; 638 } 639 } 640 641 if (method.kind != Method::Kind::constructor) 642 os << rettype_str << " "; 643 644 if (!declarations) 645 os << type_printer.class_type(cppstring) << "::"; 646 647 if (method.kind != Method::Kind::constructor) 648 os << method.name; 649 else 650 os << cppstring; 651 652 method.print_cpp_arg_list(os, [&] (int i, int arg) { 653 std::string name = method.fd->getParamDecl(i)->getName().str(); 654 ParmVarDecl *param = method.get_param(i); 655 QualType type = param->getOriginalType(); 656 string cpptype = type_printer.param(arg, type); 657 658 if (!method.param_needs_copy(i)) 659 os << "const " << cpptype << " &" << name; 660 else 661 os << cpptype << " " << name; 662 }); 663 664 if (method.kind == Method::Kind::member_method) 665 os << " const"; 666 } 667 668 /* Generate the list of argument types for a callback function of 669 * type "type", appearing in argument position "arg". 670 * If "cpp" is set, then generate the C++ type list, otherwise 671 * the C type list. 672 * 673 * For a callback of type 674 * 675 * isl_stat (*)(__isl_take isl_map *map, void *user) 676 * 677 * the following C++ argument list is generated: 678 * 679 * map 680 * 681 * The arguments of the callback are considered to appear 682 * after the position of the callback itself. 683 */ 684 std::string cpp_type_printer::generate_callback_args(int arg, QualType type, 685 bool cpp) const 686 { 687 std::string type_str; 688 const FunctionProtoType *callback; 689 int num_params; 690 691 callback = generator::extract_prototype(type); 692 num_params = callback->getNumArgs(); 693 if (cpp) 694 num_params--; 695 696 for (long i = 0; i < num_params; i++) { 697 QualType type = callback->getArgType(i); 698 699 if (cpp) 700 type_str += param(arg + 1 + i, type); 701 else 702 type_str += type.getAsString(); 703 704 if (!cpp) 705 type_str += "arg_" + ::to_string(i); 706 707 if (i != num_params - 1) 708 type_str += ", "; 709 } 710 711 return type_str; 712 } 713 714 /* Generate the full cpp type of a callback function of type "type", 715 * appearing in argument position "arg". 716 * 717 * For a callback of type 718 * 719 * isl_stat (*)(__isl_take isl_map *map, void *user) 720 * 721 * the following type is generated: 722 * 723 * std::function<stat(map)> 724 */ 725 std::string cpp_type_printer::generate_callback_type(int arg, QualType type) 726 const 727 { 728 std::string type_str; 729 const FunctionProtoType *callback = generator::extract_prototype(type); 730 QualType return_type = callback->getReturnType(); 731 string rettype_str = param(arg, return_type); 732 733 type_str = "std::function<"; 734 type_str += rettype_str; 735 type_str += "("; 736 type_str += generate_callback_args(arg, type, true); 737 type_str += ")>"; 738 739 return type_str; 740 } 741 742 /* An array listing functions that must be renamed and the function name they 743 * should be renamed to. We currently rename functions in case their name would 744 * match a reserved C++ keyword, which is not allowed in C++. 745 */ 746 static const char *rename_map[][2] = { 747 { "union", "unite" }, 748 }; 749 750 /* Rename method "name" in case the method name in the C++ bindings should not 751 * match the name in the C bindings. We do this for example to avoid 752 * C++ keywords. 753 */ 754 static std::string rename_method(std::string name) 755 { 756 for (size_t i = 0; i < sizeof(rename_map) / sizeof(rename_map[0]); i++) 757 if (name.compare(rename_map[i][0]) == 0) 758 return rename_map[i][1]; 759 760 return name; 761 } 762 763 /* Translate isl class "clazz" to its corresponding C++ type. 764 * Use the name of the type based subclass, if any. 765 */ 766 string cpp_generator::type2cpp(const isl_class &clazz) 767 { 768 return type2cpp(clazz.subclass_name); 769 } 770 771 /* Translate type string "type_str" to its C++ name counterpart. 772 */ 773 string cpp_generator::type2cpp(string type_str) 774 { 775 return type_str.substr(4); 776 } 777 778 /* Return the C++ counterpart to the isl_bool type. 779 * 780 * By default, this is simply "bool" since 781 * the exceptional case is handled through exceptions. 782 */ 783 std::string cpp_type_printer::isl_bool() const 784 { 785 return "bool"; 786 } 787 788 /* Return the C++ counterpart to the isl_stat type. 789 * 790 * By default, this is simply "void" since 791 * the exceptional case is handled through exceptions. 792 */ 793 string cpp_type_printer::isl_stat() const 794 { 795 return "void"; 796 } 797 798 /* Return the C++ counterpart to the isl_size type. 799 * 800 * By default, this is simply "unsigned" since 801 * the exceptional case is handled through exceptions. 802 */ 803 string cpp_type_printer::isl_size() const 804 { 805 return "unsigned"; 806 } 807 808 /* Return the namespace of the generated C++ bindings. 809 * 810 * By default, this is "isl::". 811 */ 812 std::string cpp_type_printer::isl_namespace() const 813 { 814 return "isl::"; 815 } 816 817 /* Return the class type given the C++ name. 818 * 819 * By default, directly use the C++ name. 820 */ 821 std::string cpp_type_printer::class_type(const std::string &cpp_name) const 822 { 823 return cpp_name; 824 } 825 826 /* Return the qualified form of the given C++ isl type name appearing 827 * in argument position "arg" (-1 for return type). 828 * 829 * By default, the argument position is ignored. 830 */ 831 std::string cpp_type_printer::qualified(int arg, const std::string &cpp_type) 832 const 833 { 834 return isl_namespace() + cpp_type; 835 } 836 837 /* Return the C++ counterpart to the given isl type appearing 838 * in argument position "arg" (-1 for return type). 839 */ 840 std::string cpp_type_printer::isl_type(int arg, QualType type) const 841 { 842 auto name = type->getPointeeType().getAsString(); 843 return qualified(arg, cpp_generator::type2cpp(name)); 844 } 845 846 /* Translate parameter or return type "type" to its C++ name counterpart. 847 * "arg" is the position of the argument, or -1 in case of the return type. 848 * If any callback is involved, then the return type and arguments types 849 * of the callback are considered to start at the position of the callback. 850 */ 851 std::string cpp_type_printer::param(int arg, QualType type) const 852 { 853 if (cpp_generator::is_isl_type(type)) 854 return isl_type(arg, type); 855 856 if (cpp_generator::is_isl_bool(type)) 857 return isl_bool(); 858 859 if (cpp_generator::is_isl_stat(type)) 860 return isl_stat(); 861 862 if (cpp_generator::is_isl_size(type)) 863 return isl_size(); 864 865 if (type->isIntegerType()) 866 return type.getAsString(); 867 868 if (cpp_generator::is_string(type)) 869 return "std::string"; 870 871 if (cpp_generator::is_callback(type)) 872 return generate_callback_type(arg, type); 873 874 generator::die("Cannot convert type to C++ type"); 875 } 876 877 /* Check if "subclass_type" is a subclass of "class_type". 878 */ 879 bool cpp_generator::is_subclass(QualType subclass_type, 880 const isl_class &class_type) 881 { 882 std::string type_str = subclass_type->getPointeeType().getAsString(); 883 std::vector<std::string> superclasses; 884 std::vector<const isl_class *> parents; 885 std::vector<std::string>::iterator ci; 886 887 superclasses = generator::find_superclasses(classes[type_str].type); 888 889 for (ci = superclasses.begin(); ci < superclasses.end(); ci++) 890 parents.push_back(&classes[*ci]); 891 892 while (!parents.empty()) { 893 const isl_class *candidate = parents.back(); 894 895 parents.pop_back(); 896 897 if (&class_type == candidate) 898 return true; 899 900 superclasses = generator::find_superclasses(candidate->type); 901 902 for (ci = superclasses.begin(); ci < superclasses.end(); ci++) 903 parents.push_back(&classes[*ci]); 904 } 905 906 return false; 907 } 908 909 /* Check if "cons" is an implicit conversion constructor of class "clazz". 910 * 911 * An implicit conversion constructor is generated in case "cons" has a single 912 * parameter, where the parameter type is a subclass of the class that is 913 * currently being generated. 914 */ 915 bool cpp_generator::is_implicit_conversion(const Method &cons) 916 { 917 const auto &clazz = cons.clazz; 918 ParmVarDecl *param = cons.fd->getParamDecl(0); 919 QualType type = param->getOriginalType(); 920 921 int num_params = cons.fd->getNumParams(); 922 if (num_params != 1) 923 return false; 924 925 if (is_isl_type(type) && !is_isl_ctx(type) && is_subclass(type, clazz)) 926 return true; 927 928 return false; 929 } 930 931 /* Construct a list combiner for printing a list. 932 */ 933 Method::list_combiner Method::print_combiner(std::ostream &os) 934 { 935 return { 936 [&] () { os << "("; }, 937 [&] () { os << ", "; }, 938 [&] () { os << ")"; } 939 }; 940 } 941 942 /* Construct a list combiner for simply iterating over a list. 943 */ 944 Method::list_combiner Method::empty_combiner() 945 { 946 return { [&] () { }, [&] () { }, [&] () { } }; 947 } 948 949 /* Get kind of "method" in "clazz". 950 * 951 * Given the declaration of a static or member method, returns its kind. 952 */ 953 static Method::Kind get_kind(const isl_class &clazz, FunctionDecl *method) 954 { 955 if (generator::is_constructor(method)) 956 return Method::Kind::constructor; 957 else if (generator::is_static(clazz, method)) 958 return Method::Kind::static_method; 959 else 960 return Method::Kind::member_method; 961 } 962 963 /* Return the callback arguments of "fd". 964 */ 965 static std::vector<ParmVarDecl *> find_callback_args(FunctionDecl *fd) 966 { 967 std::vector<ParmVarDecl *> callbacks; 968 int num_params = fd->getNumParams(); 969 970 for (int i = 0; i < num_params; ++i) { 971 ParmVarDecl *param = fd->getParamDecl(i); 972 if (generator::is_callback(param->getType())) 973 callbacks.emplace_back(param); 974 } 975 976 return callbacks; 977 } 978 979 /* Construct a C++ method object from the class to which is belongs, 980 * the isl function from which it is derived and the method name. 981 * 982 * Perform any renaming of the method that may be required and 983 * determine the type of the method. 984 */ 985 Method::Method(const isl_class &clazz, FunctionDecl *fd, 986 const std::string &name) : 987 clazz(clazz), fd(fd), name(rename_method(name)), 988 kind(get_kind(clazz, fd)), 989 callbacks(find_callback_args(fd)) 990 { 991 } 992 993 /* Construct a C++ method object from the class to which is belongs and 994 * the isl function from which it is derived. 995 * 996 * Obtain the default method name and continue 997 * with the generic constructor. 998 */ 999 Method::Method(const isl_class &clazz, FunctionDecl *fd) : 1000 Method(clazz, fd, clazz.method_name(fd)) 1001 { 1002 } 1003 1004 /* Return the number of parameters of the corresponding C function. 1005 * 1006 * This number includes any possible user pointers that follow callback 1007 * arguments. These are skipped by Method::print_fd_arg_list 1008 * during the actual argument printing. 1009 */ 1010 int Method::c_num_params() const 1011 { 1012 return fd->getNumParams(); 1013 } 1014 1015 /* Return the number of parameters of the method 1016 * (including the implicit "this"). 1017 * 1018 * By default, it is the same as the number of parameters 1019 * of the corresponding C function. 1020 */ 1021 int Method::num_params() const 1022 { 1023 return c_num_params(); 1024 } 1025 1026 /* Call "on_arg_skip_next" on the arguments from "start" (inclusive) 1027 * to "end" (exclusive), calling the methods of "combiner" 1028 * before, between and after the arguments. 1029 * If "on_arg_skip_next" returns true then the next argument is skipped. 1030 */ 1031 void Method::on_arg_list(int start, int end, 1032 const Method::list_combiner &combiner, 1033 const std::function<bool(int i)> &on_arg_skip_next) 1034 { 1035 combiner.before(); 1036 for (int i = start; i < end; ++i) { 1037 if (i != start) 1038 combiner.between(); 1039 if (on_arg_skip_next(i)) 1040 ++i; 1041 } 1042 combiner.after(); 1043 } 1044 1045 /* Print the arguments from "start" (inclusive) to "end" (exclusive) 1046 * as arguments to a method of C function call, using "print_arg_skip_next" 1047 * to print each individual argument. If this callback return true 1048 * then the next argument is skipped. 1049 */ 1050 void Method::print_arg_list(std::ostream &os, int start, int end, 1051 const std::function<bool(int i)> &print_arg_skip_next) 1052 { 1053 on_arg_list(start, end, print_combiner(os), [&] (int i) { 1054 return print_arg_skip_next(i); 1055 }); 1056 } 1057 1058 /* Call "on_arg" on the arguments from "start" (inclusive) to "end" (exclusive), 1059 * calling the methods of "combiner" before, between and after the arguments. 1060 * The first argument to "on_arg" is the position of the argument 1061 * in this->fd. 1062 * The second argument is the (first) position in the list of arguments 1063 * with all callback arguments spliced in. 1064 * 1065 * Call on_arg_list to do the actual iteration over the arguments, skipping 1066 * the user argument that comes after every callback argument. 1067 * On the C++ side no user pointer is needed, as arguments can be forwarded 1068 * as part of the std::function argument which specifies the callback function. 1069 * The user pointer is also removed from the number of parameters 1070 * of the C function because the pair of callback and user pointer 1071 * is considered as a single argument that is printed as a whole 1072 * by Method::print_param_use. 1073 * 1074 * In case of a callback argument, the second argument to "print_arg" 1075 * is also adjusted to account for the spliced-in arguments of the callback. 1076 * The return value takes the place of the callback itself, 1077 * while the arguments (excluding the final user pointer) 1078 * take the following positions. 1079 */ 1080 void Method::on_fd_arg_list(int start, int end, 1081 const Method::list_combiner &combiner, 1082 const std::function<void(int i, int arg)> &on_arg) const 1083 { 1084 int arg = start; 1085 1086 on_arg_list(start, end, combiner, [this, &on_arg, &arg] (int i) { 1087 auto type = fd->getParamDecl(i)->getType(); 1088 1089 on_arg(i, arg++); 1090 if (!generator::is_callback(type)) 1091 return false; 1092 arg += generator::prototype_n_args(type) - 1; 1093 return true; 1094 }); 1095 } 1096 1097 /* Print the arguments from "start" (inclusive) to "end" (exclusive) 1098 * as arguments to a method of C function call, using "print_arg" 1099 * to print each individual argument. 1100 * The first argument to this callback is the position of the argument 1101 * in this->fd. 1102 * The second argument is the (first) position in the list of arguments 1103 * with all callback arguments spliced in. 1104 */ 1105 void Method::print_fd_arg_list(std::ostream &os, int start, int end, 1106 const std::function<void(int i, int arg)> &print_arg) const 1107 { 1108 on_fd_arg_list(start, end, print_combiner(os), print_arg); 1109 } 1110 1111 /* Call "on_arg" on the arguments to the method call, 1112 * calling the methods of "combiner" before, between and after the arguments. 1113 * The first argument to "on_arg" is the position of the argument 1114 * in this->fd. 1115 * The second argument is the (first) position in the list of arguments 1116 * with all callback arguments spliced in. 1117 */ 1118 void Method::on_cpp_arg_list(const Method::list_combiner &combiner, 1119 const std::function<void(int i, int arg)> &on_arg) const 1120 { 1121 int first_param = kind == member_method ? 1 : 0; 1122 on_fd_arg_list(first_param, num_params(), combiner, on_arg); 1123 } 1124 1125 /* Call "on_arg" on the arguments to the method call. 1126 * The first argument to "on_arg" is the position of the argument 1127 * in this->fd. 1128 * The second argument is the (first) position in the list of arguments 1129 * with all callback arguments spliced in. 1130 */ 1131 void Method::on_cpp_arg_list( 1132 const std::function<void(int i, int arg)> &on_arg) const 1133 { 1134 on_cpp_arg_list(empty_combiner(), on_arg); 1135 } 1136 1137 /* Print the arguments to the method call, using "print_arg" 1138 * to print each individual argument. 1139 * The first argument to this callback is the position of the argument 1140 * in this->fd. 1141 * The second argument is the (first) position in the list of arguments 1142 * with all callback arguments spliced in. 1143 */ 1144 void Method::print_cpp_arg_list(std::ostream &os, 1145 const std::function<void(int i, int arg)> &print_arg) const 1146 { 1147 on_cpp_arg_list(print_combiner(os), print_arg); 1148 } 1149 1150 /* Should the parameter at position "pos" be a copy (rather than 1151 * a const reference)? 1152 * 1153 * Strictly speaking, a copy is only needed on isl types that are 1154 * not marked __isl_keep, since those will be release()'d 1155 * by code printed by Method::print_param_use. 1156 * 1157 * However, there may be other arguments such as integer types 1158 * that are more naturally passed as a copy. 1159 * The default is therefore to require a copy, except for 1160 * arguments marked __isl_keep, string arguments or callback arguments. 1161 */ 1162 bool Method::param_needs_copy(int pos) const 1163 { 1164 ParmVarDecl *param = get_param(pos); 1165 QualType type = param->getOriginalType(); 1166 1167 if (generator::keeps(param)) 1168 return false; 1169 if (generator::is_string(type) || generator::is_callback(type)) 1170 return false; 1171 return true; 1172 } 1173 1174 /* Return the method argument at position "pos". 1175 */ 1176 clang::ParmVarDecl *Method::get_param(int pos) const 1177 { 1178 return fd->getParamDecl(pos); 1179 } 1180 1181 /* Construct a method that performs one or more conversions 1182 * from the original Method (without conversions), 1183 * the name of the type to which "this" should be converted and 1184 * a function for determining the arguments of the constructed method. 1185 */ 1186 ConversionMethod::ConversionMethod(const Method &method, 1187 const std::string &this_type, 1188 const std::function<clang::ParmVarDecl *(int pos)> &get_param) : 1189 NoCopyMethod(method), this_type(this_type), 1190 get_param_fn(get_param) 1191 { 1192 } 1193 1194 /* Construct a method that only performs a conversion on "this" 1195 * from the original Method (without conversions) and 1196 * the name of the type to which "this" should be converted. 1197 * 1198 * Call the generic constructor with 1199 * a function for determining the arguments of the constructed method 1200 * that performs no conversion. 1201 */ 1202 ConversionMethod::ConversionMethod(const Method &method, 1203 const std::string &this_type) : 1204 ConversionMethod(method, this_type, [this] (int pos) { 1205 return Method::get_param(pos); 1206 }) 1207 { 1208 } 1209 1210 /* Construct a method that performs one or more argument conversions 1211 * from the original Method (without conversions) and 1212 * a function for determining the arguments of the constructed method. 1213 * 1214 * Call the generic constructor with method.clazz.name as "this" type, 1215 * indicating that "this" should not be converted. 1216 */ 1217 ConversionMethod::ConversionMethod(const Method &method, 1218 const std::function<clang::ParmVarDecl *(int pos)> &get_param) : 1219 ConversionMethod(method, method.clazz.name, get_param) 1220 { 1221 } 1222 1223 /* Should the parameter at position "pos" be a copy (rather than 1224 * a const reference)? 1225 * 1226 * Parameters of isl type do not need to be a copy. 1227 * For other types, use the same defaults as Method. 1228 */ 1229 bool NoCopyMethod::param_needs_copy(int pos) const 1230 { 1231 ParmVarDecl *param = get_param(pos); 1232 QualType type = param->getOriginalType(); 1233 1234 if (generator::is_isl_type(type)) 1235 return false; 1236 1237 return Method::param_needs_copy(pos); 1238 } 1239 1240 /* Return the method argument at position "pos". 1241 * 1242 * Call get_param_fn to determine this argument. 1243 */ 1244 clang::ParmVarDecl *ConversionMethod::get_param(int pos) const 1245 { 1246 return get_param_fn(pos); 1247 } 1248 1249 /* Print a call to the method (without the arguments), 1250 * with "ns" the namespace of the generated C++ bindings. 1251 * 1252 * If "this_type" is different from the name of the class of the method, 1253 * then "this" needs to be converted to that type before 1254 * the call is performed. 1255 */ 1256 void ConversionMethod::print_call(std::ostream &os, const std::string &ns) const 1257 { 1258 if (clazz.name == this_type) { 1259 os << "this->"; 1260 } else { 1261 auto cpp_type = ns + cpp_generator::type2cpp(this_type); 1262 os << cpp_type << "(*this)."; 1263 } 1264 os << name; 1265 } 1266 1267 /* Construct an object representing a C++ method for setting an enum 1268 * from the class to which is belongs, 1269 * the isl function from which it is derived and the method and enum names. 1270 */ 1271 EnumMethod::EnumMethod(const isl_class &clazz, FunctionDecl *fd, 1272 const std::string &method_name, const std::string &enum_name) : 1273 Method(clazz, fd, method_name), enum_name(enum_name) 1274 { 1275 } 1276 1277 /* Print the use of the argument at position "pos" to "os". 1278 * 1279 * If the position is beyond the number of method arguments, 1280 * then it corresponds to the enum value corresponding to this EnumMethod. 1281 * Otherwise, delegate to Method::print_param_use. 1282 */ 1283 void EnumMethod::print_param_use(ostream &os, int pos) const 1284 { 1285 if (pos == num_params()) 1286 os << enum_name; 1287 else 1288 Method::print_param_use(os, pos); 1289 } 1290 1291 /* Return the number of parameters of the method 1292 * (including the implicit "this"). 1293 * 1294 * The last argument of the C function does not appear in the method call, 1295 * because it is replaced by a break-up into several methods. 1296 */ 1297 int EnumMethod::num_params() const 1298 { 1299 return Method::num_params() - 1; 1300 } 1301 1302 /* Initialize a class method printer from the stream onto which the methods 1303 * are printed, the class method description and the C++ interface generator. 1304 */ 1305 cpp_generator::class_printer::class_printer(std::ostream &os, 1306 const isl_class &clazz, cpp_generator &generator, 1307 bool declarations) : 1308 os(os), clazz(clazz), cppstring(type2cpp(clazz)), generator(generator), 1309 declarations(declarations) 1310 { 1311 } 1312