1 //===- LLVMCConfigurationEmitter.cpp - Generate LLVMC config ----*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open 6 // Source License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // This tablegen backend is responsible for emitting LLVMC configuration code. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "LLVMCConfigurationEmitter.h" 15 #include "Record.h" 16 17 #include "llvm/ADT/IntrusiveRefCntPtr.h" 18 #include "llvm/ADT/StringMap.h" 19 #include "llvm/ADT/StringSet.h" 20 21 #include <algorithm> 22 #include <cassert> 23 #include <functional> 24 #include <stdexcept> 25 #include <string> 26 #include <typeinfo> 27 28 29 using namespace llvm; 30 31 namespace { 32 33 //===----------------------------------------------------------------------===// 34 /// Typedefs 35 36 typedef std::vector<Record*> RecordVector; 37 typedef std::vector<const DagInit*> DagVector; 38 typedef std::vector<std::string> StrVector; 39 40 //===----------------------------------------------------------------------===// 41 /// Constants 42 43 // Indentation. 44 const unsigned TabWidth = 4; 45 const unsigned Indent1 = TabWidth*1; 46 const unsigned Indent2 = TabWidth*2; 47 const unsigned Indent3 = TabWidth*3; 48 const unsigned Indent4 = TabWidth*4; 49 50 // Default help string. 51 const char * const DefaultHelpString = "NO HELP MESSAGE PROVIDED"; 52 53 // Name for the "sink" option. 54 const char * const SinkOptionName = "SinkOption"; 55 56 //===----------------------------------------------------------------------===// 57 /// Helper functions 58 59 /// Id - An 'identity' function object. 60 struct Id { 61 template<typename T0> 62 void operator()(const T0&) const { 63 } 64 template<typename T0, typename T1> 65 void operator()(const T0&, const T1&) const { 66 } 67 template<typename T0, typename T1, typename T2> 68 void operator()(const T0&, const T1&, const T2&) const { 69 } 70 }; 71 72 int InitPtrToInt(const Init* ptr) { 73 const IntInit& val = dynamic_cast<const IntInit&>(*ptr); 74 return val.getValue(); 75 } 76 77 bool InitPtrToBool(const Init* ptr) { 78 bool ret = false; 79 const DefInit& val = dynamic_cast<const DefInit&>(*ptr); 80 const std::string& str = val.getAsString(); 81 82 if (str == "true") { 83 ret = true; 84 } 85 else if (str == "false") { 86 ret = false; 87 } 88 else { 89 throw "Incorrect boolean value: '" + str + 90 "': must be either 'true' or 'false'"; 91 } 92 93 return ret; 94 } 95 96 const std::string& InitPtrToString(const Init* ptr) { 97 const StringInit& val = dynamic_cast<const StringInit&>(*ptr); 98 return val.getValue(); 99 } 100 101 const ListInit& InitPtrToList(const Init* ptr) { 102 const ListInit& val = dynamic_cast<const ListInit&>(*ptr); 103 return val; 104 } 105 106 const DagInit& InitPtrToDag(const Init* ptr) { 107 const DagInit& val = dynamic_cast<const DagInit&>(*ptr); 108 return val; 109 } 110 111 const std::string GetOperatorName(const DagInit& D) { 112 return D.getOperator()->getAsString(); 113 } 114 115 /// CheckBooleanConstant - Check that the provided value is a boolean constant. 116 void CheckBooleanConstant(const Init* I) { 117 InitPtrToBool(I); 118 } 119 120 // CheckNumberOfArguments - Ensure that the number of args in d is 121 // greater than or equal to min_arguments, otherwise throw an exception. 122 void CheckNumberOfArguments (const DagInit& d, unsigned minArgs) { 123 if (d.getNumArgs() < minArgs) 124 throw GetOperatorName(d) + ": too few arguments!"; 125 } 126 127 // EscapeVariableName - Escape commas and other symbols not allowed 128 // in the C++ variable names. Makes it possible to use options named 129 // like "Wa," (useful for prefix options). 130 std::string EscapeVariableName (const std::string& Var) { 131 std::string ret; 132 for (unsigned i = 0; i != Var.size(); ++i) { 133 char cur_char = Var[i]; 134 if (cur_char == ',') { 135 ret += "_comma_"; 136 } 137 else if (cur_char == '+') { 138 ret += "_plus_"; 139 } 140 else if (cur_char == '-') { 141 ret += "_dash_"; 142 } 143 else { 144 ret.push_back(cur_char); 145 } 146 } 147 return ret; 148 } 149 150 /// EscapeQuotes - Replace '"' with '\"'. 151 std::string EscapeQuotes (const std::string& Var) { 152 std::string ret; 153 for (unsigned i = 0; i != Var.size(); ++i) { 154 char cur_char = Var[i]; 155 if (cur_char == '"') { 156 ret += "\\\""; 157 } 158 else { 159 ret.push_back(cur_char); 160 } 161 } 162 return ret; 163 } 164 165 /// OneOf - Does the input string contain this character? 166 bool OneOf(const char* lst, char c) { 167 while (*lst) { 168 if (*lst++ == c) 169 return true; 170 } 171 return false; 172 } 173 174 template <class I, class S> 175 void CheckedIncrement(I& P, I E, S ErrorString) { 176 ++P; 177 if (P == E) 178 throw ErrorString; 179 } 180 181 //===----------------------------------------------------------------------===// 182 /// Back-end specific code 183 184 185 /// OptionType - One of six different option types. See the 186 /// documentation for detailed description of differences. 187 namespace OptionType { 188 189 enum OptionType { Alias, Switch, SwitchList, 190 Parameter, ParameterList, Prefix, PrefixList }; 191 192 bool IsAlias(OptionType t) { 193 return (t == Alias); 194 } 195 196 bool IsList (OptionType t) { 197 return (t == SwitchList || t == ParameterList || t == PrefixList); 198 } 199 200 bool IsSwitch (OptionType t) { 201 return (t == Switch); 202 } 203 204 bool IsSwitchList (OptionType t) { 205 return (t == SwitchList); 206 } 207 208 bool IsParameter (OptionType t) { 209 return (t == Parameter || t == Prefix); 210 } 211 212 } 213 214 OptionType::OptionType stringToOptionType(const std::string& T) { 215 if (T == "alias_option") 216 return OptionType::Alias; 217 else if (T == "switch_option") 218 return OptionType::Switch; 219 else if (T == "switch_list_option") 220 return OptionType::SwitchList; 221 else if (T == "parameter_option") 222 return OptionType::Parameter; 223 else if (T == "parameter_list_option") 224 return OptionType::ParameterList; 225 else if (T == "prefix_option") 226 return OptionType::Prefix; 227 else if (T == "prefix_list_option") 228 return OptionType::PrefixList; 229 else 230 throw "Unknown option type: " + T + '!'; 231 } 232 233 namespace OptionDescriptionFlags { 234 enum OptionDescriptionFlags { Required = 0x1, Hidden = 0x2, 235 ReallyHidden = 0x4, OneOrMore = 0x8, 236 Optional = 0x10, CommaSeparated = 0x20, 237 ForwardNotSplit = 0x40, ZeroOrMore = 0x80 }; 238 } 239 240 /// OptionDescription - Represents data contained in a single 241 /// OptionList entry. 242 struct OptionDescription { 243 OptionType::OptionType Type; 244 std::string Name; 245 unsigned Flags; 246 std::string Help; 247 unsigned MultiVal; 248 Init* InitVal; 249 250 OptionDescription(OptionType::OptionType t = OptionType::Switch, 251 const std::string& n = "", 252 const std::string& h = DefaultHelpString) 253 : Type(t), Name(n), Flags(0x0), Help(h), MultiVal(1), InitVal(0) 254 {} 255 256 /// GenTypeDeclaration - Returns the C++ variable type of this 257 /// option. 258 const char* GenTypeDeclaration() const; 259 260 /// GenVariableName - Returns the variable name used in the 261 /// generated C++ code. 262 std::string GenVariableName() const 263 { return "autogenerated::" + GenOptionType() + EscapeVariableName(Name); } 264 265 /// GenPlainVariableName - Returns the variable name without the namespace 266 /// prefix. 267 std::string GenPlainVariableName() const 268 { return GenOptionType() + EscapeVariableName(Name); } 269 270 /// Merge - Merge two option descriptions. 271 void Merge (const OptionDescription& other); 272 273 /// CheckConsistency - Check that the flags are consistent. 274 void CheckConsistency() const; 275 276 // Misc convenient getters/setters. 277 278 bool isAlias() const; 279 280 bool isMultiVal() const; 281 282 bool isCommaSeparated() const; 283 void setCommaSeparated(); 284 285 bool isForwardNotSplit() const; 286 void setForwardNotSplit(); 287 288 bool isRequired() const; 289 void setRequired(); 290 291 bool isOneOrMore() const; 292 void setOneOrMore(); 293 294 bool isZeroOrMore() const; 295 void setZeroOrMore(); 296 297 bool isOptional() const; 298 void setOptional(); 299 300 bool isHidden() const; 301 void setHidden(); 302 303 bool isReallyHidden() const; 304 void setReallyHidden(); 305 306 bool isSwitch() const 307 { return OptionType::IsSwitch(this->Type); } 308 309 bool isSwitchList() const 310 { return OptionType::IsSwitchList(this->Type); } 311 312 bool isParameter() const 313 { return OptionType::IsParameter(this->Type); } 314 315 bool isList() const 316 { return OptionType::IsList(this->Type); } 317 318 bool isParameterList() const 319 { return (OptionType::IsList(this->Type) 320 && !OptionType::IsSwitchList(this->Type)); } 321 322 private: 323 324 // GenOptionType - Helper function used by GenVariableName(). 325 std::string GenOptionType() const; 326 }; 327 328 void OptionDescription::CheckConsistency() const { 329 unsigned i = 0; 330 331 i += this->isRequired(); 332 i += this->isOptional(); 333 i += this->isOneOrMore(); 334 i += this->isZeroOrMore(); 335 336 if (i > 1) { 337 throw "Only one of (required), (optional), (one_or_more) or " 338 "(zero_or_more) properties is allowed!"; 339 } 340 } 341 342 void OptionDescription::Merge (const OptionDescription& other) 343 { 344 if (other.Type != Type) 345 throw "Conflicting definitions for the option " + Name + "!"; 346 347 if (Help == other.Help || Help == DefaultHelpString) 348 Help = other.Help; 349 else if (other.Help != DefaultHelpString) { 350 llvm::errs() << "Warning: several different help strings" 351 " defined for option " + Name + "\n"; 352 } 353 354 Flags |= other.Flags; 355 } 356 357 bool OptionDescription::isAlias() const { 358 return OptionType::IsAlias(this->Type); 359 } 360 361 bool OptionDescription::isMultiVal() const { 362 return MultiVal > 1; 363 } 364 365 bool OptionDescription::isCommaSeparated() const { 366 return Flags & OptionDescriptionFlags::CommaSeparated; 367 } 368 void OptionDescription::setCommaSeparated() { 369 Flags |= OptionDescriptionFlags::CommaSeparated; 370 } 371 372 bool OptionDescription::isForwardNotSplit() const { 373 return Flags & OptionDescriptionFlags::ForwardNotSplit; 374 } 375 void OptionDescription::setForwardNotSplit() { 376 Flags |= OptionDescriptionFlags::ForwardNotSplit; 377 } 378 379 bool OptionDescription::isRequired() const { 380 return Flags & OptionDescriptionFlags::Required; 381 } 382 void OptionDescription::setRequired() { 383 Flags |= OptionDescriptionFlags::Required; 384 } 385 386 bool OptionDescription::isOneOrMore() const { 387 return Flags & OptionDescriptionFlags::OneOrMore; 388 } 389 void OptionDescription::setOneOrMore() { 390 Flags |= OptionDescriptionFlags::OneOrMore; 391 } 392 393 bool OptionDescription::isZeroOrMore() const { 394 return Flags & OptionDescriptionFlags::ZeroOrMore; 395 } 396 void OptionDescription::setZeroOrMore() { 397 Flags |= OptionDescriptionFlags::ZeroOrMore; 398 } 399 400 bool OptionDescription::isOptional() const { 401 return Flags & OptionDescriptionFlags::Optional; 402 } 403 void OptionDescription::setOptional() { 404 Flags |= OptionDescriptionFlags::Optional; 405 } 406 407 bool OptionDescription::isHidden() const { 408 return Flags & OptionDescriptionFlags::Hidden; 409 } 410 void OptionDescription::setHidden() { 411 Flags |= OptionDescriptionFlags::Hidden; 412 } 413 414 bool OptionDescription::isReallyHidden() const { 415 return Flags & OptionDescriptionFlags::ReallyHidden; 416 } 417 void OptionDescription::setReallyHidden() { 418 Flags |= OptionDescriptionFlags::ReallyHidden; 419 } 420 421 const char* OptionDescription::GenTypeDeclaration() const { 422 switch (Type) { 423 case OptionType::Alias: 424 return "cl::alias"; 425 case OptionType::PrefixList: 426 case OptionType::ParameterList: 427 return "cl::list<std::string>"; 428 case OptionType::Switch: 429 return "cl::opt<bool>"; 430 case OptionType::SwitchList: 431 return "cl::list<bool>"; 432 case OptionType::Parameter: 433 case OptionType::Prefix: 434 default: 435 return "cl::opt<std::string>"; 436 } 437 } 438 439 std::string OptionDescription::GenOptionType() const { 440 switch (Type) { 441 case OptionType::Alias: 442 return "Alias_"; 443 case OptionType::PrefixList: 444 case OptionType::ParameterList: 445 return "List_"; 446 case OptionType::Switch: 447 return "Switch_"; 448 case OptionType::SwitchList: 449 return "SwitchList_"; 450 case OptionType::Prefix: 451 case OptionType::Parameter: 452 default: 453 return "Parameter_"; 454 } 455 } 456 457 /// OptionDescriptions - An OptionDescription array plus some helper 458 /// functions. 459 class OptionDescriptions { 460 typedef StringMap<OptionDescription> container_type; 461 462 /// Descriptions - A list of OptionDescriptions. 463 container_type Descriptions; 464 465 public: 466 /// FindOption - exception-throwing wrapper for find(). 467 const OptionDescription& FindOption(const std::string& OptName) const; 468 469 // Wrappers for FindOption that throw an exception in case the option has a 470 // wrong type. 471 const OptionDescription& FindSwitch(const std::string& OptName) const; 472 const OptionDescription& FindParameter(const std::string& OptName) const; 473 const OptionDescription& FindParameterList(const std::string& OptName) const; 474 const OptionDescription& 475 FindListOrParameter(const std::string& OptName) const; 476 const OptionDescription& 477 FindParameterListOrParameter(const std::string& OptName) const; 478 479 /// insertDescription - Insert new OptionDescription into 480 /// OptionDescriptions list 481 void InsertDescription (const OptionDescription& o); 482 483 // Support for STL-style iteration 484 typedef container_type::const_iterator const_iterator; 485 const_iterator begin() const { return Descriptions.begin(); } 486 const_iterator end() const { return Descriptions.end(); } 487 }; 488 489 const OptionDescription& 490 OptionDescriptions::FindOption(const std::string& OptName) const { 491 const_iterator I = Descriptions.find(OptName); 492 if (I != Descriptions.end()) 493 return I->second; 494 else 495 throw OptName + ": no such option!"; 496 } 497 498 const OptionDescription& 499 OptionDescriptions::FindSwitch(const std::string& OptName) const { 500 const OptionDescription& OptDesc = this->FindOption(OptName); 501 if (!OptDesc.isSwitch()) 502 throw OptName + ": incorrect option type - should be a switch!"; 503 return OptDesc; 504 } 505 506 const OptionDescription& 507 OptionDescriptions::FindParameterList(const std::string& OptName) const { 508 const OptionDescription& OptDesc = this->FindOption(OptName); 509 if (!OptDesc.isList() || OptDesc.isSwitchList()) 510 throw OptName + ": incorrect option type - should be a parameter list!"; 511 return OptDesc; 512 } 513 514 const OptionDescription& 515 OptionDescriptions::FindParameter(const std::string& OptName) const { 516 const OptionDescription& OptDesc = this->FindOption(OptName); 517 if (!OptDesc.isParameter()) 518 throw OptName + ": incorrect option type - should be a parameter!"; 519 return OptDesc; 520 } 521 522 const OptionDescription& 523 OptionDescriptions::FindListOrParameter(const std::string& OptName) const { 524 const OptionDescription& OptDesc = this->FindOption(OptName); 525 if (!OptDesc.isList() && !OptDesc.isParameter()) 526 throw OptName 527 + ": incorrect option type - should be a list or parameter!"; 528 return OptDesc; 529 } 530 531 const OptionDescription& 532 OptionDescriptions::FindParameterListOrParameter 533 (const std::string& OptName) const { 534 const OptionDescription& OptDesc = this->FindOption(OptName); 535 if ((!OptDesc.isList() && !OptDesc.isParameter()) || OptDesc.isSwitchList()) 536 throw OptName 537 + ": incorrect option type - should be a parameter list or parameter!"; 538 return OptDesc; 539 } 540 541 void OptionDescriptions::InsertDescription (const OptionDescription& o) { 542 container_type::iterator I = Descriptions.find(o.Name); 543 if (I != Descriptions.end()) { 544 OptionDescription& D = I->second; 545 D.Merge(o); 546 } 547 else { 548 Descriptions[o.Name] = o; 549 } 550 } 551 552 /// HandlerTable - A base class for function objects implemented as 553 /// 'tables of handlers'. 554 template <typename Handler> 555 class HandlerTable { 556 protected: 557 // Implementation details. 558 559 /// HandlerMap - A map from property names to property handlers 560 typedef StringMap<Handler> HandlerMap; 561 562 static HandlerMap Handlers_; 563 static bool staticMembersInitialized_; 564 565 public: 566 567 Handler GetHandler (const std::string& HandlerName) const { 568 typename HandlerMap::iterator method = Handlers_.find(HandlerName); 569 570 if (method != Handlers_.end()) { 571 Handler h = method->second; 572 return h; 573 } 574 else { 575 throw "No handler found for property " + HandlerName + "!"; 576 } 577 } 578 579 void AddHandler(const char* Property, Handler H) { 580 Handlers_[Property] = H; 581 } 582 583 }; 584 585 template <class Handler, class FunctionObject> 586 Handler GetHandler(FunctionObject* Obj, const DagInit& Dag) { 587 const std::string& HandlerName = GetOperatorName(Dag); 588 return Obj->GetHandler(HandlerName); 589 } 590 591 template <class FunctionObject> 592 void InvokeDagInitHandler(FunctionObject* Obj, Init* I) { 593 typedef void (FunctionObject::*Handler) (const DagInit&); 594 595 const DagInit& Dag = InitPtrToDag(I); 596 Handler h = GetHandler<Handler>(Obj, Dag); 597 598 ((Obj)->*(h))(Dag); 599 } 600 601 template <class FunctionObject> 602 void InvokeDagInitHandler(const FunctionObject* const Obj, 603 const Init* I, unsigned IndentLevel, raw_ostream& O) 604 { 605 typedef void (FunctionObject::*Handler) 606 (const DagInit&, unsigned IndentLevel, raw_ostream& O) const; 607 608 const DagInit& Dag = InitPtrToDag(I); 609 Handler h = GetHandler<Handler>(Obj, Dag); 610 611 ((Obj)->*(h))(Dag, IndentLevel, O); 612 } 613 614 template <typename H> 615 typename HandlerTable<H>::HandlerMap HandlerTable<H>::Handlers_; 616 617 template <typename H> 618 bool HandlerTable<H>::staticMembersInitialized_ = false; 619 620 621 /// CollectOptionProperties - Function object for iterating over an 622 /// option property list. 623 class CollectOptionProperties; 624 typedef void (CollectOptionProperties::* CollectOptionPropertiesHandler) 625 (const DagInit&); 626 627 class CollectOptionProperties 628 : public HandlerTable<CollectOptionPropertiesHandler> 629 { 630 private: 631 632 /// optDescs_ - OptionDescriptions table. This is where the 633 /// information is stored. 634 OptionDescription& optDesc_; 635 636 public: 637 638 explicit CollectOptionProperties(OptionDescription& OD) 639 : optDesc_(OD) 640 { 641 if (!staticMembersInitialized_) { 642 AddHandler("help", &CollectOptionProperties::onHelp); 643 AddHandler("hidden", &CollectOptionProperties::onHidden); 644 AddHandler("init", &CollectOptionProperties::onInit); 645 AddHandler("multi_val", &CollectOptionProperties::onMultiVal); 646 AddHandler("one_or_more", &CollectOptionProperties::onOneOrMore); 647 AddHandler("zero_or_more", &CollectOptionProperties::onZeroOrMore); 648 AddHandler("really_hidden", &CollectOptionProperties::onReallyHidden); 649 AddHandler("required", &CollectOptionProperties::onRequired); 650 AddHandler("optional", &CollectOptionProperties::onOptional); 651 AddHandler("comma_separated", &CollectOptionProperties::onCommaSeparated); 652 AddHandler("forward_not_split", 653 &CollectOptionProperties::onForwardNotSplit); 654 655 staticMembersInitialized_ = true; 656 } 657 } 658 659 /// operator() - Just forwards to the corresponding property 660 /// handler. 661 void operator() (Init* I) { 662 InvokeDagInitHandler(this, I); 663 } 664 665 private: 666 667 /// Option property handlers -- 668 /// Methods that handle option properties such as (help) or (hidden). 669 670 void onHelp (const DagInit& d) { 671 CheckNumberOfArguments(d, 1); 672 optDesc_.Help = EscapeQuotes(InitPtrToString(d.getArg(0))); 673 } 674 675 void onHidden (const DagInit& d) { 676 CheckNumberOfArguments(d, 0); 677 optDesc_.setHidden(); 678 } 679 680 void onReallyHidden (const DagInit& d) { 681 CheckNumberOfArguments(d, 0); 682 optDesc_.setReallyHidden(); 683 } 684 685 void onCommaSeparated (const DagInit& d) { 686 CheckNumberOfArguments(d, 0); 687 if (!optDesc_.isParameterList()) 688 throw "'comma_separated' is valid only on parameter list options!"; 689 optDesc_.setCommaSeparated(); 690 } 691 692 void onForwardNotSplit (const DagInit& d) { 693 CheckNumberOfArguments(d, 0); 694 if (!optDesc_.isParameter()) 695 throw "'forward_not_split' is valid only for parameter options!"; 696 optDesc_.setForwardNotSplit(); 697 } 698 699 void onRequired (const DagInit& d) { 700 CheckNumberOfArguments(d, 0); 701 702 optDesc_.setRequired(); 703 optDesc_.CheckConsistency(); 704 } 705 706 void onInit (const DagInit& d) { 707 CheckNumberOfArguments(d, 1); 708 Init* i = d.getArg(0); 709 const std::string& str = i->getAsString(); 710 711 bool correct = optDesc_.isParameter() && dynamic_cast<StringInit*>(i); 712 correct |= (optDesc_.isSwitch() && (str == "true" || str == "false")); 713 714 if (!correct) 715 throw "Incorrect usage of the 'init' option property!"; 716 717 optDesc_.InitVal = i; 718 } 719 720 void onOneOrMore (const DagInit& d) { 721 CheckNumberOfArguments(d, 0); 722 723 optDesc_.setOneOrMore(); 724 optDesc_.CheckConsistency(); 725 } 726 727 void onZeroOrMore (const DagInit& d) { 728 CheckNumberOfArguments(d, 0); 729 730 if (optDesc_.isList()) 731 llvm::errs() << "Warning: specifying the 'zero_or_more' property " 732 "on a list option has no effect.\n"; 733 734 optDesc_.setZeroOrMore(); 735 optDesc_.CheckConsistency(); 736 } 737 738 void onOptional (const DagInit& d) { 739 CheckNumberOfArguments(d, 0); 740 741 if (!optDesc_.isList()) 742 llvm::errs() << "Warning: specifying the 'optional' property" 743 "on a non-list option has no effect.\n"; 744 745 optDesc_.setOptional(); 746 optDesc_.CheckConsistency(); 747 } 748 749 void onMultiVal (const DagInit& d) { 750 CheckNumberOfArguments(d, 1); 751 int val = InitPtrToInt(d.getArg(0)); 752 if (val < 2) 753 throw "Error in the 'multi_val' property: " 754 "the value must be greater than 1!"; 755 if (!optDesc_.isParameterList()) 756 throw "The multi_val property is valid only on list options!"; 757 optDesc_.MultiVal = val; 758 } 759 760 }; 761 762 /// AddOption - A function object that is applied to every option 763 /// description. Used by CollectOptionDescriptions. 764 class AddOption { 765 private: 766 OptionDescriptions& OptDescs_; 767 768 public: 769 explicit AddOption(OptionDescriptions& OD) : OptDescs_(OD) 770 {} 771 772 void operator()(const Init* i) { 773 const DagInit& d = InitPtrToDag(i); 774 CheckNumberOfArguments(d, 1); 775 776 const OptionType::OptionType Type = 777 stringToOptionType(GetOperatorName(d)); 778 const std::string& Name = InitPtrToString(d.getArg(0)); 779 780 OptionDescription OD(Type, Name); 781 782 CheckNumberOfArguments(d, 2); 783 784 // Alias option store the aliased option name in the 'Help' field and do not 785 // have any properties. 786 if (OD.isAlias()) { 787 OD.Help = InitPtrToString(d.getArg(1)); 788 } 789 else { 790 processOptionProperties(d, OD); 791 } 792 793 // Switch options are ZeroOrMore by default. 794 if (OD.isSwitch()) { 795 if (!(OD.isOptional() || OD.isOneOrMore() || OD.isRequired())) 796 OD.setZeroOrMore(); 797 } 798 799 OptDescs_.InsertDescription(OD); 800 } 801 802 private: 803 /// processOptionProperties - Go through the list of option 804 /// properties and call a corresponding handler for each. 805 static void processOptionProperties (const DagInit& d, OptionDescription& o) { 806 CheckNumberOfArguments(d, 2); 807 DagInit::const_arg_iterator B = d.arg_begin(); 808 // Skip the first argument: it's always the option name. 809 ++B; 810 std::for_each(B, d.arg_end(), CollectOptionProperties(o)); 811 } 812 813 }; 814 815 /// CollectOptionDescriptions - Collects option properties from all 816 /// OptionLists. 817 void CollectOptionDescriptions (const RecordVector& V, 818 OptionDescriptions& OptDescs) 819 { 820 // For every OptionList: 821 for (RecordVector::const_iterator B = V.begin(), E = V.end(); B!=E; ++B) 822 { 823 // Throws an exception if the value does not exist. 824 ListInit* PropList = (*B)->getValueAsListInit("options"); 825 826 // For every option description in this list: invoke AddOption. 827 std::for_each(PropList->begin(), PropList->end(), AddOption(OptDescs)); 828 } 829 } 830 831 // Tool information record 832 833 namespace ToolFlags { 834 enum ToolFlags { Join = 0x1, Sink = 0x2 }; 835 } 836 837 struct ToolDescription : public RefCountedBase<ToolDescription> { 838 std::string Name; 839 Init* CmdLine; 840 Init* Actions; 841 StrVector InLanguage; 842 std::string InFileOption; 843 std::string OutFileOption; 844 StrVector OutLanguage; 845 std::string OutputSuffix; 846 unsigned Flags; 847 const Init* OnEmpty; 848 849 // Various boolean properties 850 void setSink() { Flags |= ToolFlags::Sink; } 851 bool isSink() const { return Flags & ToolFlags::Sink; } 852 void setJoin() { Flags |= ToolFlags::Join; } 853 bool isJoin() const { return Flags & ToolFlags::Join; } 854 855 // Default ctor here is needed because StringMap can only store 856 // DefaultConstructible objects 857 ToolDescription (const std::string &n = "") 858 : Name(n), CmdLine(0), Actions(0), OutFileOption("-o"), 859 Flags(0), OnEmpty(0) 860 {} 861 }; 862 863 /// ToolDescriptions - A list of Tool information records. 864 typedef std::vector<IntrusiveRefCntPtr<ToolDescription> > ToolDescriptions; 865 866 867 /// CollectToolProperties - Function object for iterating over a list of 868 /// tool property records. 869 870 class CollectToolProperties; 871 typedef void (CollectToolProperties::* CollectToolPropertiesHandler) 872 (const DagInit&); 873 874 class CollectToolProperties : public HandlerTable<CollectToolPropertiesHandler> 875 { 876 private: 877 878 /// toolDesc_ - Properties of the current Tool. This is where the 879 /// information is stored. 880 ToolDescription& toolDesc_; 881 882 public: 883 884 explicit CollectToolProperties (ToolDescription& d) 885 : toolDesc_(d) 886 { 887 if (!staticMembersInitialized_) { 888 889 AddHandler("actions", &CollectToolProperties::onActions); 890 AddHandler("command", &CollectToolProperties::onCommand); 891 AddHandler("in_language", &CollectToolProperties::onInLanguage); 892 AddHandler("join", &CollectToolProperties::onJoin); 893 AddHandler("out_language", &CollectToolProperties::onOutLanguage); 894 895 AddHandler("out_file_option", &CollectToolProperties::onOutFileOption); 896 AddHandler("in_file_option", &CollectToolProperties::onInFileOption); 897 898 AddHandler("output_suffix", &CollectToolProperties::onOutputSuffix); 899 AddHandler("sink", &CollectToolProperties::onSink); 900 AddHandler("works_on_empty", &CollectToolProperties::onWorksOnEmpty); 901 902 staticMembersInitialized_ = true; 903 } 904 } 905 906 void operator() (Init* I) { 907 InvokeDagInitHandler(this, I); 908 } 909 910 private: 911 912 /// Property handlers -- 913 /// Functions that extract information about tool properties from 914 /// DAG representation. 915 916 void onActions (const DagInit& d) { 917 CheckNumberOfArguments(d, 1); 918 Init* Case = d.getArg(0); 919 if (typeid(*Case) != typeid(DagInit) || 920 GetOperatorName(static_cast<DagInit&>(*Case)) != "case") 921 throw "The argument to (actions) should be a 'case' construct!"; 922 toolDesc_.Actions = Case; 923 } 924 925 void onCommand (const DagInit& d) { 926 CheckNumberOfArguments(d, 1); 927 toolDesc_.CmdLine = d.getArg(0); 928 } 929 930 /// onInOutLanguage - Common implementation of on{In,Out}Language(). 931 void onInOutLanguage (const DagInit& d, StrVector& OutVec) { 932 CheckNumberOfArguments(d, 1); 933 934 // Copy strings to the output vector. 935 for (unsigned i = 0, NumArgs = d.getNumArgs(); i < NumArgs; ++i) { 936 OutVec.push_back(InitPtrToString(d.getArg(i))); 937 } 938 939 // Remove duplicates. 940 std::sort(OutVec.begin(), OutVec.end()); 941 StrVector::iterator newE = std::unique(OutVec.begin(), OutVec.end()); 942 OutVec.erase(newE, OutVec.end()); 943 } 944 945 946 void onInLanguage (const DagInit& d) { 947 this->onInOutLanguage(d, toolDesc_.InLanguage); 948 } 949 950 void onJoin (const DagInit& d) { 951 bool isReallyJoin = false; 952 953 if (d.getNumArgs() == 0) { 954 isReallyJoin = true; 955 } 956 else { 957 Init* I = d.getArg(0); 958 isReallyJoin = InitPtrToBool(I); 959 } 960 961 // Is this *really* a join tool? We allow (join false) for generating two 962 // tool descriptions from a single generic one. 963 // TOFIX: come up with a cleaner solution. 964 if (isReallyJoin) { 965 toolDesc_.setJoin(); 966 } 967 } 968 969 void onOutLanguage (const DagInit& d) { 970 this->onInOutLanguage(d, toolDesc_.OutLanguage); 971 } 972 973 void onOutFileOption (const DagInit& d) { 974 CheckNumberOfArguments(d, 1); 975 toolDesc_.OutFileOption = InitPtrToString(d.getArg(0)); 976 } 977 978 void onInFileOption (const DagInit& d) { 979 CheckNumberOfArguments(d, 1); 980 toolDesc_.InFileOption = InitPtrToString(d.getArg(0)); 981 } 982 983 void onOutputSuffix (const DagInit& d) { 984 CheckNumberOfArguments(d, 1); 985 toolDesc_.OutputSuffix = InitPtrToString(d.getArg(0)); 986 } 987 988 void onSink (const DagInit& d) { 989 CheckNumberOfArguments(d, 0); 990 toolDesc_.setSink(); 991 } 992 993 void onWorksOnEmpty (const DagInit& d) { 994 toolDesc_.OnEmpty = d.getArg(0); 995 } 996 997 }; 998 999 /// CollectToolDescriptions - Gather information about tool properties 1000 /// from the parsed TableGen data (basically a wrapper for the 1001 /// CollectToolProperties function object). 1002 void CollectToolDescriptions (const RecordVector& Tools, 1003 ToolDescriptions& ToolDescs) 1004 { 1005 // Iterate over a properties list of every Tool definition 1006 for (RecordVector::const_iterator B = Tools.begin(), 1007 E = Tools.end(); B!=E; ++B) { 1008 const Record* T = *B; 1009 // Throws an exception if the value does not exist. 1010 ListInit* PropList = T->getValueAsListInit("properties"); 1011 1012 IntrusiveRefCntPtr<ToolDescription> 1013 ToolDesc(new ToolDescription(T->getName())); 1014 1015 std::for_each(PropList->begin(), PropList->end(), 1016 CollectToolProperties(*ToolDesc)); 1017 ToolDescs.push_back(ToolDesc); 1018 } 1019 } 1020 1021 /// FillInEdgeVector - Merge all compilation graph definitions into 1022 /// one single edge list. 1023 void FillInEdgeVector(const RecordVector& CompilationGraphs, 1024 DagVector& Out) { 1025 for (RecordVector::const_iterator B = CompilationGraphs.begin(), 1026 E = CompilationGraphs.end(); B != E; ++B) { 1027 const ListInit* Edges = (*B)->getValueAsListInit("edges"); 1028 1029 for (ListInit::const_iterator B = Edges->begin(), 1030 E = Edges->end(); B != E; ++B) { 1031 Out.push_back(&InitPtrToDag(*B)); 1032 } 1033 } 1034 } 1035 1036 /// NotInGraph - Helper function object for FilterNotInGraph. 1037 struct NotInGraph { 1038 private: 1039 const llvm::StringSet<>& ToolsInGraph_; 1040 1041 public: 1042 NotInGraph(const llvm::StringSet<>& ToolsInGraph) 1043 : ToolsInGraph_(ToolsInGraph) 1044 {} 1045 1046 bool operator()(const IntrusiveRefCntPtr<ToolDescription>& x) { 1047 return (ToolsInGraph_.count(x->Name) == 0); 1048 } 1049 }; 1050 1051 /// FilterNotInGraph - Filter out from ToolDescs all Tools not 1052 /// mentioned in the compilation graph definition. 1053 void FilterNotInGraph (const DagVector& EdgeVector, 1054 ToolDescriptions& ToolDescs) { 1055 1056 // List all tools mentioned in the graph. 1057 llvm::StringSet<> ToolsInGraph; 1058 1059 for (DagVector::const_iterator B = EdgeVector.begin(), 1060 E = EdgeVector.end(); B != E; ++B) { 1061 1062 const DagInit* Edge = *B; 1063 const std::string& NodeA = InitPtrToString(Edge->getArg(0)); 1064 const std::string& NodeB = InitPtrToString(Edge->getArg(1)); 1065 1066 if (NodeA != "root") 1067 ToolsInGraph.insert(NodeA); 1068 ToolsInGraph.insert(NodeB); 1069 } 1070 1071 // Filter ToolPropertiesList. 1072 ToolDescriptions::iterator new_end = 1073 std::remove_if(ToolDescs.begin(), ToolDescs.end(), 1074 NotInGraph(ToolsInGraph)); 1075 ToolDescs.erase(new_end, ToolDescs.end()); 1076 } 1077 1078 /// FillInToolToLang - Fills in two tables that map tool names to 1079 /// input & output language names. Helper function used by TypecheckGraph(). 1080 void FillInToolToLang (const ToolDescriptions& ToolDescs, 1081 StringMap<StringSet<> >& ToolToInLang, 1082 StringMap<StringSet<> >& ToolToOutLang) { 1083 for (ToolDescriptions::const_iterator B = ToolDescs.begin(), 1084 E = ToolDescs.end(); B != E; ++B) { 1085 const ToolDescription& D = *(*B); 1086 for (StrVector::const_iterator B = D.InLanguage.begin(), 1087 E = D.InLanguage.end(); B != E; ++B) 1088 ToolToInLang[D.Name].insert(*B); 1089 for (StrVector::const_iterator B = D.OutLanguage.begin(), 1090 E = D.OutLanguage.end(); B != E; ++B) 1091 ToolToOutLang[D.Name].insert(*B); 1092 } 1093 } 1094 1095 /// Intersect - Is set intersection non-empty? 1096 bool Intersect (const StringSet<>& S1, const StringSet<>& S2) { 1097 for (StringSet<>::const_iterator B = S1.begin(), E = S1.end(); B != E; ++B) { 1098 if (S2.count(B->first()) != 0) 1099 return true; 1100 } 1101 return false; 1102 } 1103 1104 /// TypecheckGraph - Check that names for output and input languages 1105 /// on all edges do match. 1106 void TypecheckGraph (const DagVector& EdgeVector, 1107 const ToolDescriptions& ToolDescs) { 1108 StringMap<StringSet<> > ToolToInLang; 1109 StringMap<StringSet<> > ToolToOutLang; 1110 1111 FillInToolToLang(ToolDescs, ToolToInLang, ToolToOutLang); 1112 1113 for (DagVector::const_iterator B = EdgeVector.begin(), 1114 E = EdgeVector.end(); B != E; ++B) { 1115 const DagInit* Edge = *B; 1116 const std::string& NodeA = InitPtrToString(Edge->getArg(0)); 1117 const std::string& NodeB = InitPtrToString(Edge->getArg(1)); 1118 StringMap<StringSet<> >::iterator IA = ToolToOutLang.find(NodeA); 1119 StringMap<StringSet<> >::iterator IB = ToolToInLang.find(NodeB); 1120 1121 if (NodeB == "root") 1122 throw "Edges back to the root are not allowed!"; 1123 1124 if (NodeA != "root") { 1125 if (IA == ToolToOutLang.end()) 1126 throw NodeA + ": no output language defined!"; 1127 if (IB == ToolToInLang.end()) 1128 throw NodeB + ": no input language defined!"; 1129 1130 if (!Intersect(IA->second, IB->second)) { 1131 throw "Edge " + NodeA + "->" + NodeB 1132 + ": output->input language mismatch"; 1133 } 1134 } 1135 } 1136 } 1137 1138 /// WalkCase - Walks the 'case' expression DAG and invokes 1139 /// TestCallback on every test, and StatementCallback on every 1140 /// statement. Handles 'case' nesting, but not the 'and' and 'or' 1141 /// combinators (that is, they are passed directly to TestCallback). 1142 /// TestCallback must have type 'void TestCallback(const DagInit*, unsigned 1143 /// IndentLevel, bool FirstTest)'. 1144 /// StatementCallback must have type 'void StatementCallback(const Init*, 1145 /// unsigned IndentLevel)'. 1146 template <typename F1, typename F2> 1147 void WalkCase(const Init* Case, F1 TestCallback, F2 StatementCallback, 1148 unsigned IndentLevel = 0) 1149 { 1150 const DagInit& d = InitPtrToDag(Case); 1151 1152 // Error checks. 1153 if (GetOperatorName(d) != "case") 1154 throw "WalkCase should be invoked only on 'case' expressions!"; 1155 1156 if (d.getNumArgs() < 2) 1157 throw "There should be at least one clause in the 'case' expression:\n" 1158 + d.getAsString(); 1159 1160 // Main loop. 1161 bool even = false; 1162 const unsigned numArgs = d.getNumArgs(); 1163 unsigned i = 1; 1164 for (DagInit::const_arg_iterator B = d.arg_begin(), E = d.arg_end(); 1165 B != E; ++B) { 1166 Init* arg = *B; 1167 1168 if (!even) 1169 { 1170 // Handle test. 1171 const DagInit& Test = InitPtrToDag(arg); 1172 1173 if (GetOperatorName(Test) == "default" && (i+1 != numArgs)) 1174 throw "The 'default' clause should be the last in the " 1175 "'case' construct!"; 1176 if (i == numArgs) 1177 throw "Case construct handler: no corresponding action " 1178 "found for the test " + Test.getAsString() + '!'; 1179 1180 TestCallback(Test, IndentLevel, (i == 1)); 1181 } 1182 else 1183 { 1184 if (dynamic_cast<DagInit*>(arg) 1185 && GetOperatorName(static_cast<DagInit&>(*arg)) == "case") { 1186 // Nested 'case'. 1187 WalkCase(arg, TestCallback, StatementCallback, IndentLevel + Indent1); 1188 } 1189 1190 // Handle statement. 1191 StatementCallback(arg, IndentLevel); 1192 } 1193 1194 ++i; 1195 even = !even; 1196 } 1197 } 1198 1199 /// ExtractOptionNames - A helper function object used by 1200 /// CheckForSuperfluousOptions() to walk the 'case' DAG. 1201 class ExtractOptionNames { 1202 llvm::StringSet<>& OptionNames_; 1203 1204 void processDag(const Init* Statement) { 1205 const DagInit& Stmt = InitPtrToDag(Statement); 1206 const std::string& ActionName = GetOperatorName(Stmt); 1207 if (ActionName == "forward" || ActionName == "forward_as" || 1208 ActionName == "forward_value" || 1209 ActionName == "forward_transformed_value" || 1210 ActionName == "parameter_equals" || ActionName == "element_in_list") { 1211 CheckNumberOfArguments(Stmt, 1); 1212 1213 Init* Arg = Stmt.getArg(0); 1214 if (typeid(*Arg) == typeid(StringInit)) 1215 OptionNames_.insert(InitPtrToString(Arg)); 1216 } 1217 else if (ActionName == "any_switch_on" || ActionName == "switch_on" || 1218 ActionName == "any_not_empty" || ActionName == "any_empty" || 1219 ActionName == "not_empty" || ActionName == "empty") { 1220 for (unsigned i = 0, NumArgs = Stmt.getNumArgs(); i < NumArgs; ++i) { 1221 Init* Arg = Stmt.getArg(i); 1222 if (typeid(*Arg) == typeid(StringInit)) 1223 OptionNames_.insert(InitPtrToString(Arg)); 1224 } 1225 } 1226 else if (ActionName == "and" || ActionName == "or" || ActionName == "not") { 1227 for (unsigned i = 0, NumArgs = Stmt.getNumArgs(); i < NumArgs; ++i) { 1228 this->processDag(Stmt.getArg(i)); 1229 } 1230 } 1231 } 1232 1233 public: 1234 ExtractOptionNames(llvm::StringSet<>& OptionNames) : OptionNames_(OptionNames) 1235 {} 1236 1237 void operator()(const Init* Statement) { 1238 // Statement is either a dag, or a list of dags. 1239 if (typeid(*Statement) == typeid(ListInit)) { 1240 const ListInit& DagList = *static_cast<const ListInit*>(Statement); 1241 for (ListInit::const_iterator B = DagList.begin(), E = DagList.end(); 1242 B != E; ++B) 1243 this->processDag(*B); 1244 } 1245 else { 1246 this->processDag(Statement); 1247 } 1248 } 1249 1250 void operator()(const DagInit& Test, unsigned, bool) { 1251 this->operator()(&Test); 1252 } 1253 void operator()(const Init* Statement, unsigned) { 1254 this->operator()(Statement); 1255 } 1256 }; 1257 1258 /// IsOptionalEdge - Validate that the 'optional_edge' has proper structure. 1259 bool IsOptionalEdge (const DagInit& Edg) { 1260 return (GetOperatorName(Edg) == "optional_edge") && (Edg.getNumArgs() > 2); 1261 } 1262 1263 /// CheckForSuperfluousOptions - Check that there are no side 1264 /// effect-free options (specified only in the OptionList). Otherwise, 1265 /// output a warning. 1266 void CheckForSuperfluousOptions (const DagVector& EdgeVector, 1267 const ToolDescriptions& ToolDescs, 1268 const OptionDescriptions& OptDescs) { 1269 llvm::StringSet<> nonSuperfluousOptions; 1270 1271 // Add all options mentioned in the ToolDesc.Actions to the set of 1272 // non-superfluous options. 1273 for (ToolDescriptions::const_iterator B = ToolDescs.begin(), 1274 E = ToolDescs.end(); B != E; ++B) { 1275 const ToolDescription& TD = *(*B); 1276 ExtractOptionNames Callback(nonSuperfluousOptions); 1277 if (TD.Actions) 1278 WalkCase(TD.Actions, Callback, Callback); 1279 } 1280 1281 // Add all options mentioned in the 'case' clauses of the 1282 // OptionalEdges of the compilation graph to the set of 1283 // non-superfluous options. 1284 for (DagVector::const_iterator B = EdgeVector.begin(), 1285 E = EdgeVector.end(); B != E; ++B) { 1286 const DagInit& Edge = **B; 1287 if (IsOptionalEdge(Edge)) { 1288 const DagInit& Weight = InitPtrToDag(Edge.getArg(2)); 1289 WalkCase(&Weight, ExtractOptionNames(nonSuperfluousOptions), Id()); 1290 } 1291 } 1292 1293 // Check that all options in OptDescs belong to the set of 1294 // non-superfluous options. 1295 for (OptionDescriptions::const_iterator B = OptDescs.begin(), 1296 E = OptDescs.end(); B != E; ++B) { 1297 const OptionDescription& Val = B->second; 1298 if (!nonSuperfluousOptions.count(Val.Name) 1299 && Val.Type != OptionType::Alias) 1300 llvm::errs() << "Warning: option '-" << Val.Name << "' has no effect! " 1301 "Probable cause: this option is specified only in the OptionList.\n"; 1302 } 1303 } 1304 1305 /// EmitCaseTest0Args - Helper function used by EmitCaseConstructHandler(). 1306 bool EmitCaseTest0Args(const std::string& TestName, raw_ostream& O) { 1307 if (TestName == "single_input_file") { 1308 O << "InputFilenames.size() == 1"; 1309 return true; 1310 } 1311 else if (TestName == "multiple_input_files") { 1312 O << "InputFilenames.size() > 1"; 1313 return true; 1314 } 1315 1316 return false; 1317 } 1318 1319 /// EmitMultipleArgumentTest - Helper function used by 1320 /// EmitCaseTestMultipleArgs() 1321 template <typename F> 1322 void EmitMultipleArgumentTest(const DagInit& D, const char* LogicOp, 1323 F Callback, raw_ostream& O) 1324 { 1325 for (unsigned i = 0, NumArgs = D.getNumArgs(); i < NumArgs; ++i) { 1326 if (i != 0) 1327 O << ' ' << LogicOp << ' '; 1328 Callback(InitPtrToString(D.getArg(i)), O); 1329 } 1330 } 1331 1332 // Callbacks for use with EmitMultipleArgumentTest 1333 1334 class EmitSwitchOn { 1335 const OptionDescriptions& OptDescs_; 1336 public: 1337 EmitSwitchOn(const OptionDescriptions& OptDescs) : OptDescs_(OptDescs) 1338 {} 1339 1340 void operator()(const std::string& OptName, raw_ostream& O) const { 1341 const OptionDescription& OptDesc = OptDescs_.FindSwitch(OptName); 1342 O << OptDesc.GenVariableName(); 1343 } 1344 }; 1345 1346 class EmitEmptyTest { 1347 bool EmitNegate_; 1348 const OptionDescriptions& OptDescs_; 1349 public: 1350 EmitEmptyTest(bool EmitNegate, const OptionDescriptions& OptDescs) 1351 : EmitNegate_(EmitNegate), OptDescs_(OptDescs) 1352 {} 1353 1354 void operator()(const std::string& OptName, raw_ostream& O) const { 1355 const char* Neg = (EmitNegate_ ? "!" : ""); 1356 if (OptName == "o") { 1357 O << Neg << "OutputFilename.empty()"; 1358 } 1359 else if (OptName == "save-temps") { 1360 O << Neg << "(SaveTemps == SaveTempsEnum::Unset)"; 1361 } 1362 else { 1363 const OptionDescription& OptDesc = OptDescs_.FindListOrParameter(OptName); 1364 O << Neg << OptDesc.GenVariableName() << ".empty()"; 1365 } 1366 } 1367 }; 1368 1369 1370 /// EmitCaseTestMultipleArgs - Helper function used by EmitCaseTest1Arg() 1371 bool EmitCaseTestMultipleArgs (const std::string& TestName, 1372 const DagInit& d, 1373 const OptionDescriptions& OptDescs, 1374 raw_ostream& O) { 1375 if (TestName == "any_switch_on") { 1376 EmitMultipleArgumentTest(d, "||", EmitSwitchOn(OptDescs), O); 1377 return true; 1378 } 1379 else if (TestName == "switch_on") { 1380 EmitMultipleArgumentTest(d, "&&", EmitSwitchOn(OptDescs), O); 1381 return true; 1382 } 1383 else if (TestName == "any_not_empty") { 1384 EmitMultipleArgumentTest(d, "||", EmitEmptyTest(true, OptDescs), O); 1385 return true; 1386 } 1387 else if (TestName == "any_empty") { 1388 EmitMultipleArgumentTest(d, "||", EmitEmptyTest(false, OptDescs), O); 1389 return true; 1390 } 1391 else if (TestName == "not_empty") { 1392 EmitMultipleArgumentTest(d, "&&", EmitEmptyTest(true, OptDescs), O); 1393 return true; 1394 } 1395 else if (TestName == "empty") { 1396 EmitMultipleArgumentTest(d, "&&", EmitEmptyTest(false, OptDescs), O); 1397 return true; 1398 } 1399 1400 return false; 1401 } 1402 1403 /// EmitCaseTest1Arg - Helper function used by EmitCaseTest1OrMoreArgs() 1404 bool EmitCaseTest1Arg (const std::string& TestName, 1405 const DagInit& d, 1406 const OptionDescriptions& OptDescs, 1407 raw_ostream& O) { 1408 const std::string& Arg = InitPtrToString(d.getArg(0)); 1409 1410 if (TestName == "input_languages_contain") { 1411 O << "InLangs.count(\"" << Arg << "\") != 0"; 1412 return true; 1413 } 1414 else if (TestName == "in_language") { 1415 // This works only for single-argument Tool::GenerateAction. Join 1416 // tools can process several files in different languages simultaneously. 1417 1418 // TODO: make this work with Edge::Weight (if possible). 1419 O << "LangMap.GetLanguage(inFile) == \"" << Arg << '\"'; 1420 return true; 1421 } 1422 1423 return false; 1424 } 1425 1426 /// EmitCaseTest1OrMoreArgs - Helper function used by 1427 /// EmitCaseConstructHandler() 1428 bool EmitCaseTest1OrMoreArgs(const std::string& TestName, 1429 const DagInit& d, 1430 const OptionDescriptions& OptDescs, 1431 raw_ostream& O) { 1432 CheckNumberOfArguments(d, 1); 1433 return EmitCaseTest1Arg(TestName, d, OptDescs, O) || 1434 EmitCaseTestMultipleArgs(TestName, d, OptDescs, O); 1435 } 1436 1437 /// EmitCaseTest2Args - Helper function used by EmitCaseConstructHandler(). 1438 bool EmitCaseTest2Args(const std::string& TestName, 1439 const DagInit& d, 1440 unsigned IndentLevel, 1441 const OptionDescriptions& OptDescs, 1442 raw_ostream& O) { 1443 CheckNumberOfArguments(d, 2); 1444 const std::string& OptName = InitPtrToString(d.getArg(0)); 1445 const std::string& OptArg = InitPtrToString(d.getArg(1)); 1446 1447 if (TestName == "parameter_equals") { 1448 const OptionDescription& OptDesc = OptDescs.FindParameter(OptName); 1449 O << OptDesc.GenVariableName() << " == \"" << OptArg << "\""; 1450 return true; 1451 } 1452 else if (TestName == "element_in_list") { 1453 const OptionDescription& OptDesc = OptDescs.FindParameterList(OptName); 1454 const std::string& VarName = OptDesc.GenVariableName(); 1455 O << "std::find(" << VarName << ".begin(),\n"; 1456 O.indent(IndentLevel + Indent1) 1457 << VarName << ".end(), \"" 1458 << OptArg << "\") != " << VarName << ".end()"; 1459 return true; 1460 } 1461 1462 return false; 1463 } 1464 1465 // Forward declaration. 1466 // EmitLogicalOperationTest and EmitCaseTest are mutually recursive. 1467 void EmitCaseTest(const DagInit& d, unsigned IndentLevel, 1468 const OptionDescriptions& OptDescs, 1469 raw_ostream& O); 1470 1471 /// EmitLogicalOperationTest - Helper function used by 1472 /// EmitCaseConstructHandler. 1473 void EmitLogicalOperationTest(const DagInit& d, const char* LogicOp, 1474 unsigned IndentLevel, 1475 const OptionDescriptions& OptDescs, 1476 raw_ostream& O) { 1477 O << '('; 1478 for (unsigned i = 0, NumArgs = d.getNumArgs(); i < NumArgs; ++i) { 1479 const DagInit& InnerTest = InitPtrToDag(d.getArg(i)); 1480 EmitCaseTest(InnerTest, IndentLevel, OptDescs, O); 1481 if (i != NumArgs - 1) { 1482 O << ")\n"; 1483 O.indent(IndentLevel + Indent1) << ' ' << LogicOp << " ("; 1484 } 1485 else { 1486 O << ')'; 1487 } 1488 } 1489 } 1490 1491 void EmitLogicalNot(const DagInit& d, unsigned IndentLevel, 1492 const OptionDescriptions& OptDescs, raw_ostream& O) 1493 { 1494 CheckNumberOfArguments(d, 1); 1495 const DagInit& InnerTest = InitPtrToDag(d.getArg(0)); 1496 O << "! ("; 1497 EmitCaseTest(InnerTest, IndentLevel, OptDescs, O); 1498 O << ")"; 1499 } 1500 1501 /// EmitCaseTest - Helper function used by EmitCaseConstructHandler. 1502 void EmitCaseTest(const DagInit& d, unsigned IndentLevel, 1503 const OptionDescriptions& OptDescs, 1504 raw_ostream& O) { 1505 const std::string& TestName = GetOperatorName(d); 1506 1507 if (TestName == "and") 1508 EmitLogicalOperationTest(d, "&&", IndentLevel, OptDescs, O); 1509 else if (TestName == "or") 1510 EmitLogicalOperationTest(d, "||", IndentLevel, OptDescs, O); 1511 else if (TestName == "not") 1512 EmitLogicalNot(d, IndentLevel, OptDescs, O); 1513 else if (EmitCaseTest0Args(TestName, O)) 1514 return; 1515 else if (EmitCaseTest1OrMoreArgs(TestName, d, OptDescs, O)) 1516 return; 1517 else if (EmitCaseTest2Args(TestName, d, IndentLevel, OptDescs, O)) 1518 return; 1519 else 1520 throw "Unknown test '" + TestName + "' used in the 'case' construct!"; 1521 } 1522 1523 1524 /// EmitCaseTestCallback - Callback used by EmitCaseConstructHandler. 1525 class EmitCaseTestCallback { 1526 bool EmitElseIf_; 1527 const OptionDescriptions& OptDescs_; 1528 raw_ostream& O_; 1529 public: 1530 1531 EmitCaseTestCallback(bool EmitElseIf, 1532 const OptionDescriptions& OptDescs, raw_ostream& O) 1533 : EmitElseIf_(EmitElseIf), OptDescs_(OptDescs), O_(O) 1534 {} 1535 1536 void operator()(const DagInit& Test, unsigned IndentLevel, bool FirstTest) 1537 { 1538 if (GetOperatorName(Test) == "default") { 1539 O_.indent(IndentLevel) << "else {\n"; 1540 } 1541 else { 1542 O_.indent(IndentLevel) 1543 << ((!FirstTest && EmitElseIf_) ? "else if (" : "if ("); 1544 EmitCaseTest(Test, IndentLevel, OptDescs_, O_); 1545 O_ << ") {\n"; 1546 } 1547 } 1548 }; 1549 1550 /// EmitCaseStatementCallback - Callback used by EmitCaseConstructHandler. 1551 template <typename F> 1552 class EmitCaseStatementCallback { 1553 F Callback_; 1554 raw_ostream& O_; 1555 public: 1556 1557 EmitCaseStatementCallback(F Callback, raw_ostream& O) 1558 : Callback_(Callback), O_(O) 1559 {} 1560 1561 void operator() (const Init* Statement, unsigned IndentLevel) { 1562 // Is this a nested 'case'? 1563 bool IsCase = dynamic_cast<const DagInit*>(Statement) && 1564 GetOperatorName(static_cast<const DagInit&>(*Statement)) == "case"; 1565 1566 // If so, ignore it, it is handled by our caller, WalkCase. 1567 if (!IsCase) { 1568 if (typeid(*Statement) == typeid(ListInit)) { 1569 const ListInit& DagList = *static_cast<const ListInit*>(Statement); 1570 for (ListInit::const_iterator B = DagList.begin(), E = DagList.end(); 1571 B != E; ++B) 1572 Callback_(*B, (IndentLevel + Indent1), O_); 1573 } 1574 else { 1575 Callback_(Statement, (IndentLevel + Indent1), O_); 1576 } 1577 } 1578 O_.indent(IndentLevel) << "}\n"; 1579 } 1580 1581 }; 1582 1583 /// EmitCaseConstructHandler - Emit code that handles the 'case' 1584 /// construct. Takes a function object that should emit code for every case 1585 /// clause. Implemented on top of WalkCase. 1586 /// Callback's type is void F(const Init* Statement, unsigned IndentLevel, 1587 /// raw_ostream& O). 1588 /// EmitElseIf parameter controls the type of condition that is emitted ('if 1589 /// (..) {..} else if (..) {} .. else {..}' vs. 'if (..) {..} if(..) {..} 1590 /// .. else {..}'). 1591 template <typename F> 1592 void EmitCaseConstructHandler(const Init* Case, unsigned IndentLevel, 1593 F Callback, bool EmitElseIf, 1594 const OptionDescriptions& OptDescs, 1595 raw_ostream& O) { 1596 WalkCase(Case, EmitCaseTestCallback(EmitElseIf, OptDescs, O), 1597 EmitCaseStatementCallback<F>(Callback, O), IndentLevel); 1598 } 1599 1600 /// TokenizeCmdLine - converts from 1601 /// "$CALL(HookName, 'Arg1', 'Arg2')/path -arg1 -arg2" to 1602 /// ["$CALL(", "HookName", "Arg1", "Arg2", ")/path", "-arg1", "-arg2"]. 1603 void TokenizeCmdLine(const std::string& CmdLine, StrVector& Out) { 1604 const char* Delimiters = " \t\n\v\f\r"; 1605 enum TokenizerState 1606 { Normal, SpecialCommand, InsideSpecialCommand, InsideQuotationMarks } 1607 cur_st = Normal; 1608 1609 if (CmdLine.empty()) 1610 return; 1611 Out.push_back(""); 1612 1613 std::string::size_type B = CmdLine.find_first_not_of(Delimiters), 1614 E = CmdLine.size(); 1615 1616 for (; B != E; ++B) { 1617 char cur_ch = CmdLine[B]; 1618 1619 switch (cur_st) { 1620 case Normal: 1621 if (cur_ch == '$') { 1622 cur_st = SpecialCommand; 1623 break; 1624 } 1625 if (OneOf(Delimiters, cur_ch)) { 1626 // Skip whitespace 1627 B = CmdLine.find_first_not_of(Delimiters, B); 1628 if (B == std::string::npos) { 1629 B = E-1; 1630 continue; 1631 } 1632 --B; 1633 Out.push_back(""); 1634 continue; 1635 } 1636 break; 1637 1638 1639 case SpecialCommand: 1640 if (OneOf(Delimiters, cur_ch)) { 1641 cur_st = Normal; 1642 Out.push_back(""); 1643 continue; 1644 } 1645 if (cur_ch == '(') { 1646 Out.push_back(""); 1647 cur_st = InsideSpecialCommand; 1648 continue; 1649 } 1650 break; 1651 1652 case InsideSpecialCommand: 1653 if (OneOf(Delimiters, cur_ch)) { 1654 continue; 1655 } 1656 if (cur_ch == '\'') { 1657 cur_st = InsideQuotationMarks; 1658 Out.push_back(""); 1659 continue; 1660 } 1661 if (cur_ch == ')') { 1662 cur_st = Normal; 1663 Out.push_back(""); 1664 } 1665 if (cur_ch == ',') { 1666 continue; 1667 } 1668 1669 break; 1670 1671 case InsideQuotationMarks: 1672 if (cur_ch == '\'') { 1673 cur_st = InsideSpecialCommand; 1674 continue; 1675 } 1676 break; 1677 } 1678 1679 Out.back().push_back(cur_ch); 1680 } 1681 } 1682 1683 /// SubstituteCall - Given "$CALL(HookName, [Arg1 [, Arg2 [...]]])", output 1684 /// "hooks::HookName([Arg1 [, Arg2 [, ...]]])". Helper function used by 1685 /// SubstituteSpecialCommands(). 1686 StrVector::const_iterator 1687 SubstituteCall (StrVector::const_iterator Pos, 1688 StrVector::const_iterator End, 1689 bool IsJoin, raw_ostream& O) 1690 { 1691 const char* errorMessage = "Syntax error in $CALL invocation!"; 1692 CheckedIncrement(Pos, End, errorMessage); 1693 const std::string& CmdName = *Pos; 1694 1695 if (CmdName == ")") 1696 throw "$CALL invocation: empty argument list!"; 1697 1698 O << "hooks::"; 1699 O << CmdName << "("; 1700 1701 1702 bool firstIteration = true; 1703 while (true) { 1704 CheckedIncrement(Pos, End, errorMessage); 1705 const std::string& Arg = *Pos; 1706 assert(Arg.size() != 0); 1707 1708 if (Arg[0] == ')') 1709 break; 1710 1711 if (firstIteration) 1712 firstIteration = false; 1713 else 1714 O << ", "; 1715 1716 if (Arg == "$INFILE") { 1717 if (IsJoin) 1718 throw "$CALL(Hook, $INFILE) can't be used with a Join tool!"; 1719 else 1720 O << "inFile.c_str()"; 1721 } 1722 else { 1723 O << '"' << Arg << '"'; 1724 } 1725 } 1726 1727 O << ')'; 1728 1729 return Pos; 1730 } 1731 1732 /// SubstituteEnv - Given '$ENV(VAR_NAME)', output 'getenv("VAR_NAME")'. Helper 1733 /// function used by SubstituteSpecialCommands(). 1734 StrVector::const_iterator 1735 SubstituteEnv (StrVector::const_iterator Pos, 1736 StrVector::const_iterator End, raw_ostream& O) 1737 { 1738 const char* errorMessage = "Syntax error in $ENV invocation!"; 1739 CheckedIncrement(Pos, End, errorMessage); 1740 const std::string& EnvName = *Pos; 1741 1742 if (EnvName == ")") 1743 throw "$ENV invocation: empty argument list!"; 1744 1745 O << "checkCString(std::getenv(\""; 1746 O << EnvName; 1747 O << "\"))"; 1748 1749 CheckedIncrement(Pos, End, errorMessage); 1750 1751 return Pos; 1752 } 1753 1754 /// SubstituteSpecialCommands - Given an invocation of $CALL or $ENV, output 1755 /// handler code. Helper function used by EmitCmdLineVecFill(). 1756 StrVector::const_iterator 1757 SubstituteSpecialCommands (StrVector::const_iterator Pos, 1758 StrVector::const_iterator End, 1759 bool IsJoin, raw_ostream& O) 1760 { 1761 1762 const std::string& cmd = *Pos; 1763 1764 // Perform substitution. 1765 if (cmd == "$CALL") { 1766 Pos = SubstituteCall(Pos, End, IsJoin, O); 1767 } 1768 else if (cmd == "$ENV") { 1769 Pos = SubstituteEnv(Pos, End, O); 1770 } 1771 else { 1772 throw "Unknown special command: " + cmd; 1773 } 1774 1775 // Handle '$CMD(ARG)/additional/text'. 1776 const std::string& Leftover = *Pos; 1777 assert(Leftover.at(0) == ')'); 1778 if (Leftover.size() != 1) 1779 O << " + std::string(\"" << (Leftover.c_str() + 1) << "\")"; 1780 1781 return Pos; 1782 } 1783 1784 /// EmitCmdLineVecFill - Emit code that fills in the command line 1785 /// vector. Helper function used by EmitGenerateActionMethod(). 1786 void EmitCmdLineVecFill(const Init* CmdLine, const std::string& ToolName, 1787 bool IsJoin, unsigned IndentLevel, 1788 raw_ostream& O) { 1789 StrVector StrVec; 1790 TokenizeCmdLine(InitPtrToString(CmdLine), StrVec); 1791 1792 if (StrVec.empty()) 1793 throw "Tool '" + ToolName + "' has empty command line!"; 1794 1795 StrVector::const_iterator B = StrVec.begin(), E = StrVec.end(); 1796 1797 // Emit the command itself. 1798 assert(!StrVec[0].empty()); 1799 O.indent(IndentLevel) << "cmd = "; 1800 if (StrVec[0][0] == '$') { 1801 B = SubstituteSpecialCommands(B, E, IsJoin, O); 1802 ++B; 1803 } 1804 else { 1805 O << '"' << StrVec[0] << '"'; 1806 ++B; 1807 } 1808 O << ";\n"; 1809 1810 // Go through the command arguments. 1811 assert(B <= E); 1812 for (; B != E; ++B) { 1813 const std::string& cmd = *B; 1814 1815 assert(!cmd.empty()); 1816 O.indent(IndentLevel); 1817 1818 if (cmd.at(0) == '$') { 1819 O << "vec.push_back(std::make_pair(0, "; 1820 B = SubstituteSpecialCommands(B, E, IsJoin, O); 1821 O << "));\n"; 1822 } 1823 else { 1824 O << "vec.push_back(std::make_pair(0, \"" << cmd << "\"));\n"; 1825 } 1826 } 1827 1828 } 1829 1830 /// EmitForEachListElementCycleHeader - Emit common code for iterating through 1831 /// all elements of a list. Helper function used by 1832 /// EmitForwardOptionPropertyHandlingCode. 1833 void EmitForEachListElementCycleHeader (const OptionDescription& D, 1834 unsigned IndentLevel, 1835 raw_ostream& O) { 1836 unsigned IndentLevel1 = IndentLevel + Indent1; 1837 1838 O.indent(IndentLevel) 1839 << "for (" << D.GenTypeDeclaration() 1840 << "::iterator B = " << D.GenVariableName() << ".begin(),\n"; 1841 O.indent(IndentLevel) 1842 << "E = " << D.GenVariableName() << ".end(); B != E;) {\n"; 1843 O.indent(IndentLevel1) << "unsigned pos = " << D.GenVariableName() 1844 << ".getPosition(B - " << D.GenVariableName() 1845 << ".begin());\n"; 1846 } 1847 1848 /// EmitForwardOptionPropertyHandlingCode - Helper function used to 1849 /// implement EmitActionHandler. Emits code for 1850 /// handling the (forward) and (forward_as) option properties. 1851 void EmitForwardOptionPropertyHandlingCode (const OptionDescription& D, 1852 unsigned IndentLevel, 1853 const std::string& NewName, 1854 raw_ostream& O) { 1855 const std::string& Name = NewName.empty() 1856 ? ("-" + D.Name) 1857 : NewName; 1858 unsigned IndentLevel1 = IndentLevel + Indent1; 1859 1860 switch (D.Type) { 1861 case OptionType::Switch: 1862 O.indent(IndentLevel) 1863 << "vec.push_back(std::make_pair(" << D.GenVariableName() 1864 << ".getPosition(), \"" << Name << "\"));\n"; 1865 break; 1866 case OptionType::Parameter: 1867 O.indent(IndentLevel) << "vec.push_back(std::make_pair(" 1868 << D.GenVariableName() 1869 <<".getPosition(), \"" << Name; 1870 1871 if (!D.isForwardNotSplit()) { 1872 O << "\"));\n"; 1873 O.indent(IndentLevel) << "vec.push_back(std::make_pair(" 1874 << D.GenVariableName() << ".getPosition(), " 1875 << D.GenVariableName() << "));\n"; 1876 } 1877 else { 1878 O << "=\" + " << D.GenVariableName() << "));\n"; 1879 } 1880 break; 1881 case OptionType::Prefix: 1882 O.indent(IndentLevel) << "vec.push_back(std::make_pair(" 1883 << D.GenVariableName() << ".getPosition(), \"" 1884 << Name << "\" + " 1885 << D.GenVariableName() << "));\n"; 1886 break; 1887 case OptionType::PrefixList: 1888 EmitForEachListElementCycleHeader(D, IndentLevel, O); 1889 O.indent(IndentLevel1) << "vec.push_back(std::make_pair(pos, \"" 1890 << Name << "\" + " << "*B));\n"; 1891 O.indent(IndentLevel1) << "++B;\n"; 1892 1893 for (int i = 1, j = D.MultiVal; i < j; ++i) { 1894 O.indent(IndentLevel1) << "vec.push_back(std::make_pair(pos, *B));\n"; 1895 O.indent(IndentLevel1) << "++B;\n"; 1896 } 1897 1898 O.indent(IndentLevel) << "}\n"; 1899 break; 1900 case OptionType::ParameterList: 1901 EmitForEachListElementCycleHeader(D, IndentLevel, O); 1902 O.indent(IndentLevel1) << "vec.push_back(std::make_pair(pos, \"" 1903 << Name << "\"));\n"; 1904 1905 for (int i = 0, j = D.MultiVal; i < j; ++i) { 1906 O.indent(IndentLevel1) << "vec.push_back(std::make_pair(pos, *B));\n"; 1907 O.indent(IndentLevel1) << "++B;\n"; 1908 } 1909 1910 O.indent(IndentLevel) << "}\n"; 1911 break; 1912 case OptionType::SwitchList: 1913 EmitForEachListElementCycleHeader(D, IndentLevel, O); 1914 O.indent(IndentLevel1) << "vec.push_back(std::make_pair(pos, \"" 1915 << Name << "\"));\n"; 1916 O.indent(IndentLevel1) << "++B;\n"; 1917 O.indent(IndentLevel) << "}\n"; 1918 break; 1919 case OptionType::Alias: 1920 default: 1921 throw "Aliases are not allowed in tool option descriptions!"; 1922 } 1923 } 1924 1925 /// ActionHandlingCallbackBase - Base class of EmitActionHandlersCallback and 1926 /// EmitPreprocessOptionsCallback. 1927 struct ActionHandlingCallbackBase 1928 { 1929 1930 void onErrorDag(const DagInit& d, 1931 unsigned IndentLevel, raw_ostream& O) const 1932 { 1933 O.indent(IndentLevel) 1934 << "PrintError(\"" 1935 << (d.getNumArgs() >= 1 ? InitPtrToString(d.getArg(0)) : "Unknown error!") 1936 << "\");\n"; 1937 O.indent(IndentLevel) << "return 1;\n"; 1938 } 1939 1940 void onWarningDag(const DagInit& d, 1941 unsigned IndentLevel, raw_ostream& O) const 1942 { 1943 CheckNumberOfArguments(d, 1); 1944 O.indent(IndentLevel) << "llvm::errs() << \"" 1945 << InitPtrToString(d.getArg(0)) << "\";\n"; 1946 } 1947 1948 }; 1949 1950 /// EmitActionHandlersCallback - Emit code that handles actions. Used by 1951 /// EmitGenerateActionMethod() as an argument to EmitCaseConstructHandler(). 1952 class EmitActionHandlersCallback; 1953 1954 typedef void (EmitActionHandlersCallback::* EmitActionHandlersCallbackHandler) 1955 (const DagInit&, unsigned, raw_ostream&) const; 1956 1957 class EmitActionHandlersCallback : 1958 public ActionHandlingCallbackBase, 1959 public HandlerTable<EmitActionHandlersCallbackHandler> 1960 { 1961 typedef EmitActionHandlersCallbackHandler Handler; 1962 1963 const OptionDescriptions& OptDescs; 1964 1965 /// EmitHookInvocation - Common code for hook invocation from actions. Used by 1966 /// onAppendCmd and onOutputSuffix. 1967 void EmitHookInvocation(const std::string& Str, 1968 const char* BlockOpen, const char* BlockClose, 1969 unsigned IndentLevel, raw_ostream& O) const 1970 { 1971 StrVector Out; 1972 TokenizeCmdLine(Str, Out); 1973 1974 for (StrVector::const_iterator B = Out.begin(), E = Out.end(); 1975 B != E; ++B) { 1976 const std::string& cmd = *B; 1977 1978 O.indent(IndentLevel) << BlockOpen; 1979 1980 if (cmd.at(0) == '$') 1981 B = SubstituteSpecialCommands(B, E, /* IsJoin = */ true, O); 1982 else 1983 O << '"' << cmd << '"'; 1984 1985 O << BlockClose; 1986 } 1987 } 1988 1989 void onAppendCmd (const DagInit& Dag, 1990 unsigned IndentLevel, raw_ostream& O) const 1991 { 1992 CheckNumberOfArguments(Dag, 1); 1993 this->EmitHookInvocation(InitPtrToString(Dag.getArg(0)), 1994 "vec.push_back(std::make_pair(65536, ", "));\n", 1995 IndentLevel, O); 1996 } 1997 1998 void onForward (const DagInit& Dag, 1999 unsigned IndentLevel, raw_ostream& O) const 2000 { 2001 CheckNumberOfArguments(Dag, 1); 2002 const std::string& Name = InitPtrToString(Dag.getArg(0)); 2003 EmitForwardOptionPropertyHandlingCode(OptDescs.FindOption(Name), 2004 IndentLevel, "", O); 2005 } 2006 2007 void onForwardAs (const DagInit& Dag, 2008 unsigned IndentLevel, raw_ostream& O) const 2009 { 2010 CheckNumberOfArguments(Dag, 2); 2011 const std::string& Name = InitPtrToString(Dag.getArg(0)); 2012 const std::string& NewName = InitPtrToString(Dag.getArg(1)); 2013 EmitForwardOptionPropertyHandlingCode(OptDescs.FindOption(Name), 2014 IndentLevel, NewName, O); 2015 } 2016 2017 void onForwardValue (const DagInit& Dag, 2018 unsigned IndentLevel, raw_ostream& O) const 2019 { 2020 CheckNumberOfArguments(Dag, 1); 2021 const std::string& Name = InitPtrToString(Dag.getArg(0)); 2022 const OptionDescription& D = OptDescs.FindParameterListOrParameter(Name); 2023 2024 if (D.isSwitchList()) { 2025 throw std::runtime_error 2026 ("forward_value is not allowed with switch_list"); 2027 } 2028 2029 if (D.isParameter()) { 2030 O.indent(IndentLevel) << "vec.push_back(std::make_pair(" 2031 << D.GenVariableName() << ".getPosition(), " 2032 << D.GenVariableName() << "));\n"; 2033 } 2034 else { 2035 O.indent(IndentLevel) << "for (" << D.GenTypeDeclaration() 2036 << "::iterator B = " << D.GenVariableName() 2037 << ".begin(), \n"; 2038 O.indent(IndentLevel + Indent1) << " E = " << D.GenVariableName() 2039 << ".end(); B != E; ++B)\n"; 2040 O.indent(IndentLevel) << "{\n"; 2041 O.indent(IndentLevel + Indent1) 2042 << "unsigned pos = " << D.GenVariableName() 2043 << ".getPosition(B - " << D.GenVariableName() 2044 << ".begin());\n"; 2045 O.indent(IndentLevel + Indent1) 2046 << "vec.push_back(std::make_pair(pos, *B));\n"; 2047 O.indent(IndentLevel) << "}\n"; 2048 } 2049 } 2050 2051 void onForwardTransformedValue (const DagInit& Dag, 2052 unsigned IndentLevel, raw_ostream& O) const 2053 { 2054 CheckNumberOfArguments(Dag, 2); 2055 const std::string& Name = InitPtrToString(Dag.getArg(0)); 2056 const std::string& Hook = InitPtrToString(Dag.getArg(1)); 2057 const OptionDescription& D = OptDescs.FindParameterListOrParameter(Name); 2058 2059 O.indent(IndentLevel) << "vec.push_back(std::make_pair(" 2060 << D.GenVariableName() << ".getPosition(" 2061 << (D.isList() ? "0" : "") << "), " 2062 << "hooks::" << Hook << "(" << D.GenVariableName() 2063 << (D.isParameter() ? ".c_str()" : "") << ")));\n"; 2064 } 2065 2066 void onNoOutFile (const DagInit& Dag, 2067 unsigned IndentLevel, raw_ostream& O) const 2068 { 2069 CheckNumberOfArguments(Dag, 0); 2070 O.indent(IndentLevel) << "no_out_file = true;\n"; 2071 } 2072 2073 void onOutputSuffix (const DagInit& Dag, 2074 unsigned IndentLevel, raw_ostream& O) const 2075 { 2076 CheckNumberOfArguments(Dag, 1); 2077 this->EmitHookInvocation(InitPtrToString(Dag.getArg(0)), 2078 "output_suffix = ", ";\n", IndentLevel, O); 2079 } 2080 2081 void onStopCompilation (const DagInit& Dag, 2082 unsigned IndentLevel, raw_ostream& O) const 2083 { 2084 O.indent(IndentLevel) << "stop_compilation = true;\n"; 2085 } 2086 2087 2088 void onUnpackValues (const DagInit& Dag, 2089 unsigned IndentLevel, raw_ostream& O) const 2090 { 2091 throw "'unpack_values' is deprecated. " 2092 "Use 'comma_separated' + 'forward_value' instead!"; 2093 } 2094 2095 public: 2096 2097 explicit EmitActionHandlersCallback(const OptionDescriptions& OD) 2098 : OptDescs(OD) 2099 { 2100 if (!staticMembersInitialized_) { 2101 AddHandler("error", &EmitActionHandlersCallback::onErrorDag); 2102 AddHandler("warning", &EmitActionHandlersCallback::onWarningDag); 2103 AddHandler("append_cmd", &EmitActionHandlersCallback::onAppendCmd); 2104 AddHandler("forward", &EmitActionHandlersCallback::onForward); 2105 AddHandler("forward_as", &EmitActionHandlersCallback::onForwardAs); 2106 AddHandler("forward_value", &EmitActionHandlersCallback::onForwardValue); 2107 AddHandler("forward_transformed_value", 2108 &EmitActionHandlersCallback::onForwardTransformedValue); 2109 AddHandler("no_out_file", 2110 &EmitActionHandlersCallback::onNoOutFile); 2111 AddHandler("output_suffix", &EmitActionHandlersCallback::onOutputSuffix); 2112 AddHandler("stop_compilation", 2113 &EmitActionHandlersCallback::onStopCompilation); 2114 AddHandler("unpack_values", 2115 &EmitActionHandlersCallback::onUnpackValues); 2116 2117 2118 staticMembersInitialized_ = true; 2119 } 2120 } 2121 2122 void operator()(const Init* I, 2123 unsigned IndentLevel, raw_ostream& O) const 2124 { 2125 InvokeDagInitHandler(this, I, IndentLevel, O); 2126 } 2127 }; 2128 2129 void EmitGenerateActionMethodHeader(const ToolDescription& D, 2130 bool IsJoin, bool Naked, 2131 raw_ostream& O) 2132 { 2133 O.indent(Indent1) << "int GenerateAction(Action& Out,\n"; 2134 2135 if (IsJoin) 2136 O.indent(Indent2) << "const PathVector& inFiles,\n"; 2137 else 2138 O.indent(Indent2) << "const sys::Path& inFile,\n"; 2139 2140 O.indent(Indent2) << "const bool HasChildren,\n"; 2141 O.indent(Indent2) << "const llvm::sys::Path& TempDir,\n"; 2142 O.indent(Indent2) << "const InputLanguagesSet& InLangs,\n"; 2143 O.indent(Indent2) << "const LanguageMap& LangMap) const\n"; 2144 O.indent(Indent1) << "{\n"; 2145 2146 if (!Naked) { 2147 O.indent(Indent2) << "std::string cmd;\n"; 2148 O.indent(Indent2) << "std::string out_file;\n"; 2149 O.indent(Indent2) 2150 << "std::vector<std::pair<unsigned, std::string> > vec;\n"; 2151 O.indent(Indent2) << "bool stop_compilation = !HasChildren;\n"; 2152 O.indent(Indent2) << "bool no_out_file = false;\n"; 2153 O.indent(Indent2) << "std::string output_suffix(\"" 2154 << D.OutputSuffix << "\");\n"; 2155 } 2156 } 2157 2158 // EmitGenerateActionMethod - Emit either a normal or a "join" version of the 2159 // Tool::GenerateAction() method. 2160 void EmitGenerateActionMethod (const ToolDescription& D, 2161 const OptionDescriptions& OptDescs, 2162 bool IsJoin, raw_ostream& O) { 2163 2164 EmitGenerateActionMethodHeader(D, IsJoin, /* Naked = */ false, O); 2165 2166 if (!D.CmdLine) 2167 throw "Tool " + D.Name + " has no cmd_line property!"; 2168 2169 // Process the 'command' property. 2170 O << '\n'; 2171 EmitCmdLineVecFill(D.CmdLine, D.Name, IsJoin, Indent2, O); 2172 O << '\n'; 2173 2174 // Process the 'actions' list of this tool. 2175 if (D.Actions) 2176 EmitCaseConstructHandler(D.Actions, Indent2, 2177 EmitActionHandlersCallback(OptDescs), 2178 false, OptDescs, O); 2179 O << '\n'; 2180 2181 // Input file (s) 2182 if (!D.InFileOption.empty()) { 2183 O.indent(Indent2) 2184 << "vec.push_back(std::make_pair(InputFilenames.getPosition(0), \"" 2185 << D.InFileOption << "\");\n"; 2186 } 2187 2188 if (IsJoin) { 2189 O.indent(Indent2) 2190 << "for (PathVector::const_iterator B = inFiles.begin(),\n"; 2191 O.indent(Indent3) << "E = inFiles.end(); B != E; ++B)\n"; 2192 O.indent(Indent2) << "{\n"; 2193 O.indent(Indent3) << "vec.push_back(std::make_pair(" 2194 << "InputFilenames.getPosition(B - inFiles.begin()), " 2195 << "B->str()));\n"; 2196 O.indent(Indent2) << "}\n"; 2197 } 2198 else { 2199 O.indent(Indent2) << "vec.push_back(std::make_pair(" 2200 << "InputFilenames.getPosition(0), inFile.str()));\n"; 2201 } 2202 2203 // Output file 2204 O.indent(Indent2) << "if (!no_out_file) {\n"; 2205 if (!D.OutFileOption.empty()) 2206 O.indent(Indent3) << "vec.push_back(std::make_pair(65536, \"" 2207 << D.OutFileOption << "\"));\n"; 2208 2209 O.indent(Indent3) << "out_file = this->OutFilename(" 2210 << (IsJoin ? "sys::Path(),\n" : "inFile,\n"); 2211 O.indent(Indent4) << 2212 "TempDir, stop_compilation, output_suffix.c_str()).str();\n\n"; 2213 O.indent(Indent3) << "vec.push_back(std::make_pair(65536, out_file));\n"; 2214 2215 O.indent(Indent2) << "}\n\n"; 2216 2217 // Handle the Sink property. 2218 std::string SinkOption("autogenerated::"); 2219 SinkOption += SinkOptionName; 2220 if (D.isSink()) { 2221 O.indent(Indent2) << "if (!" << SinkOption << ".empty()) {\n"; 2222 O.indent(Indent3) << "for (cl::list<std::string>::iterator B = " 2223 << SinkOption << ".begin(), E = " << SinkOption 2224 << ".end(); B != E; ++B)\n"; 2225 O.indent(Indent4) << "vec.push_back(std::make_pair(" << SinkOption 2226 << ".getPosition(B - " << SinkOption 2227 << ".begin()), *B));\n"; 2228 O.indent(Indent2) << "}\n"; 2229 } 2230 2231 O.indent(Indent2) << "Out.Construct(cmd, this->SortArgs(vec), " 2232 << "stop_compilation, out_file);\n"; 2233 O.indent(Indent2) << "return 0;\n"; 2234 O.indent(Indent1) << "}\n\n"; 2235 } 2236 2237 /// EmitGenerateActionMethods - Emit two GenerateAction() methods for 2238 /// a given Tool class. 2239 void EmitGenerateActionMethods (const ToolDescription& ToolDesc, 2240 const OptionDescriptions& OptDescs, 2241 raw_ostream& O) { 2242 if (!ToolDesc.isJoin()) { 2243 EmitGenerateActionMethodHeader(ToolDesc, /* IsJoin = */ true, 2244 /* Naked = */ true, O); 2245 O.indent(Indent2) << "PrintError(\"" << ToolDesc.Name 2246 << " is not a Join tool!\");\n"; 2247 O.indent(Indent2) << "return -1;\n"; 2248 O.indent(Indent1) << "}\n\n"; 2249 } 2250 else { 2251 EmitGenerateActionMethod(ToolDesc, OptDescs, true, O); 2252 } 2253 2254 EmitGenerateActionMethod(ToolDesc, OptDescs, false, O); 2255 } 2256 2257 /// EmitInOutLanguageMethods - Emit the [Input,Output]Language() 2258 /// methods for a given Tool class. 2259 void EmitInOutLanguageMethods (const ToolDescription& D, raw_ostream& O) { 2260 O.indent(Indent1) << "const char** InputLanguages() const {\n"; 2261 O.indent(Indent2) << "return InputLanguages_;\n"; 2262 O.indent(Indent1) << "}\n\n"; 2263 2264 O.indent(Indent1) << "const char** OutputLanguages() const {\n"; 2265 O.indent(Indent2) << "return OutputLanguages_;\n"; 2266 O.indent(Indent1) << "}\n\n"; 2267 } 2268 2269 /// EmitNameMethod - Emit the Name() method for a given Tool class. 2270 void EmitNameMethod (const ToolDescription& D, raw_ostream& O) { 2271 O.indent(Indent1) << "const char* Name() const {\n"; 2272 O.indent(Indent2) << "return \"" << D.Name << "\";\n"; 2273 O.indent(Indent1) << "}\n\n"; 2274 } 2275 2276 /// EmitIsJoinMethod - Emit the IsJoin() method for a given Tool 2277 /// class. 2278 void EmitIsJoinMethod (const ToolDescription& D, raw_ostream& O) { 2279 O.indent(Indent1) << "bool IsJoin() const {\n"; 2280 if (D.isJoin()) 2281 O.indent(Indent2) << "return true;\n"; 2282 else 2283 O.indent(Indent2) << "return false;\n"; 2284 O.indent(Indent1) << "}\n\n"; 2285 } 2286 2287 /// EmitWorksOnEmptyCallback - Callback used by EmitWorksOnEmptyMethod in 2288 /// conjunction with EmitCaseConstructHandler. 2289 void EmitWorksOnEmptyCallback (const Init* Value, 2290 unsigned IndentLevel, raw_ostream& O) { 2291 CheckBooleanConstant(Value); 2292 O.indent(IndentLevel) << "return " << Value->getAsString() << ";\n"; 2293 } 2294 2295 /// EmitWorksOnEmptyMethod - Emit the WorksOnEmpty() method for a given Tool 2296 /// class. 2297 void EmitWorksOnEmptyMethod (const ToolDescription& D, 2298 const OptionDescriptions& OptDescs, 2299 raw_ostream& O) 2300 { 2301 O.indent(Indent1) << "bool WorksOnEmpty() const {\n"; 2302 if (D.OnEmpty == 0) 2303 O.indent(Indent2) << "return false;\n"; 2304 else 2305 EmitCaseConstructHandler(D.OnEmpty, Indent2, EmitWorksOnEmptyCallback, 2306 /*EmitElseIf = */ true, OptDescs, O); 2307 O.indent(Indent1) << "}\n\n"; 2308 } 2309 2310 /// EmitStrArray - Emit definition of a 'const char**' static member 2311 /// variable. Helper used by EmitStaticMemberDefinitions(); 2312 void EmitStrArray(const std::string& Name, const std::string& VarName, 2313 const StrVector& StrVec, raw_ostream& O) { 2314 O << "const char* " << Name << "::" << VarName << "[] = {"; 2315 for (StrVector::const_iterator B = StrVec.begin(), E = StrVec.end(); 2316 B != E; ++B) 2317 O << '\"' << *B << "\", "; 2318 O << "0};\n"; 2319 } 2320 2321 /// EmitStaticMemberDefinitions - Emit static member definitions for a 2322 /// given Tool class. 2323 void EmitStaticMemberDefinitions(const ToolDescription& D, raw_ostream& O) { 2324 if (D.InLanguage.empty()) 2325 throw "Tool " + D.Name + " has no 'in_language' property!"; 2326 if (D.OutLanguage.empty()) 2327 throw "Tool " + D.Name + " has no 'out_language' property!"; 2328 2329 EmitStrArray(D.Name, "InputLanguages_", D.InLanguage, O); 2330 EmitStrArray(D.Name, "OutputLanguages_", D.OutLanguage, O); 2331 O << '\n'; 2332 } 2333 2334 /// EmitToolClassDefinition - Emit a Tool class definition. 2335 void EmitToolClassDefinition (const ToolDescription& D, 2336 const OptionDescriptions& OptDescs, 2337 raw_ostream& O) { 2338 if (D.Name == "root") 2339 return; 2340 2341 // Header 2342 O << "class " << D.Name << " : public "; 2343 if (D.isJoin()) 2344 O << "JoinTool"; 2345 else 2346 O << "Tool"; 2347 2348 O << " {\nprivate:\n"; 2349 O.indent(Indent1) << "static const char* InputLanguages_[];\n"; 2350 O.indent(Indent1) << "static const char* OutputLanguages_[];\n\n"; 2351 2352 O << "public:\n"; 2353 EmitNameMethod(D, O); 2354 EmitInOutLanguageMethods(D, O); 2355 EmitIsJoinMethod(D, O); 2356 EmitWorksOnEmptyMethod(D, OptDescs, O); 2357 EmitGenerateActionMethods(D, OptDescs, O); 2358 2359 // Close class definition 2360 O << "};\n"; 2361 2362 EmitStaticMemberDefinitions(D, O); 2363 2364 } 2365 2366 /// EmitOptionDefinitions - Iterate over a list of option descriptions 2367 /// and emit registration code. 2368 void EmitOptionDefinitions (const OptionDescriptions& descs, 2369 bool HasSink, raw_ostream& O) 2370 { 2371 std::vector<OptionDescription> Aliases; 2372 2373 // Emit static cl::Option variables. 2374 for (OptionDescriptions::const_iterator B = descs.begin(), 2375 E = descs.end(); B!=E; ++B) { 2376 const OptionDescription& val = B->second; 2377 2378 if (val.Type == OptionType::Alias) { 2379 Aliases.push_back(val); 2380 continue; 2381 } 2382 2383 O << val.GenTypeDeclaration() << ' ' 2384 << val.GenPlainVariableName(); 2385 2386 O << "(\"" << val.Name << "\"\n"; 2387 2388 if (val.Type == OptionType::Prefix || val.Type == OptionType::PrefixList) 2389 O << ", cl::Prefix"; 2390 2391 if (val.isRequired()) { 2392 if (val.isList() && !val.isMultiVal()) 2393 O << ", cl::OneOrMore"; 2394 else 2395 O << ", cl::Required"; 2396 } 2397 2398 if (val.isOptional()) 2399 O << ", cl::Optional"; 2400 2401 if (val.isOneOrMore()) 2402 O << ", cl::OneOrMore"; 2403 2404 if (val.isZeroOrMore()) 2405 O << ", cl::ZeroOrMore"; 2406 2407 if (val.isReallyHidden()) 2408 O << ", cl::ReallyHidden"; 2409 else if (val.isHidden()) 2410 O << ", cl::Hidden"; 2411 2412 if (val.isCommaSeparated()) 2413 O << ", cl::CommaSeparated"; 2414 2415 if (val.MultiVal > 1) 2416 O << ", cl::multi_val(" << val.MultiVal << ')'; 2417 2418 if (val.InitVal) { 2419 const std::string& str = val.InitVal->getAsString(); 2420 O << ", cl::init(" << str << ')'; 2421 } 2422 2423 if (!val.Help.empty()) 2424 O << ", cl::desc(\"" << val.Help << "\")"; 2425 2426 O << ");\n\n"; 2427 } 2428 2429 // Emit the aliases (they should go after all the 'proper' options). 2430 for (std::vector<OptionDescription>::const_iterator 2431 B = Aliases.begin(), E = Aliases.end(); B != E; ++B) { 2432 const OptionDescription& val = *B; 2433 2434 O << val.GenTypeDeclaration() << ' ' 2435 << val.GenPlainVariableName() 2436 << "(\"" << val.Name << '\"'; 2437 2438 const OptionDescription& D = descs.FindOption(val.Help); 2439 O << ", cl::aliasopt(" << D.GenVariableName() << ")"; 2440 2441 O << ", cl::desc(\"" << "An alias for -" + val.Help << "\"));\n"; 2442 } 2443 2444 // Emit the sink option. 2445 if (HasSink) 2446 O << "cl::list<std::string> " << SinkOptionName << "(cl::Sink);\n"; 2447 2448 O << '\n'; 2449 } 2450 2451 /// EmitPreprocessOptionsCallback - Helper function passed to 2452 /// EmitCaseConstructHandler() by EmitPreprocessOptions(). 2453 2454 class EmitPreprocessOptionsCallback; 2455 2456 typedef void 2457 (EmitPreprocessOptionsCallback::* EmitPreprocessOptionsCallbackHandler) 2458 (const DagInit&, unsigned, raw_ostream&) const; 2459 2460 class EmitPreprocessOptionsCallback : 2461 public ActionHandlingCallbackBase, 2462 public HandlerTable<EmitPreprocessOptionsCallbackHandler> 2463 { 2464 typedef EmitPreprocessOptionsCallbackHandler Handler; 2465 typedef void 2466 (EmitPreprocessOptionsCallback::* HandlerImpl) 2467 (const Init*, unsigned, raw_ostream&) const; 2468 2469 const OptionDescriptions& OptDescs_; 2470 2471 void onEachArgument(const DagInit& d, HandlerImpl h, 2472 unsigned IndentLevel, raw_ostream& O) const 2473 { 2474 CheckNumberOfArguments(d, 1); 2475 2476 for (unsigned i = 0, NumArgs = d.getNumArgs(); i < NumArgs; ++i) { 2477 ((this)->*(h))(d.getArg(i), IndentLevel, O); 2478 } 2479 } 2480 2481 void onUnsetOptionImpl(const Init* I, 2482 unsigned IndentLevel, raw_ostream& O) const 2483 { 2484 const std::string& OptName = InitPtrToString(I); 2485 const OptionDescription& OptDesc = OptDescs_.FindOption(OptName); 2486 2487 if (OptDesc.isSwitch()) { 2488 O.indent(IndentLevel) << OptDesc.GenVariableName() << " = false;\n"; 2489 } 2490 else if (OptDesc.isParameter()) { 2491 O.indent(IndentLevel) << OptDesc.GenVariableName() << " = \"\";\n"; 2492 } 2493 else if (OptDesc.isList()) { 2494 O.indent(IndentLevel) << OptDesc.GenVariableName() << ".clear();\n"; 2495 } 2496 else { 2497 throw "Can't apply 'unset_option' to alias option '" + OptName + "'!"; 2498 } 2499 } 2500 2501 void onUnsetOption(const DagInit& d, 2502 unsigned IndentLevel, raw_ostream& O) const 2503 { 2504 this->onEachArgument(d, &EmitPreprocessOptionsCallback::onUnsetOptionImpl, 2505 IndentLevel, O); 2506 } 2507 2508 void onSetOptionImpl(const DagInit& D, 2509 unsigned IndentLevel, raw_ostream& O) const { 2510 CheckNumberOfArguments(D, 2); 2511 2512 const std::string& OptName = InitPtrToString(D.getArg(0)); 2513 const OptionDescription& OptDesc = OptDescs_.FindOption(OptName); 2514 const Init* Value = D.getArg(1); 2515 2516 if (OptDesc.isList()) { 2517 const ListInit& List = InitPtrToList(Value); 2518 2519 O.indent(IndentLevel) << OptDesc.GenVariableName() << ".clear();\n"; 2520 for (ListInit::const_iterator B = List.begin(), E = List.end(); 2521 B != E; ++B) { 2522 const Init* CurElem = *B; 2523 if (OptDesc.isSwitchList()) 2524 CheckBooleanConstant(CurElem); 2525 2526 O.indent(IndentLevel) 2527 << OptDesc.GenVariableName() << ".push_back(\"" 2528 << (OptDesc.isSwitchList() ? CurElem->getAsString() 2529 : InitPtrToString(CurElem)) 2530 << "\");\n"; 2531 } 2532 } 2533 else if (OptDesc.isSwitch()) { 2534 CheckBooleanConstant(Value); 2535 O.indent(IndentLevel) << OptDesc.GenVariableName() 2536 << " = " << Value->getAsString() << ";\n"; 2537 } 2538 else if (OptDesc.isParameter()) { 2539 const std::string& Str = InitPtrToString(Value); 2540 O.indent(IndentLevel) << OptDesc.GenVariableName() 2541 << " = \"" << Str << "\";\n"; 2542 } 2543 else { 2544 throw "Can't apply 'set_option' to alias option '" + OptName + "'!"; 2545 } 2546 } 2547 2548 void onSetSwitch(const Init* I, 2549 unsigned IndentLevel, raw_ostream& O) const { 2550 const std::string& OptName = InitPtrToString(I); 2551 const OptionDescription& OptDesc = OptDescs_.FindOption(OptName); 2552 2553 if (OptDesc.isSwitch()) 2554 O.indent(IndentLevel) << OptDesc.GenVariableName() << " = true;\n"; 2555 else 2556 throw "set_option: -" + OptName + " is not a switch option!"; 2557 } 2558 2559 void onSetOption(const DagInit& d, 2560 unsigned IndentLevel, raw_ostream& O) const 2561 { 2562 CheckNumberOfArguments(d, 1); 2563 2564 // 2-argument form: (set_option "A", true), (set_option "B", "C"), 2565 // (set_option "D", ["E", "F"]) 2566 if (d.getNumArgs() == 2) { 2567 const OptionDescription& OptDesc = 2568 OptDescs_.FindOption(InitPtrToString(d.getArg(0))); 2569 const Init* Opt2 = d.getArg(1); 2570 2571 if (!OptDesc.isSwitch() || typeid(*Opt2) != typeid(StringInit)) { 2572 this->onSetOptionImpl(d, IndentLevel, O); 2573 return; 2574 } 2575 } 2576 2577 // Multiple argument form: (set_option "A"), (set_option "B", "C", "D") 2578 this->onEachArgument(d, &EmitPreprocessOptionsCallback::onSetSwitch, 2579 IndentLevel, O); 2580 } 2581 2582 public: 2583 2584 EmitPreprocessOptionsCallback(const OptionDescriptions& OptDescs) 2585 : OptDescs_(OptDescs) 2586 { 2587 if (!staticMembersInitialized_) { 2588 AddHandler("error", &EmitPreprocessOptionsCallback::onErrorDag); 2589 AddHandler("warning", &EmitPreprocessOptionsCallback::onWarningDag); 2590 AddHandler("unset_option", &EmitPreprocessOptionsCallback::onUnsetOption); 2591 AddHandler("set_option", &EmitPreprocessOptionsCallback::onSetOption); 2592 2593 staticMembersInitialized_ = true; 2594 } 2595 } 2596 2597 void operator()(const Init* I, 2598 unsigned IndentLevel, raw_ostream& O) const 2599 { 2600 InvokeDagInitHandler(this, I, IndentLevel, O); 2601 } 2602 2603 }; 2604 2605 /// EmitPreprocessOptions - Emit the PreprocessOptions() function. 2606 void EmitPreprocessOptions (const RecordKeeper& Records, 2607 const OptionDescriptions& OptDecs, raw_ostream& O) 2608 { 2609 O << "int PreprocessOptions () {\n"; 2610 2611 const RecordVector& OptionPreprocessors = 2612 Records.getAllDerivedDefinitions("OptionPreprocessor"); 2613 2614 for (RecordVector::const_iterator B = OptionPreprocessors.begin(), 2615 E = OptionPreprocessors.end(); B!=E; ++B) { 2616 DagInit* Case = (*B)->getValueAsDag("preprocessor"); 2617 EmitCaseConstructHandler(Case, Indent1, 2618 EmitPreprocessOptionsCallback(OptDecs), 2619 false, OptDecs, O); 2620 } 2621 2622 O << '\n'; 2623 O.indent(Indent1) << "return 0;\n"; 2624 O << "}\n\n"; 2625 } 2626 2627 class DoEmitPopulateLanguageMap; 2628 typedef void (DoEmitPopulateLanguageMap::* DoEmitPopulateLanguageMapHandler) 2629 (const DagInit& D); 2630 2631 class DoEmitPopulateLanguageMap 2632 : public HandlerTable<DoEmitPopulateLanguageMapHandler> 2633 { 2634 private: 2635 raw_ostream& O_; 2636 2637 public: 2638 2639 explicit DoEmitPopulateLanguageMap (raw_ostream& O) : O_(O) { 2640 if (!staticMembersInitialized_) { 2641 AddHandler("lang_to_suffixes", 2642 &DoEmitPopulateLanguageMap::onLangToSuffixes); 2643 2644 staticMembersInitialized_ = true; 2645 } 2646 } 2647 2648 void operator() (Init* I) { 2649 InvokeDagInitHandler(this, I); 2650 } 2651 2652 private: 2653 2654 void onLangToSuffixes (const DagInit& d) { 2655 CheckNumberOfArguments(d, 2); 2656 2657 const std::string& Lang = InitPtrToString(d.getArg(0)); 2658 Init* Suffixes = d.getArg(1); 2659 2660 // Second argument to lang_to_suffixes is either a single string... 2661 if (typeid(*Suffixes) == typeid(StringInit)) { 2662 O_.indent(Indent1) << "langMap[\"" << InitPtrToString(Suffixes) 2663 << "\"] = \"" << Lang << "\";\n"; 2664 } 2665 // ...or a list of strings. 2666 else { 2667 const ListInit& Lst = InitPtrToList(Suffixes); 2668 assert(Lst.size() != 0); 2669 for (ListInit::const_iterator B = Lst.begin(), E = Lst.end(); 2670 B != E; ++B) { 2671 O_.indent(Indent1) << "langMap[\"" << InitPtrToString(*B) 2672 << "\"] = \"" << Lang << "\";\n"; 2673 } 2674 } 2675 } 2676 2677 }; 2678 2679 /// EmitPopulateLanguageMap - Emit the PopulateLanguageMap() function. 2680 void EmitPopulateLanguageMap (const RecordKeeper& Records, raw_ostream& O) 2681 { 2682 O << "int PopulateLanguageMap (LanguageMap& langMap) {\n"; 2683 2684 // For each LanguageMap: 2685 const RecordVector& LangMaps = 2686 Records.getAllDerivedDefinitions("LanguageMap"); 2687 2688 // Call DoEmitPopulateLanguageMap. 2689 for (RecordVector::const_iterator B = LangMaps.begin(), 2690 E = LangMaps.end(); B!=E; ++B) { 2691 ListInit* LangMap = (*B)->getValueAsListInit("map"); 2692 std::for_each(LangMap->begin(), LangMap->end(), 2693 DoEmitPopulateLanguageMap(O)); 2694 } 2695 2696 O << '\n'; 2697 O.indent(Indent1) << "return 0;\n"; 2698 O << "}\n\n"; 2699 } 2700 2701 /// EmitEdgePropertyHandlerCallback - Emits code that handles edge 2702 /// properties. Helper function passed to EmitCaseConstructHandler() by 2703 /// EmitEdgeClass(). 2704 void EmitEdgePropertyHandlerCallback (const Init* i, unsigned IndentLevel, 2705 raw_ostream& O) { 2706 const DagInit& d = InitPtrToDag(i); 2707 const std::string& OpName = GetOperatorName(d); 2708 2709 if (OpName == "inc_weight") { 2710 O.indent(IndentLevel) << "ret += "; 2711 } 2712 else if (OpName == "error") { 2713 CheckNumberOfArguments(d, 1); 2714 O.indent(IndentLevel) << "PrintError(\"" 2715 << InitPtrToString(d.getArg(0)) 2716 << "\");\n"; 2717 O.indent(IndentLevel) << "return -1;\n"; 2718 return; 2719 } 2720 else { 2721 throw "Unknown operator in edge properties list: '" + OpName + "'!" 2722 "\nOnly 'inc_weight', 'dec_weight' and 'error' are allowed."; 2723 } 2724 2725 if (d.getNumArgs() > 0) 2726 O << InitPtrToInt(d.getArg(0)) << ";\n"; 2727 else 2728 O << "2;\n"; 2729 2730 } 2731 2732 /// EmitEdgeClass - Emit a single Edge# class. 2733 void EmitEdgeClass (unsigned N, const std::string& Target, 2734 const DagInit& Case, const OptionDescriptions& OptDescs, 2735 raw_ostream& O) { 2736 2737 // Class constructor. 2738 O << "class Edge" << N << ": public Edge {\n" 2739 << "public:\n"; 2740 O.indent(Indent1) << "Edge" << N << "() : Edge(\"" << Target 2741 << "\") {}\n\n"; 2742 2743 // Function Weight(). 2744 O.indent(Indent1) 2745 << "int Weight(const InputLanguagesSet& InLangs) const {\n"; 2746 O.indent(Indent2) << "unsigned ret = 0;\n"; 2747 2748 // Handle the 'case' construct. 2749 EmitCaseConstructHandler(&Case, Indent2, EmitEdgePropertyHandlerCallback, 2750 false, OptDescs, O); 2751 2752 O.indent(Indent2) << "return ret;\n"; 2753 O.indent(Indent1) << "}\n\n};\n\n"; 2754 } 2755 2756 /// EmitEdgeClasses - Emit Edge* classes that represent graph edges. 2757 void EmitEdgeClasses (const DagVector& EdgeVector, 2758 const OptionDescriptions& OptDescs, 2759 raw_ostream& O) { 2760 int i = 0; 2761 for (DagVector::const_iterator B = EdgeVector.begin(), 2762 E = EdgeVector.end(); B != E; ++B) { 2763 const DagInit& Edge = **B; 2764 const std::string& Name = GetOperatorName(Edge); 2765 2766 if (Name == "optional_edge") { 2767 assert(IsOptionalEdge(Edge)); 2768 const std::string& NodeB = InitPtrToString(Edge.getArg(1)); 2769 2770 const DagInit& Weight = InitPtrToDag(Edge.getArg(2)); 2771 EmitEdgeClass(i, NodeB, Weight, OptDescs, O); 2772 } 2773 else if (Name != "edge") { 2774 throw "Unknown edge class: '" + Name + "'!"; 2775 } 2776 2777 ++i; 2778 } 2779 } 2780 2781 /// EmitPopulateCompilationGraph - Emit the PopulateCompilationGraph() function. 2782 void EmitPopulateCompilationGraph (const DagVector& EdgeVector, 2783 const ToolDescriptions& ToolDescs, 2784 raw_ostream& O) 2785 { 2786 O << "int PopulateCompilationGraph (CompilationGraph& G) {\n"; 2787 2788 for (ToolDescriptions::const_iterator B = ToolDescs.begin(), 2789 E = ToolDescs.end(); B != E; ++B) 2790 O.indent(Indent1) << "G.insertNode(new " << (*B)->Name << "());\n"; 2791 2792 O << '\n'; 2793 2794 // Insert edges. 2795 2796 int i = 0; 2797 for (DagVector::const_iterator B = EdgeVector.begin(), 2798 E = EdgeVector.end(); B != E; ++B) { 2799 const DagInit& Edge = **B; 2800 const std::string& NodeA = InitPtrToString(Edge.getArg(0)); 2801 const std::string& NodeB = InitPtrToString(Edge.getArg(1)); 2802 2803 O.indent(Indent1) << "if (int ret = G.insertEdge(\"" << NodeA << "\", "; 2804 2805 if (IsOptionalEdge(Edge)) 2806 O << "new Edge" << i << "()"; 2807 else 2808 O << "new SimpleEdge(\"" << NodeB << "\")"; 2809 2810 O << "))\n"; 2811 O.indent(Indent2) << "return ret;\n"; 2812 2813 ++i; 2814 } 2815 2816 O << '\n'; 2817 O.indent(Indent1) << "return 0;\n"; 2818 O << "}\n\n"; 2819 } 2820 2821 /// HookInfo - Information about the hook type and number of arguments. 2822 struct HookInfo { 2823 2824 // A hook can either have a single parameter of type std::vector<std::string>, 2825 // or NumArgs parameters of type const char*. 2826 enum HookType { ListHook, ArgHook }; 2827 2828 HookType Type; 2829 unsigned NumArgs; 2830 2831 HookInfo() : Type(ArgHook), NumArgs(1) 2832 {} 2833 2834 HookInfo(HookType T) : Type(T), NumArgs(1) 2835 {} 2836 2837 HookInfo(unsigned N) : Type(ArgHook), NumArgs(N) 2838 {} 2839 }; 2840 2841 typedef llvm::StringMap<HookInfo> HookInfoMap; 2842 2843 /// ExtractHookNames - Extract the hook names from all instances of 2844 /// $CALL(HookName) in the provided command line string/action. Helper 2845 /// function used by FillInHookNames(). 2846 class ExtractHookNames { 2847 HookInfoMap& HookNames_; 2848 const OptionDescriptions& OptDescs_; 2849 public: 2850 ExtractHookNames(HookInfoMap& HookNames, const OptionDescriptions& OptDescs) 2851 : HookNames_(HookNames), OptDescs_(OptDescs) 2852 {} 2853 2854 void onAction (const DagInit& Dag) { 2855 const std::string& Name = GetOperatorName(Dag); 2856 2857 if (Name == "forward_transformed_value") { 2858 CheckNumberOfArguments(Dag, 2); 2859 const std::string& OptName = InitPtrToString(Dag.getArg(0)); 2860 const std::string& HookName = InitPtrToString(Dag.getArg(1)); 2861 const OptionDescription& D = 2862 OptDescs_.FindParameterListOrParameter(OptName); 2863 2864 HookNames_[HookName] = HookInfo(D.isList() ? HookInfo::ListHook 2865 : HookInfo::ArgHook); 2866 } 2867 else if (Name == "append_cmd" || Name == "output_suffix") { 2868 CheckNumberOfArguments(Dag, 1); 2869 this->onCmdLine(InitPtrToString(Dag.getArg(0))); 2870 } 2871 } 2872 2873 void onCmdLine(const std::string& Cmd) { 2874 StrVector cmds; 2875 TokenizeCmdLine(Cmd, cmds); 2876 2877 for (StrVector::const_iterator B = cmds.begin(), E = cmds.end(); 2878 B != E; ++B) { 2879 const std::string& cmd = *B; 2880 2881 if (cmd == "$CALL") { 2882 unsigned NumArgs = 0; 2883 CheckedIncrement(B, E, "Syntax error in $CALL invocation!"); 2884 const std::string& HookName = *B; 2885 2886 if (HookName.at(0) == ')') 2887 throw "$CALL invoked with no arguments!"; 2888 2889 while (++B != E && B->at(0) != ')') { 2890 ++NumArgs; 2891 } 2892 2893 HookInfoMap::const_iterator H = HookNames_.find(HookName); 2894 2895 if (H != HookNames_.end() && H->second.NumArgs != NumArgs && 2896 H->second.Type != HookInfo::ArgHook) 2897 throw "Overloading of hooks is not allowed. Overloaded hook: " 2898 + HookName; 2899 else 2900 HookNames_[HookName] = HookInfo(NumArgs); 2901 } 2902 } 2903 } 2904 2905 void operator()(const Init* Arg) { 2906 2907 // We're invoked on an action (either a dag or a dag list). 2908 if (typeid(*Arg) == typeid(DagInit)) { 2909 const DagInit& Dag = InitPtrToDag(Arg); 2910 this->onAction(Dag); 2911 return; 2912 } 2913 else if (typeid(*Arg) == typeid(ListInit)) { 2914 const ListInit& List = InitPtrToList(Arg); 2915 for (ListInit::const_iterator B = List.begin(), E = List.end(); B != E; 2916 ++B) { 2917 const DagInit& Dag = InitPtrToDag(*B); 2918 this->onAction(Dag); 2919 } 2920 return; 2921 } 2922 2923 // We're invoked on a command line string. 2924 this->onCmdLine(InitPtrToString(Arg)); 2925 } 2926 2927 void operator()(const Init* Statement, unsigned) { 2928 this->operator()(Statement); 2929 } 2930 }; 2931 2932 /// FillInHookNames - Actually extract the hook names from all command 2933 /// line strings. Helper function used by EmitHookDeclarations(). 2934 void FillInHookNames(const ToolDescriptions& ToolDescs, 2935 const OptionDescriptions& OptDescs, 2936 HookInfoMap& HookNames) 2937 { 2938 // For all tool descriptions: 2939 for (ToolDescriptions::const_iterator B = ToolDescs.begin(), 2940 E = ToolDescs.end(); B != E; ++B) { 2941 const ToolDescription& D = *(*B); 2942 2943 // Look for 'forward_transformed_value' in 'actions'. 2944 if (D.Actions) 2945 WalkCase(D.Actions, Id(), ExtractHookNames(HookNames, OptDescs)); 2946 2947 // Look for hook invocations in 'cmd_line'. 2948 if (!D.CmdLine) 2949 continue; 2950 if (dynamic_cast<StringInit*>(D.CmdLine)) 2951 // This is a string. 2952 ExtractHookNames(HookNames, OptDescs).operator()(D.CmdLine); 2953 else 2954 // This is a 'case' construct. 2955 WalkCase(D.CmdLine, Id(), ExtractHookNames(HookNames, OptDescs)); 2956 } 2957 } 2958 2959 /// EmitHookDeclarations - Parse CmdLine fields of all the tool 2960 /// property records and emit hook function declaration for each 2961 /// instance of $CALL(HookName). 2962 void EmitHookDeclarations(const ToolDescriptions& ToolDescs, 2963 const OptionDescriptions& OptDescs, raw_ostream& O) { 2964 HookInfoMap HookNames; 2965 2966 FillInHookNames(ToolDescs, OptDescs, HookNames); 2967 if (HookNames.empty()) 2968 return; 2969 2970 for (HookInfoMap::const_iterator B = HookNames.begin(), 2971 E = HookNames.end(); B != E; ++B) { 2972 StringRef HookName = B->first(); 2973 const HookInfo &Info = B->second; 2974 2975 O.indent(Indent1) << "std::string " << HookName << "("; 2976 2977 if (Info.Type == HookInfo::ArgHook) { 2978 for (unsigned i = 0, j = Info.NumArgs; i < j; ++i) { 2979 O << "const char* Arg" << i << (i+1 == j ? "" : ", "); 2980 } 2981 } 2982 else { 2983 O << "const std::vector<std::string>& Arg"; 2984 } 2985 2986 O <<");\n"; 2987 } 2988 } 2989 2990 /// EmitIncludes - Emit necessary #include directives and some 2991 /// additional declarations. 2992 void EmitIncludes(raw_ostream& O) { 2993 O << "#include \"llvm/CompilerDriver/BuiltinOptions.h\"\n" 2994 << "#include \"llvm/CompilerDriver/CompilationGraph.h\"\n" 2995 << "#include \"llvm/CompilerDriver/Error.h\"\n" 2996 << "#include \"llvm/CompilerDriver/Tool.h\"\n\n" 2997 2998 << "#include \"llvm/Support/CommandLine.h\"\n" 2999 << "#include \"llvm/Support/raw_ostream.h\"\n\n" 3000 3001 << "#include <algorithm>\n" 3002 << "#include <cstdlib>\n" 3003 << "#include <iterator>\n" 3004 << "#include <stdexcept>\n\n" 3005 3006 << "using namespace llvm;\n" 3007 << "using namespace llvmc;\n\n" 3008 3009 << "inline const char* checkCString(const char* s)\n" 3010 << "{ return s == NULL ? \"\" : s; }\n\n"; 3011 } 3012 3013 3014 /// DriverData - Holds all information about the driver. 3015 struct DriverData { 3016 OptionDescriptions OptDescs; 3017 ToolDescriptions ToolDescs; 3018 DagVector Edges; 3019 bool HasSink; 3020 }; 3021 3022 /// HasSink - Go through the list of tool descriptions and check if 3023 /// there are any with the 'sink' property set. 3024 bool HasSink(const ToolDescriptions& ToolDescs) { 3025 for (ToolDescriptions::const_iterator B = ToolDescs.begin(), 3026 E = ToolDescs.end(); B != E; ++B) 3027 if ((*B)->isSink()) 3028 return true; 3029 3030 return false; 3031 } 3032 3033 /// CollectDriverData - Collect compilation graph edges, tool properties and 3034 /// option properties from the parse tree. 3035 void CollectDriverData (const RecordKeeper& Records, DriverData& Data) { 3036 // Collect option properties. 3037 const RecordVector& OptionLists = 3038 Records.getAllDerivedDefinitions("OptionList"); 3039 CollectOptionDescriptions(OptionLists, Data.OptDescs); 3040 3041 // Collect tool properties. 3042 const RecordVector& Tools = Records.getAllDerivedDefinitions("Tool"); 3043 CollectToolDescriptions(Tools, Data.ToolDescs); 3044 Data.HasSink = HasSink(Data.ToolDescs); 3045 3046 // Collect compilation graph edges. 3047 const RecordVector& CompilationGraphs = 3048 Records.getAllDerivedDefinitions("CompilationGraph"); 3049 FillInEdgeVector(CompilationGraphs, Data.Edges); 3050 } 3051 3052 /// CheckDriverData - Perform some sanity checks on the collected data. 3053 void CheckDriverData(DriverData& Data) { 3054 // Filter out all tools not mentioned in the compilation graph. 3055 FilterNotInGraph(Data.Edges, Data.ToolDescs); 3056 3057 // Typecheck the compilation graph. 3058 // TODO: use a genuine graph representation instead of a vector and check for 3059 // multiple edges. 3060 TypecheckGraph(Data.Edges, Data.ToolDescs); 3061 3062 // Check that there are no options without side effects (specified 3063 // only in the OptionList). 3064 CheckForSuperfluousOptions(Data.Edges, Data.ToolDescs, Data.OptDescs); 3065 } 3066 3067 void EmitDriverCode(const DriverData& Data, 3068 raw_ostream& O, RecordKeeper &Records) { 3069 // Emit file header. 3070 EmitIncludes(O); 3071 3072 // Emit global option registration code. 3073 O << "namespace llvmc {\n" 3074 << "namespace autogenerated {\n\n"; 3075 EmitOptionDefinitions(Data.OptDescs, Data.HasSink, O); 3076 O << "} // End namespace autogenerated.\n" 3077 << "} // End namespace llvmc.\n\n"; 3078 3079 // Emit hook declarations. 3080 O << "namespace hooks {\n"; 3081 EmitHookDeclarations(Data.ToolDescs, Data.OptDescs, O); 3082 O << "} // End namespace hooks.\n\n"; 3083 3084 O << "namespace {\n\n"; 3085 O << "using namespace llvmc::autogenerated;\n\n"; 3086 3087 // Emit Tool classes. 3088 for (ToolDescriptions::const_iterator B = Data.ToolDescs.begin(), 3089 E = Data.ToolDescs.end(); B!=E; ++B) 3090 EmitToolClassDefinition(*(*B), Data.OptDescs, O); 3091 3092 // Emit Edge# classes. 3093 EmitEdgeClasses(Data.Edges, Data.OptDescs, O); 3094 3095 O << "} // End anonymous namespace.\n\n"; 3096 3097 O << "namespace llvmc {\n"; 3098 O << "namespace autogenerated {\n\n"; 3099 3100 // Emit PreprocessOptions() function. 3101 EmitPreprocessOptions(Records, Data.OptDescs, O); 3102 3103 // Emit PopulateLanguageMap() function 3104 // (language map maps from file extensions to language names). 3105 EmitPopulateLanguageMap(Records, O); 3106 3107 // Emit PopulateCompilationGraph() function. 3108 EmitPopulateCompilationGraph(Data.Edges, Data.ToolDescs, O); 3109 3110 O << "} // End namespace autogenerated.\n"; 3111 O << "} // End namespace llvmc.\n\n"; 3112 3113 // EOF 3114 } 3115 3116 3117 // End of anonymous namespace 3118 } 3119 3120 /// run - The back-end entry point. 3121 void LLVMCConfigurationEmitter::run (raw_ostream &O) { 3122 try { 3123 DriverData Data; 3124 3125 CollectDriverData(Records, Data); 3126 CheckDriverData(Data); 3127 3128 this->EmitSourceFileHeader("llvmc-based driver: auto-generated code", O); 3129 EmitDriverCode(Data, O, Records); 3130 3131 } catch (std::exception& Error) { 3132 throw Error.what() + std::string(" - usually this means a syntax error."); 3133 } 3134 } 3135