Silence -Wunused-variable in release builds.
[llvm/stm8.git] / utils / TableGen / LLVMCConfigurationEmitter.cpp
blob090faf5085560c7075f09c8e66d2561ccb59f2c9
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.
12 //===----------------------------------------------------------------------===//
14 #include "LLVMCConfigurationEmitter.h"
15 #include "Record.h"
17 #include "llvm/ADT/IntrusiveRefCntPtr.h"
18 #include "llvm/ADT/StringMap.h"
19 #include "llvm/ADT/StringSet.h"
21 #include <algorithm>
22 #include <cassert>
23 #include <functional>
24 #include <stdexcept>
25 #include <string>
26 #include <typeinfo>
29 using namespace llvm;
31 namespace {
33 //===----------------------------------------------------------------------===//
34 /// Typedefs
36 typedef std::vector<Record*> RecordVector;
37 typedef std::vector<const DagInit*> DagVector;
38 typedef std::vector<std::string> StrVector;
40 //===----------------------------------------------------------------------===//
41 /// Constants
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;
50 // Default help string.
51 const char * const DefaultHelpString = "NO HELP MESSAGE PROVIDED";
53 // Name for the "sink" option.
54 const char * const SinkOptionName = "SinkOption";
56 //===----------------------------------------------------------------------===//
57 /// Helper functions
59 /// Id - An 'identity' function object.
60 struct Id {
61 template<typename T0>
62 void operator()(const T0&) const {
64 template<typename T0, typename T1>
65 void operator()(const T0&, const T1&) const {
67 template<typename T0, typename T1, typename T2>
68 void operator()(const T0&, const T1&, const T2&) const {
72 int InitPtrToInt(const Init* ptr) {
73 const IntInit& val = dynamic_cast<const IntInit&>(*ptr);
74 return val.getValue();
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();
82 if (str == "true") {
83 ret = true;
85 else if (str == "false") {
86 ret = false;
88 else {
89 throw "Incorrect boolean value: '" + str +
90 "': must be either 'true' or 'false'";
93 return ret;
96 const std::string& InitPtrToString(const Init* ptr) {
97 const StringInit& val = dynamic_cast<const StringInit&>(*ptr);
98 return val.getValue();
101 const ListInit& InitPtrToList(const Init* ptr) {
102 const ListInit& val = dynamic_cast<const ListInit&>(*ptr);
103 return val;
106 const DagInit& InitPtrToDag(const Init* ptr) {
107 const DagInit& val = dynamic_cast<const DagInit&>(*ptr);
108 return val;
111 const std::string GetOperatorName(const DagInit& D) {
112 return D.getOperator()->getAsString();
115 /// CheckBooleanConstant - Check that the provided value is a boolean constant.
116 void CheckBooleanConstant(const Init* I) {
117 InitPtrToBool(I);
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!";
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_";
137 else if (cur_char == '+') {
138 ret += "_plus_";
140 else if (cur_char == '-') {
141 ret += "_dash_";
143 else {
144 ret.push_back(cur_char);
147 return ret;
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 += "\\\"";
158 else {
159 ret.push_back(cur_char);
162 return ret;
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;
171 return false;
174 template <class I, class S>
175 void CheckedIncrement(I& P, I E, S ErrorString) {
176 ++P;
177 if (P == E)
178 throw ErrorString;
181 //===----------------------------------------------------------------------===//
182 /// Back-end specific code
185 /// OptionType - One of six different option types. See the
186 /// documentation for detailed description of differences.
187 namespace OptionType {
189 enum OptionType { Alias, Switch, SwitchList,
190 Parameter, ParameterList, Prefix, PrefixList };
192 bool IsAlias(OptionType t) {
193 return (t == Alias);
196 bool IsList (OptionType t) {
197 return (t == SwitchList || t == ParameterList || t == PrefixList);
200 bool IsSwitch (OptionType t) {
201 return (t == Switch);
204 bool IsSwitchList (OptionType t) {
205 return (t == SwitchList);
208 bool IsParameter (OptionType t) {
209 return (t == Parameter || t == Prefix);
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 + '!';
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 };
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;
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)
256 /// GenTypeDeclaration - Returns the C++ variable type of this
257 /// option.
258 const char* GenTypeDeclaration() const;
260 /// GenVariableName - Returns the variable name used in the
261 /// generated C++ code.
262 std::string GenVariableName() const
263 { return "autogenerated::" + GenOptionType() + EscapeVariableName(Name); }
265 /// GenPlainVariableName - Returns the variable name without the namespace
266 /// prefix.
267 std::string GenPlainVariableName() const
268 { return GenOptionType() + EscapeVariableName(Name); }
270 /// Merge - Merge two option descriptions.
271 void Merge (const OptionDescription& other);
273 /// CheckConsistency - Check that the flags are consistent.
274 void CheckConsistency() const;
276 // Misc convenient getters/setters.
278 bool isAlias() const;
280 bool isMultiVal() const;
282 bool isCommaSeparated() const;
283 void setCommaSeparated();
285 bool isForwardNotSplit() const;
286 void setForwardNotSplit();
288 bool isRequired() const;
289 void setRequired();
291 bool isOneOrMore() const;
292 void setOneOrMore();
294 bool isZeroOrMore() const;
295 void setZeroOrMore();
297 bool isOptional() const;
298 void setOptional();
300 bool isHidden() const;
301 void setHidden();
303 bool isReallyHidden() const;
304 void setReallyHidden();
306 bool isSwitch() const
307 { return OptionType::IsSwitch(this->Type); }
309 bool isSwitchList() const
310 { return OptionType::IsSwitchList(this->Type); }
312 bool isParameter() const
313 { return OptionType::IsParameter(this->Type); }
315 bool isList() const
316 { return OptionType::IsList(this->Type); }
318 bool isParameterList() const
319 { return (OptionType::IsList(this->Type)
320 && !OptionType::IsSwitchList(this->Type)); }
322 private:
324 // GenOptionType - Helper function used by GenVariableName().
325 std::string GenOptionType() const;
328 void OptionDescription::CheckConsistency() const {
329 unsigned i = 0;
331 i += this->isRequired();
332 i += this->isOptional();
333 i += this->isOneOrMore();
334 i += this->isZeroOrMore();
336 if (i > 1) {
337 throw "Only one of (required), (optional), (one_or_more) or "
338 "(zero_or_more) properties is allowed!";
342 void OptionDescription::Merge (const OptionDescription& other)
344 if (other.Type != Type)
345 throw "Conflicting definitions for the option " + Name + "!";
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";
354 Flags |= other.Flags;
357 bool OptionDescription::isAlias() const {
358 return OptionType::IsAlias(this->Type);
361 bool OptionDescription::isMultiVal() const {
362 return MultiVal > 1;
365 bool OptionDescription::isCommaSeparated() const {
366 return Flags & OptionDescriptionFlags::CommaSeparated;
368 void OptionDescription::setCommaSeparated() {
369 Flags |= OptionDescriptionFlags::CommaSeparated;
372 bool OptionDescription::isForwardNotSplit() const {
373 return Flags & OptionDescriptionFlags::ForwardNotSplit;
375 void OptionDescription::setForwardNotSplit() {
376 Flags |= OptionDescriptionFlags::ForwardNotSplit;
379 bool OptionDescription::isRequired() const {
380 return Flags & OptionDescriptionFlags::Required;
382 void OptionDescription::setRequired() {
383 Flags |= OptionDescriptionFlags::Required;
386 bool OptionDescription::isOneOrMore() const {
387 return Flags & OptionDescriptionFlags::OneOrMore;
389 void OptionDescription::setOneOrMore() {
390 Flags |= OptionDescriptionFlags::OneOrMore;
393 bool OptionDescription::isZeroOrMore() const {
394 return Flags & OptionDescriptionFlags::ZeroOrMore;
396 void OptionDescription::setZeroOrMore() {
397 Flags |= OptionDescriptionFlags::ZeroOrMore;
400 bool OptionDescription::isOptional() const {
401 return Flags & OptionDescriptionFlags::Optional;
403 void OptionDescription::setOptional() {
404 Flags |= OptionDescriptionFlags::Optional;
407 bool OptionDescription::isHidden() const {
408 return Flags & OptionDescriptionFlags::Hidden;
410 void OptionDescription::setHidden() {
411 Flags |= OptionDescriptionFlags::Hidden;
414 bool OptionDescription::isReallyHidden() const {
415 return Flags & OptionDescriptionFlags::ReallyHidden;
417 void OptionDescription::setReallyHidden() {
418 Flags |= OptionDescriptionFlags::ReallyHidden;
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>";
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_";
457 /// OptionDescriptions - An OptionDescription array plus some helper
458 /// functions.
459 class OptionDescriptions {
460 typedef StringMap<OptionDescription> container_type;
462 /// Descriptions - A list of OptionDescriptions.
463 container_type Descriptions;
465 public:
466 /// FindOption - exception-throwing wrapper for find().
467 const OptionDescription& FindOption(const std::string& OptName) const;
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;
479 /// insertDescription - Insert new OptionDescription into
480 /// OptionDescriptions list
481 void InsertDescription (const OptionDescription& o);
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(); }
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!";
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;
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;
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;
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;
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;
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);
547 else {
548 Descriptions[o.Name] = o;
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.
559 /// HandlerMap - A map from property names to property handlers
560 typedef StringMap<Handler> HandlerMap;
562 static HandlerMap Handlers_;
563 static bool staticMembersInitialized_;
565 public:
567 Handler GetHandler (const std::string& HandlerName) const {
568 typename HandlerMap::iterator method = Handlers_.find(HandlerName);
570 if (method != Handlers_.end()) {
571 Handler h = method->second;
572 return h;
574 else {
575 throw "No handler found for property " + HandlerName + "!";
579 void AddHandler(const char* Property, Handler H) {
580 Handlers_[Property] = H;
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);
591 template <class FunctionObject>
592 void InvokeDagInitHandler(FunctionObject* Obj, Init* I) {
593 typedef void (FunctionObject::*Handler) (const DagInit&);
595 const DagInit& Dag = InitPtrToDag(I);
596 Handler h = GetHandler<Handler>(Obj, Dag);
598 ((Obj)->*(h))(Dag);
601 template <class FunctionObject>
602 void InvokeDagInitHandler(const FunctionObject* const Obj,
603 const Init* I, unsigned IndentLevel, raw_ostream& O)
605 typedef void (FunctionObject::*Handler)
606 (const DagInit&, unsigned IndentLevel, raw_ostream& O) const;
608 const DagInit& Dag = InitPtrToDag(I);
609 Handler h = GetHandler<Handler>(Obj, Dag);
611 ((Obj)->*(h))(Dag, IndentLevel, O);
614 template <typename H>
615 typename HandlerTable<H>::HandlerMap HandlerTable<H>::Handlers_;
617 template <typename H>
618 bool HandlerTable<H>::staticMembersInitialized_ = false;
621 /// CollectOptionProperties - Function object for iterating over an
622 /// option property list.
623 class CollectOptionProperties;
624 typedef void (CollectOptionProperties::* CollectOptionPropertiesHandler)
625 (const DagInit&);
627 class CollectOptionProperties
628 : public HandlerTable<CollectOptionPropertiesHandler>
630 private:
632 /// optDescs_ - OptionDescriptions table. This is where the
633 /// information is stored.
634 OptionDescription& optDesc_;
636 public:
638 explicit CollectOptionProperties(OptionDescription& OD)
639 : optDesc_(OD)
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);
655 staticMembersInitialized_ = true;
659 /// operator() - Just forwards to the corresponding property
660 /// handler.
661 void operator() (Init* I) {
662 InvokeDagInitHandler(this, I);
665 private:
667 /// Option property handlers --
668 /// Methods that handle option properties such as (help) or (hidden).
670 void onHelp (const DagInit& d) {
671 CheckNumberOfArguments(d, 1);
672 optDesc_.Help = EscapeQuotes(InitPtrToString(d.getArg(0)));
675 void onHidden (const DagInit& d) {
676 CheckNumberOfArguments(d, 0);
677 optDesc_.setHidden();
680 void onReallyHidden (const DagInit& d) {
681 CheckNumberOfArguments(d, 0);
682 optDesc_.setReallyHidden();
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();
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();
699 void onRequired (const DagInit& d) {
700 CheckNumberOfArguments(d, 0);
702 optDesc_.setRequired();
703 optDesc_.CheckConsistency();
706 void onInit (const DagInit& d) {
707 CheckNumberOfArguments(d, 1);
708 Init* i = d.getArg(0);
709 const std::string& str = i->getAsString();
711 bool correct = optDesc_.isParameter() && dynamic_cast<StringInit*>(i);
712 correct |= (optDesc_.isSwitch() && (str == "true" || str == "false"));
714 if (!correct)
715 throw "Incorrect usage of the 'init' option property!";
717 optDesc_.InitVal = i;
720 void onOneOrMore (const DagInit& d) {
721 CheckNumberOfArguments(d, 0);
723 optDesc_.setOneOrMore();
724 optDesc_.CheckConsistency();
727 void onZeroOrMore (const DagInit& d) {
728 CheckNumberOfArguments(d, 0);
730 if (optDesc_.isList())
731 llvm::errs() << "Warning: specifying the 'zero_or_more' property "
732 "on a list option has no effect.\n";
734 optDesc_.setZeroOrMore();
735 optDesc_.CheckConsistency();
738 void onOptional (const DagInit& d) {
739 CheckNumberOfArguments(d, 0);
741 if (!optDesc_.isList())
742 llvm::errs() << "Warning: specifying the 'optional' property"
743 "on a non-list option has no effect.\n";
745 optDesc_.setOptional();
746 optDesc_.CheckConsistency();
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;
762 /// AddOption - A function object that is applied to every option
763 /// description. Used by CollectOptionDescriptions.
764 class AddOption {
765 private:
766 OptionDescriptions& OptDescs_;
768 public:
769 explicit AddOption(OptionDescriptions& OD) : OptDescs_(OD)
772 void operator()(const Init* i) {
773 const DagInit& d = InitPtrToDag(i);
774 CheckNumberOfArguments(d, 1);
776 const OptionType::OptionType Type =
777 stringToOptionType(GetOperatorName(d));
778 const std::string& Name = InitPtrToString(d.getArg(0));
780 OptionDescription OD(Type, Name);
782 CheckNumberOfArguments(d, 2);
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));
789 else {
790 processOptionProperties(d, OD);
793 // Switch options are ZeroOrMore by default.
794 if (OD.isSwitch()) {
795 if (!(OD.isOptional() || OD.isOneOrMore() || OD.isRequired()))
796 OD.setZeroOrMore();
799 OptDescs_.InsertDescription(OD);
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));
815 /// CollectOptionDescriptions - Collects option properties from all
816 /// OptionLists.
817 void CollectOptionDescriptions (const RecordVector& V,
818 OptionDescriptions& OptDescs)
820 // For every OptionList:
821 for (RecordVector::const_iterator B = V.begin(), E = V.end(); B!=E; ++B)
823 // Throws an exception if the value does not exist.
824 ListInit* PropList = (*B)->getValueAsListInit("options");
826 // For every option description in this list: invoke AddOption.
827 std::for_each(PropList->begin(), PropList->end(), AddOption(OptDescs));
831 // Tool information record
833 namespace ToolFlags {
834 enum ToolFlags { Join = 0x1, Sink = 0x2 };
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;
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; }
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)
863 /// ToolDescriptions - A list of Tool information records.
864 typedef std::vector<IntrusiveRefCntPtr<ToolDescription> > ToolDescriptions;
867 /// CollectToolProperties - Function object for iterating over a list of
868 /// tool property records.
870 class CollectToolProperties;
871 typedef void (CollectToolProperties::* CollectToolPropertiesHandler)
872 (const DagInit&);
874 class CollectToolProperties : public HandlerTable<CollectToolPropertiesHandler>
876 private:
878 /// toolDesc_ - Properties of the current Tool. This is where the
879 /// information is stored.
880 ToolDescription& toolDesc_;
882 public:
884 explicit CollectToolProperties (ToolDescription& d)
885 : toolDesc_(d)
887 if (!staticMembersInitialized_) {
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);
895 AddHandler("out_file_option", &CollectToolProperties::onOutFileOption);
896 AddHandler("in_file_option", &CollectToolProperties::onInFileOption);
898 AddHandler("output_suffix", &CollectToolProperties::onOutputSuffix);
899 AddHandler("sink", &CollectToolProperties::onSink);
900 AddHandler("works_on_empty", &CollectToolProperties::onWorksOnEmpty);
902 staticMembersInitialized_ = true;
906 void operator() (Init* I) {
907 InvokeDagInitHandler(this, I);
910 private:
912 /// Property handlers --
913 /// Functions that extract information about tool properties from
914 /// DAG representation.
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;
925 void onCommand (const DagInit& d) {
926 CheckNumberOfArguments(d, 1);
927 toolDesc_.CmdLine = d.getArg(0);
930 /// onInOutLanguage - Common implementation of on{In,Out}Language().
931 void onInOutLanguage (const DagInit& d, StrVector& OutVec) {
932 CheckNumberOfArguments(d, 1);
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)));
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());
946 void onInLanguage (const DagInit& d) {
947 this->onInOutLanguage(d, toolDesc_.InLanguage);
950 void onJoin (const DagInit& d) {
951 bool isReallyJoin = false;
953 if (d.getNumArgs() == 0) {
954 isReallyJoin = true;
956 else {
957 Init* I = d.getArg(0);
958 isReallyJoin = InitPtrToBool(I);
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();
969 void onOutLanguage (const DagInit& d) {
970 this->onInOutLanguage(d, toolDesc_.OutLanguage);
973 void onOutFileOption (const DagInit& d) {
974 CheckNumberOfArguments(d, 1);
975 toolDesc_.OutFileOption = InitPtrToString(d.getArg(0));
978 void onInFileOption (const DagInit& d) {
979 CheckNumberOfArguments(d, 1);
980 toolDesc_.InFileOption = InitPtrToString(d.getArg(0));
983 void onOutputSuffix (const DagInit& d) {
984 CheckNumberOfArguments(d, 1);
985 toolDesc_.OutputSuffix = InitPtrToString(d.getArg(0));
988 void onSink (const DagInit& d) {
989 CheckNumberOfArguments(d, 0);
990 toolDesc_.setSink();
993 void onWorksOnEmpty (const DagInit& d) {
994 toolDesc_.OnEmpty = d.getArg(0);
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)
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");
1012 IntrusiveRefCntPtr<ToolDescription>
1013 ToolDesc(new ToolDescription(T->getName()));
1015 std::for_each(PropList->begin(), PropList->end(),
1016 CollectToolProperties(*ToolDesc));
1017 ToolDescs.push_back(ToolDesc);
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");
1029 for (ListInit::const_iterator B = Edges->begin(),
1030 E = Edges->end(); B != E; ++B) {
1031 Out.push_back(&InitPtrToDag(*B));
1036 /// NotInGraph - Helper function object for FilterNotInGraph.
1037 struct NotInGraph {
1038 private:
1039 const llvm::StringSet<>& ToolsInGraph_;
1041 public:
1042 NotInGraph(const llvm::StringSet<>& ToolsInGraph)
1043 : ToolsInGraph_(ToolsInGraph)
1046 bool operator()(const IntrusiveRefCntPtr<ToolDescription>& x) {
1047 return (ToolsInGraph_.count(x->Name) == 0);
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) {
1056 // List all tools mentioned in the graph.
1057 llvm::StringSet<> ToolsInGraph;
1059 for (DagVector::const_iterator B = EdgeVector.begin(),
1060 E = EdgeVector.end(); B != E; ++B) {
1062 const DagInit* Edge = *B;
1063 const std::string& NodeA = InitPtrToString(Edge->getArg(0));
1064 const std::string& NodeB = InitPtrToString(Edge->getArg(1));
1066 if (NodeA != "root")
1067 ToolsInGraph.insert(NodeA);
1068 ToolsInGraph.insert(NodeB);
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());
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);
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;
1101 return false;
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;
1111 FillInToolToLang(ToolDescs, ToolToInLang, ToolToOutLang);
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);
1121 if (NodeB == "root")
1122 throw "Edges back to the root are not allowed!";
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!";
1130 if (!Intersect(IA->second, IB->second)) {
1131 throw "Edge " + NodeA + "->" + NodeB
1132 + ": output->input language mismatch";
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)
1150 const DagInit& d = InitPtrToDag(Case);
1152 // Error checks.
1153 if (GetOperatorName(d) != "case")
1154 throw "WalkCase should be invoked only on 'case' expressions!";
1156 if (d.getNumArgs() < 2)
1157 throw "There should be at least one clause in the 'case' expression:\n"
1158 + d.getAsString();
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;
1168 if (!even)
1170 // Handle test.
1171 const DagInit& Test = InitPtrToDag(arg);
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() + '!';
1180 TestCallback(Test, IndentLevel, (i == 1));
1182 else
1184 if (dynamic_cast<DagInit*>(arg)
1185 && GetOperatorName(static_cast<DagInit&>(*arg)) == "case") {
1186 // Nested 'case'.
1187 WalkCase(arg, TestCallback, StatementCallback, IndentLevel + Indent1);
1190 // Handle statement.
1191 StatementCallback(arg, IndentLevel);
1194 ++i;
1195 even = !even;
1199 /// ExtractOptionNames - A helper function object used by
1200 /// CheckForSuperfluousOptions() to walk the 'case' DAG.
1201 class ExtractOptionNames {
1202 llvm::StringSet<>& OptionNames_;
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);
1213 Init* Arg = Stmt.getArg(0);
1214 if (typeid(*Arg) == typeid(StringInit))
1215 OptionNames_.insert(InitPtrToString(Arg));
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));
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));
1233 public:
1234 ExtractOptionNames(llvm::StringSet<>& OptionNames) : OptionNames_(OptionNames)
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);
1245 else {
1246 this->processDag(Statement);
1250 void operator()(const DagInit& Test, unsigned, bool) {
1251 this->operator()(&Test);
1253 void operator()(const Init* Statement, unsigned) {
1254 this->operator()(Statement);
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);
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;
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);
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());
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";
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;
1311 else if (TestName == "multiple_input_files") {
1312 O << "InputFilenames.size() > 1";
1313 return true;
1316 return false;
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)
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);
1332 // Callbacks for use with EmitMultipleArgumentTest
1334 class EmitSwitchOn {
1335 const OptionDescriptions& OptDescs_;
1336 public:
1337 EmitSwitchOn(const OptionDescriptions& OptDescs) : OptDescs_(OptDescs)
1340 void operator()(const std::string& OptName, raw_ostream& O) const {
1341 const OptionDescription& OptDesc = OptDescs_.FindSwitch(OptName);
1342 O << OptDesc.GenVariableName();
1346 class EmitEmptyTest {
1347 bool EmitNegate_;
1348 const OptionDescriptions& OptDescs_;
1349 public:
1350 EmitEmptyTest(bool EmitNegate, const OptionDescriptions& OptDescs)
1351 : EmitNegate_(EmitNegate), OptDescs_(OptDescs)
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()";
1359 else if (OptName == "save-temps") {
1360 O << Neg << "(SaveTemps == SaveTempsEnum::Unset)";
1362 else {
1363 const OptionDescription& OptDesc = OptDescs_.FindListOrParameter(OptName);
1364 O << Neg << OptDesc.GenVariableName() << ".empty()";
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;
1379 else if (TestName == "switch_on") {
1380 EmitMultipleArgumentTest(d, "&&", EmitSwitchOn(OptDescs), O);
1381 return true;
1383 else if (TestName == "any_not_empty") {
1384 EmitMultipleArgumentTest(d, "||", EmitEmptyTest(true, OptDescs), O);
1385 return true;
1387 else if (TestName == "any_empty") {
1388 EmitMultipleArgumentTest(d, "||", EmitEmptyTest(false, OptDescs), O);
1389 return true;
1391 else if (TestName == "not_empty") {
1392 EmitMultipleArgumentTest(d, "&&", EmitEmptyTest(true, OptDescs), O);
1393 return true;
1395 else if (TestName == "empty") {
1396 EmitMultipleArgumentTest(d, "&&", EmitEmptyTest(false, OptDescs), O);
1397 return true;
1400 return false;
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));
1410 if (TestName == "input_languages_contain") {
1411 O << "InLangs.count(\"" << Arg << "\") != 0";
1412 return true;
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.
1418 // TODO: make this work with Edge::Weight (if possible).
1419 O << "LangMap.GetLanguage(inFile) == \"" << Arg << '\"';
1420 return true;
1423 return false;
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);
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));
1447 if (TestName == "parameter_equals") {
1448 const OptionDescription& OptDesc = OptDescs.FindParameter(OptName);
1449 O << OptDesc.GenVariableName() << " == \"" << OptArg << "\"";
1450 return true;
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;
1462 return false;
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);
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 << " (";
1485 else {
1486 O << ')';
1491 void EmitLogicalNot(const DagInit& d, unsigned IndentLevel,
1492 const OptionDescriptions& OptDescs, raw_ostream& O)
1494 CheckNumberOfArguments(d, 1);
1495 const DagInit& InnerTest = InitPtrToDag(d.getArg(0));
1496 O << "! (";
1497 EmitCaseTest(InnerTest, IndentLevel, OptDescs, O);
1498 O << ")";
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);
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!";
1524 /// EmitCaseTestCallback - Callback used by EmitCaseConstructHandler.
1525 class EmitCaseTestCallback {
1526 bool EmitElseIf_;
1527 const OptionDescriptions& OptDescs_;
1528 raw_ostream& O_;
1529 public:
1531 EmitCaseTestCallback(bool EmitElseIf,
1532 const OptionDescriptions& OptDescs, raw_ostream& O)
1533 : EmitElseIf_(EmitElseIf), OptDescs_(OptDescs), O_(O)
1536 void operator()(const DagInit& Test, unsigned IndentLevel, bool FirstTest)
1538 if (GetOperatorName(Test) == "default") {
1539 O_.indent(IndentLevel) << "else {\n";
1541 else {
1542 O_.indent(IndentLevel)
1543 << ((!FirstTest && EmitElseIf_) ? "else if (" : "if (");
1544 EmitCaseTest(Test, IndentLevel, OptDescs_, O_);
1545 O_ << ") {\n";
1550 /// EmitCaseStatementCallback - Callback used by EmitCaseConstructHandler.
1551 template <typename F>
1552 class EmitCaseStatementCallback {
1553 F Callback_;
1554 raw_ostream& O_;
1555 public:
1557 EmitCaseStatementCallback(F Callback, raw_ostream& O)
1558 : Callback_(Callback), O_(O)
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";
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_);
1574 else {
1575 Callback_(Statement, (IndentLevel + Indent1), O_);
1578 O_.indent(IndentLevel) << "}\n";
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);
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;
1609 if (CmdLine.empty())
1610 return;
1611 Out.push_back("");
1613 std::string::size_type B = CmdLine.find_first_not_of(Delimiters),
1614 E = CmdLine.size();
1616 for (; B != E; ++B) {
1617 char cur_ch = CmdLine[B];
1619 switch (cur_st) {
1620 case Normal:
1621 if (cur_ch == '$') {
1622 cur_st = SpecialCommand;
1623 break;
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;
1632 --B;
1633 Out.push_back("");
1634 continue;
1636 break;
1639 case SpecialCommand:
1640 if (OneOf(Delimiters, cur_ch)) {
1641 cur_st = Normal;
1642 Out.push_back("");
1643 continue;
1645 if (cur_ch == '(') {
1646 Out.push_back("");
1647 cur_st = InsideSpecialCommand;
1648 continue;
1650 break;
1652 case InsideSpecialCommand:
1653 if (OneOf(Delimiters, cur_ch)) {
1654 continue;
1656 if (cur_ch == '\'') {
1657 cur_st = InsideQuotationMarks;
1658 Out.push_back("");
1659 continue;
1661 if (cur_ch == ')') {
1662 cur_st = Normal;
1663 Out.push_back("");
1665 if (cur_ch == ',') {
1666 continue;
1669 break;
1671 case InsideQuotationMarks:
1672 if (cur_ch == '\'') {
1673 cur_st = InsideSpecialCommand;
1674 continue;
1676 break;
1679 Out.back().push_back(cur_ch);
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)
1691 const char* errorMessage = "Syntax error in $CALL invocation!";
1692 CheckedIncrement(Pos, End, errorMessage);
1693 const std::string& CmdName = *Pos;
1695 if (CmdName == ")")
1696 throw "$CALL invocation: empty argument list!";
1698 O << "hooks::";
1699 O << CmdName << "(";
1702 bool firstIteration = true;
1703 while (true) {
1704 CheckedIncrement(Pos, End, errorMessage);
1705 const std::string& Arg = *Pos;
1706 assert(Arg.size() != 0);
1708 if (Arg[0] == ')')
1709 break;
1711 if (firstIteration)
1712 firstIteration = false;
1713 else
1714 O << ", ";
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()";
1722 else {
1723 O << '"' << Arg << '"';
1727 O << ')';
1729 return Pos;
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)
1738 const char* errorMessage = "Syntax error in $ENV invocation!";
1739 CheckedIncrement(Pos, End, errorMessage);
1740 const std::string& EnvName = *Pos;
1742 if (EnvName == ")")
1743 throw "$ENV invocation: empty argument list!";
1745 O << "checkCString(std::getenv(\"";
1746 O << EnvName;
1747 O << "\"))";
1749 CheckedIncrement(Pos, End, errorMessage);
1751 return Pos;
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)
1762 const std::string& cmd = *Pos;
1764 // Perform substitution.
1765 if (cmd == "$CALL") {
1766 Pos = SubstituteCall(Pos, End, IsJoin, O);
1768 else if (cmd == "$ENV") {
1769 Pos = SubstituteEnv(Pos, End, O);
1771 else {
1772 throw "Unknown special command: " + cmd;
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) << "\")";
1781 return Pos;
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);
1792 if (StrVec.empty())
1793 throw "Tool '" + ToolName + "' has empty command line!";
1795 StrVector::const_iterator B = StrVec.begin(), E = StrVec.end();
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;
1804 else {
1805 O << '"' << StrVec[0] << '"';
1806 ++B;
1808 O << ";\n";
1810 // Go through the command arguments.
1811 assert(B <= E);
1812 for (; B != E; ++B) {
1813 const std::string& cmd = *B;
1815 assert(!cmd.empty());
1816 O.indent(IndentLevel);
1818 if (cmd.at(0) == '$') {
1819 O << "vec.push_back(std::make_pair(0, ";
1820 B = SubstituteSpecialCommands(B, E, IsJoin, O);
1821 O << "));\n";
1823 else {
1824 O << "vec.push_back(std::make_pair(0, \"" << cmd << "\"));\n";
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;
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";
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;
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;
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";
1877 else {
1878 O << "=\" + " << D.GenVariableName() << "));\n";
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";
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";
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";
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";
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!";
1925 /// ActionHandlingCallbackBase - Base class of EmitActionHandlersCallback and
1926 /// EmitPreprocessOptionsCallback.
1927 struct ActionHandlingCallbackBase
1930 void onErrorDag(const DagInit& d,
1931 unsigned IndentLevel, raw_ostream& O) const
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";
1940 void onWarningDag(const DagInit& d,
1941 unsigned IndentLevel, raw_ostream& O) const
1943 CheckNumberOfArguments(d, 1);
1944 O.indent(IndentLevel) << "llvm::errs() << \""
1945 << InitPtrToString(d.getArg(0)) << "\";\n";
1950 /// EmitActionHandlersCallback - Emit code that handles actions. Used by
1951 /// EmitGenerateActionMethod() as an argument to EmitCaseConstructHandler().
1952 class EmitActionHandlersCallback;
1954 typedef void (EmitActionHandlersCallback::* EmitActionHandlersCallbackHandler)
1955 (const DagInit&, unsigned, raw_ostream&) const;
1957 class EmitActionHandlersCallback :
1958 public ActionHandlingCallbackBase,
1959 public HandlerTable<EmitActionHandlersCallbackHandler>
1961 typedef EmitActionHandlersCallbackHandler Handler;
1963 const OptionDescriptions& OptDescs;
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
1971 StrVector Out;
1972 TokenizeCmdLine(Str, Out);
1974 for (StrVector::const_iterator B = Out.begin(), E = Out.end();
1975 B != E; ++B) {
1976 const std::string& cmd = *B;
1978 O.indent(IndentLevel) << BlockOpen;
1980 if (cmd.at(0) == '$')
1981 B = SubstituteSpecialCommands(B, E, /* IsJoin = */ true, O);
1982 else
1983 O << '"' << cmd << '"';
1985 O << BlockClose;
1989 void onAppendCmd (const DagInit& Dag,
1990 unsigned IndentLevel, raw_ostream& O) const
1992 CheckNumberOfArguments(Dag, 1);
1993 this->EmitHookInvocation(InitPtrToString(Dag.getArg(0)),
1994 "vec.push_back(std::make_pair(65536, ", "));\n",
1995 IndentLevel, O);
1998 void onForward (const DagInit& Dag,
1999 unsigned IndentLevel, raw_ostream& O) const
2001 CheckNumberOfArguments(Dag, 1);
2002 const std::string& Name = InitPtrToString(Dag.getArg(0));
2003 EmitForwardOptionPropertyHandlingCode(OptDescs.FindOption(Name),
2004 IndentLevel, "", O);
2007 void onForwardAs (const DagInit& Dag,
2008 unsigned IndentLevel, raw_ostream& O) const
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);
2017 void onForwardValue (const DagInit& Dag,
2018 unsigned IndentLevel, raw_ostream& O) const
2020 CheckNumberOfArguments(Dag, 1);
2021 const std::string& Name = InitPtrToString(Dag.getArg(0));
2022 const OptionDescription& D = OptDescs.FindParameterListOrParameter(Name);
2024 if (D.isSwitchList()) {
2025 throw std::runtime_error
2026 ("forward_value is not allowed with switch_list");
2029 if (D.isParameter()) {
2030 O.indent(IndentLevel) << "vec.push_back(std::make_pair("
2031 << D.GenVariableName() << ".getPosition(), "
2032 << D.GenVariableName() << "));\n";
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";
2051 void onForwardTransformedValue (const DagInit& Dag,
2052 unsigned IndentLevel, raw_ostream& O) const
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);
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";
2066 void onNoOutFile (const DagInit& Dag,
2067 unsigned IndentLevel, raw_ostream& O) const
2069 CheckNumberOfArguments(Dag, 0);
2070 O.indent(IndentLevel) << "no_out_file = true;\n";
2073 void onOutputSuffix (const DagInit& Dag,
2074 unsigned IndentLevel, raw_ostream& O) const
2076 CheckNumberOfArguments(Dag, 1);
2077 this->EmitHookInvocation(InitPtrToString(Dag.getArg(0)),
2078 "output_suffix = ", ";\n", IndentLevel, O);
2081 void onStopCompilation (const DagInit& Dag,
2082 unsigned IndentLevel, raw_ostream& O) const
2084 O.indent(IndentLevel) << "stop_compilation = true;\n";
2088 void onUnpackValues (const DagInit& Dag,
2089 unsigned IndentLevel, raw_ostream& O) const
2091 throw "'unpack_values' is deprecated. "
2092 "Use 'comma_separated' + 'forward_value' instead!";
2095 public:
2097 explicit EmitActionHandlersCallback(const OptionDescriptions& OD)
2098 : OptDescs(OD)
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);
2118 staticMembersInitialized_ = true;
2122 void operator()(const Init* I,
2123 unsigned IndentLevel, raw_ostream& O) const
2125 InvokeDagInitHandler(this, I, IndentLevel, O);
2129 void EmitGenerateActionMethodHeader(const ToolDescription& D,
2130 bool IsJoin, bool Naked,
2131 raw_ostream& O)
2133 O.indent(Indent1) << "int GenerateAction(Action& Out,\n";
2135 if (IsJoin)
2136 O.indent(Indent2) << "const PathVector& inFiles,\n";
2137 else
2138 O.indent(Indent2) << "const sys::Path& inFile,\n";
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";
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";
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) {
2164 EmitGenerateActionMethodHeader(D, IsJoin, /* Naked = */ false, O);
2166 if (!D.CmdLine)
2167 throw "Tool " + D.Name + " has no cmd_line property!";
2169 // Process the 'command' property.
2170 O << '\n';
2171 EmitCmdLineVecFill(D.CmdLine, D.Name, IsJoin, Indent2, O);
2172 O << '\n';
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';
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";
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";
2198 else {
2199 O.indent(Indent2) << "vec.push_back(std::make_pair("
2200 << "InputFilenames.getPosition(0), inFile.str()));\n";
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";
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";
2215 O.indent(Indent2) << "}\n\n";
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";
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";
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";
2250 else {
2251 EmitGenerateActionMethod(ToolDesc, OptDescs, true, O);
2254 EmitGenerateActionMethod(ToolDesc, OptDescs, false, O);
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";
2264 O.indent(Indent1) << "const char** OutputLanguages() const {\n";
2265 O.indent(Indent2) << "return OutputLanguages_;\n";
2266 O.indent(Indent1) << "}\n\n";
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";
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";
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";
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)
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";
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";
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!";
2329 EmitStrArray(D.Name, "InputLanguages_", D.InLanguage, O);
2330 EmitStrArray(D.Name, "OutputLanguages_", D.OutLanguage, O);
2331 O << '\n';
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;
2341 // Header
2342 O << "class " << D.Name << " : public ";
2343 if (D.isJoin())
2344 O << "JoinTool";
2345 else
2346 O << "Tool";
2348 O << " {\nprivate:\n";
2349 O.indent(Indent1) << "static const char* InputLanguages_[];\n";
2350 O.indent(Indent1) << "static const char* OutputLanguages_[];\n\n";
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);
2359 // Close class definition
2360 O << "};\n";
2362 EmitStaticMemberDefinitions(D, O);
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)
2371 std::vector<OptionDescription> Aliases;
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;
2378 if (val.Type == OptionType::Alias) {
2379 Aliases.push_back(val);
2380 continue;
2383 O << val.GenTypeDeclaration() << ' '
2384 << val.GenPlainVariableName();
2386 O << "(\"" << val.Name << "\"\n";
2388 if (val.Type == OptionType::Prefix || val.Type == OptionType::PrefixList)
2389 O << ", cl::Prefix";
2391 if (val.isRequired()) {
2392 if (val.isList() && !val.isMultiVal())
2393 O << ", cl::OneOrMore";
2394 else
2395 O << ", cl::Required";
2398 if (val.isOptional())
2399 O << ", cl::Optional";
2401 if (val.isOneOrMore())
2402 O << ", cl::OneOrMore";
2404 if (val.isZeroOrMore())
2405 O << ", cl::ZeroOrMore";
2407 if (val.isReallyHidden())
2408 O << ", cl::ReallyHidden";
2409 else if (val.isHidden())
2410 O << ", cl::Hidden";
2412 if (val.isCommaSeparated())
2413 O << ", cl::CommaSeparated";
2415 if (val.MultiVal > 1)
2416 O << ", cl::multi_val(" << val.MultiVal << ')';
2418 if (val.InitVal) {
2419 const std::string& str = val.InitVal->getAsString();
2420 O << ", cl::init(" << str << ')';
2423 if (!val.Help.empty())
2424 O << ", cl::desc(\"" << val.Help << "\")";
2426 O << ");\n\n";
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;
2434 O << val.GenTypeDeclaration() << ' '
2435 << val.GenPlainVariableName()
2436 << "(\"" << val.Name << '\"';
2438 const OptionDescription& D = descs.FindOption(val.Help);
2439 O << ", cl::aliasopt(" << D.GenVariableName() << ")";
2441 O << ", cl::desc(\"" << "An alias for -" + val.Help << "\"));\n";
2444 // Emit the sink option.
2445 if (HasSink)
2446 O << "cl::list<std::string> " << SinkOptionName << "(cl::Sink);\n";
2448 O << '\n';
2451 /// EmitPreprocessOptionsCallback - Helper function passed to
2452 /// EmitCaseConstructHandler() by EmitPreprocessOptions().
2454 class EmitPreprocessOptionsCallback;
2456 typedef void
2457 (EmitPreprocessOptionsCallback::* EmitPreprocessOptionsCallbackHandler)
2458 (const DagInit&, unsigned, raw_ostream&) const;
2460 class EmitPreprocessOptionsCallback :
2461 public ActionHandlingCallbackBase,
2462 public HandlerTable<EmitPreprocessOptionsCallbackHandler>
2464 typedef EmitPreprocessOptionsCallbackHandler Handler;
2465 typedef void
2466 (EmitPreprocessOptionsCallback::* HandlerImpl)
2467 (const Init*, unsigned, raw_ostream&) const;
2469 const OptionDescriptions& OptDescs_;
2471 void onEachArgument(const DagInit& d, HandlerImpl h,
2472 unsigned IndentLevel, raw_ostream& O) const
2474 CheckNumberOfArguments(d, 1);
2476 for (unsigned i = 0, NumArgs = d.getNumArgs(); i < NumArgs; ++i) {
2477 ((this)->*(h))(d.getArg(i), IndentLevel, O);
2481 void onUnsetOptionImpl(const Init* I,
2482 unsigned IndentLevel, raw_ostream& O) const
2484 const std::string& OptName = InitPtrToString(I);
2485 const OptionDescription& OptDesc = OptDescs_.FindOption(OptName);
2487 if (OptDesc.isSwitch()) {
2488 O.indent(IndentLevel) << OptDesc.GenVariableName() << " = false;\n";
2490 else if (OptDesc.isParameter()) {
2491 O.indent(IndentLevel) << OptDesc.GenVariableName() << " = \"\";\n";
2493 else if (OptDesc.isList()) {
2494 O.indent(IndentLevel) << OptDesc.GenVariableName() << ".clear();\n";
2496 else {
2497 throw "Can't apply 'unset_option' to alias option '" + OptName + "'!";
2501 void onUnsetOption(const DagInit& d,
2502 unsigned IndentLevel, raw_ostream& O) const
2504 this->onEachArgument(d, &EmitPreprocessOptionsCallback::onUnsetOptionImpl,
2505 IndentLevel, O);
2508 void onSetOptionImpl(const DagInit& D,
2509 unsigned IndentLevel, raw_ostream& O) const {
2510 CheckNumberOfArguments(D, 2);
2512 const std::string& OptName = InitPtrToString(D.getArg(0));
2513 const OptionDescription& OptDesc = OptDescs_.FindOption(OptName);
2514 const Init* Value = D.getArg(1);
2516 if (OptDesc.isList()) {
2517 const ListInit& List = InitPtrToList(Value);
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);
2526 O.indent(IndentLevel)
2527 << OptDesc.GenVariableName() << ".push_back(\""
2528 << (OptDesc.isSwitchList() ? CurElem->getAsString()
2529 : InitPtrToString(CurElem))
2530 << "\");\n";
2533 else if (OptDesc.isSwitch()) {
2534 CheckBooleanConstant(Value);
2535 O.indent(IndentLevel) << OptDesc.GenVariableName()
2536 << " = " << Value->getAsString() << ";\n";
2538 else if (OptDesc.isParameter()) {
2539 const std::string& Str = InitPtrToString(Value);
2540 O.indent(IndentLevel) << OptDesc.GenVariableName()
2541 << " = \"" << Str << "\";\n";
2543 else {
2544 throw "Can't apply 'set_option' to alias option '" + OptName + "'!";
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);
2553 if (OptDesc.isSwitch())
2554 O.indent(IndentLevel) << OptDesc.GenVariableName() << " = true;\n";
2555 else
2556 throw "set_option: -" + OptName + " is not a switch option!";
2559 void onSetOption(const DagInit& d,
2560 unsigned IndentLevel, raw_ostream& O) const
2562 CheckNumberOfArguments(d, 1);
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);
2571 if (!OptDesc.isSwitch() || typeid(*Opt2) != typeid(StringInit)) {
2572 this->onSetOptionImpl(d, IndentLevel, O);
2573 return;
2577 // Multiple argument form: (set_option "A"), (set_option "B", "C", "D")
2578 this->onEachArgument(d, &EmitPreprocessOptionsCallback::onSetSwitch,
2579 IndentLevel, O);
2582 public:
2584 EmitPreprocessOptionsCallback(const OptionDescriptions& OptDescs)
2585 : OptDescs_(OptDescs)
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);
2593 staticMembersInitialized_ = true;
2597 void operator()(const Init* I,
2598 unsigned IndentLevel, raw_ostream& O) const
2600 InvokeDagInitHandler(this, I, IndentLevel, O);
2605 /// EmitPreprocessOptions - Emit the PreprocessOptions() function.
2606 void EmitPreprocessOptions (const RecordKeeper& Records,
2607 const OptionDescriptions& OptDecs, raw_ostream& O)
2609 O << "int PreprocessOptions () {\n";
2611 const RecordVector& OptionPreprocessors =
2612 Records.getAllDerivedDefinitions("OptionPreprocessor");
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);
2622 O << '\n';
2623 O.indent(Indent1) << "return 0;\n";
2624 O << "}\n\n";
2627 class DoEmitPopulateLanguageMap;
2628 typedef void (DoEmitPopulateLanguageMap::* DoEmitPopulateLanguageMapHandler)
2629 (const DagInit& D);
2631 class DoEmitPopulateLanguageMap
2632 : public HandlerTable<DoEmitPopulateLanguageMapHandler>
2634 private:
2635 raw_ostream& O_;
2637 public:
2639 explicit DoEmitPopulateLanguageMap (raw_ostream& O) : O_(O) {
2640 if (!staticMembersInitialized_) {
2641 AddHandler("lang_to_suffixes",
2642 &DoEmitPopulateLanguageMap::onLangToSuffixes);
2644 staticMembersInitialized_ = true;
2648 void operator() (Init* I) {
2649 InvokeDagInitHandler(this, I);
2652 private:
2654 void onLangToSuffixes (const DagInit& d) {
2655 CheckNumberOfArguments(d, 2);
2657 const std::string& Lang = InitPtrToString(d.getArg(0));
2658 Init* Suffixes = d.getArg(1);
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";
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";
2679 /// EmitPopulateLanguageMap - Emit the PopulateLanguageMap() function.
2680 void EmitPopulateLanguageMap (const RecordKeeper& Records, raw_ostream& O)
2682 O << "int PopulateLanguageMap (LanguageMap& langMap) {\n";
2684 // For each LanguageMap:
2685 const RecordVector& LangMaps =
2686 Records.getAllDerivedDefinitions("LanguageMap");
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));
2696 O << '\n';
2697 O.indent(Indent1) << "return 0;\n";
2698 O << "}\n\n";
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);
2709 if (OpName == "inc_weight") {
2710 O.indent(IndentLevel) << "ret += ";
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;
2720 else {
2721 throw "Unknown operator in edge properties list: '" + OpName + "'!"
2722 "\nOnly 'inc_weight', 'dec_weight' and 'error' are allowed.";
2725 if (d.getNumArgs() > 0)
2726 O << InitPtrToInt(d.getArg(0)) << ";\n";
2727 else
2728 O << "2;\n";
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) {
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";
2743 // Function Weight().
2744 O.indent(Indent1)
2745 << "int Weight(const InputLanguagesSet& InLangs) const {\n";
2746 O.indent(Indent2) << "unsigned ret = 0;\n";
2748 // Handle the 'case' construct.
2749 EmitCaseConstructHandler(&Case, Indent2, EmitEdgePropertyHandlerCallback,
2750 false, OptDescs, O);
2752 O.indent(Indent2) << "return ret;\n";
2753 O.indent(Indent1) << "}\n\n};\n\n";
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);
2766 if (Name == "optional_edge") {
2767 assert(IsOptionalEdge(Edge));
2768 const std::string& NodeB = InitPtrToString(Edge.getArg(1));
2770 const DagInit& Weight = InitPtrToDag(Edge.getArg(2));
2771 EmitEdgeClass(i, NodeB, Weight, OptDescs, O);
2773 else if (Name != "edge") {
2774 throw "Unknown edge class: '" + Name + "'!";
2777 ++i;
2781 /// EmitPopulateCompilationGraph - Emit the PopulateCompilationGraph() function.
2782 void EmitPopulateCompilationGraph (const DagVector& EdgeVector,
2783 const ToolDescriptions& ToolDescs,
2784 raw_ostream& O)
2786 O << "int PopulateCompilationGraph (CompilationGraph& G) {\n";
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";
2792 O << '\n';
2794 // Insert edges.
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));
2803 O.indent(Indent1) << "if (int ret = G.insertEdge(\"" << NodeA << "\", ";
2805 if (IsOptionalEdge(Edge))
2806 O << "new Edge" << i << "()";
2807 else
2808 O << "new SimpleEdge(\"" << NodeB << "\")";
2810 O << "))\n";
2811 O.indent(Indent2) << "return ret;\n";
2813 ++i;
2816 O << '\n';
2817 O.indent(Indent1) << "return 0;\n";
2818 O << "}\n\n";
2821 /// HookInfo - Information about the hook type and number of arguments.
2822 struct HookInfo {
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 };
2828 HookType Type;
2829 unsigned NumArgs;
2831 HookInfo() : Type(ArgHook), NumArgs(1)
2834 HookInfo(HookType T) : Type(T), NumArgs(1)
2837 HookInfo(unsigned N) : Type(ArgHook), NumArgs(N)
2841 typedef llvm::StringMap<HookInfo> HookInfoMap;
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)
2854 void onAction (const DagInit& Dag) {
2855 const std::string& Name = GetOperatorName(Dag);
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);
2864 HookNames_[HookName] = HookInfo(D.isList() ? HookInfo::ListHook
2865 : HookInfo::ArgHook);
2867 else if (Name == "append_cmd" || Name == "output_suffix") {
2868 CheckNumberOfArguments(Dag, 1);
2869 this->onCmdLine(InitPtrToString(Dag.getArg(0)));
2873 void onCmdLine(const std::string& Cmd) {
2874 StrVector cmds;
2875 TokenizeCmdLine(Cmd, cmds);
2877 for (StrVector::const_iterator B = cmds.begin(), E = cmds.end();
2878 B != E; ++B) {
2879 const std::string& cmd = *B;
2881 if (cmd == "$CALL") {
2882 unsigned NumArgs = 0;
2883 CheckedIncrement(B, E, "Syntax error in $CALL invocation!");
2884 const std::string& HookName = *B;
2886 if (HookName.at(0) == ')')
2887 throw "$CALL invoked with no arguments!";
2889 while (++B != E && B->at(0) != ')') {
2890 ++NumArgs;
2893 HookInfoMap::const_iterator H = HookNames_.find(HookName);
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);
2905 void operator()(const Init* Arg) {
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;
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);
2920 return;
2923 // We're invoked on a command line string.
2924 this->onCmdLine(InitPtrToString(Arg));
2927 void operator()(const Init* Statement, unsigned) {
2928 this->operator()(Statement);
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)
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);
2943 // Look for 'forward_transformed_value' in 'actions'.
2944 if (D.Actions)
2945 WalkCase(D.Actions, Id(), ExtractHookNames(HookNames, OptDescs));
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));
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;
2966 FillInHookNames(ToolDescs, OptDescs, HookNames);
2967 if (HookNames.empty())
2968 return;
2970 for (HookInfoMap::const_iterator B = HookNames.begin(),
2971 E = HookNames.end(); B != E; ++B) {
2972 const char* HookName = B->first();
2973 const HookInfo& Info = B->second;
2975 O.indent(Indent1) << "std::string " << HookName << "(";
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 ? "" : ", ");
2982 else {
2983 O << "const std::vector<std::string>& Arg";
2986 O <<");\n";
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"
2998 << "#include \"llvm/Support/CommandLine.h\"\n"
2999 << "#include \"llvm/Support/raw_ostream.h\"\n\n"
3001 << "#include <algorithm>\n"
3002 << "#include <cstdlib>\n"
3003 << "#include <iterator>\n"
3004 << "#include <stdexcept>\n\n"
3006 << "using namespace llvm;\n"
3007 << "using namespace llvmc;\n\n"
3009 << "inline const char* checkCString(const char* s)\n"
3010 << "{ return s == NULL ? \"\" : s; }\n\n";
3014 /// DriverData - Holds all information about the driver.
3015 struct DriverData {
3016 OptionDescriptions OptDescs;
3017 ToolDescriptions ToolDescs;
3018 DagVector Edges;
3019 bool HasSink;
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;
3030 return false;
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);
3041 // Collect tool properties.
3042 const RecordVector& Tools = Records.getAllDerivedDefinitions("Tool");
3043 CollectToolDescriptions(Tools, Data.ToolDescs);
3044 Data.HasSink = HasSink(Data.ToolDescs);
3046 // Collect compilation graph edges.
3047 const RecordVector& CompilationGraphs =
3048 Records.getAllDerivedDefinitions("CompilationGraph");
3049 FillInEdgeVector(CompilationGraphs, Data.Edges);
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);
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);
3062 // Check that there are no options without side effects (specified
3063 // only in the OptionList).
3064 CheckForSuperfluousOptions(Data.Edges, Data.ToolDescs, Data.OptDescs);
3067 void EmitDriverCode(const DriverData& Data,
3068 raw_ostream& O, RecordKeeper &Records) {
3069 // Emit file header.
3070 EmitIncludes(O);
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";
3079 // Emit hook declarations.
3080 O << "namespace hooks {\n";
3081 EmitHookDeclarations(Data.ToolDescs, Data.OptDescs, O);
3082 O << "} // End namespace hooks.\n\n";
3084 O << "namespace {\n\n";
3085 O << "using namespace llvmc::autogenerated;\n\n";
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);
3092 // Emit Edge# classes.
3093 EmitEdgeClasses(Data.Edges, Data.OptDescs, O);
3095 O << "} // End anonymous namespace.\n\n";
3097 O << "namespace llvmc {\n";
3098 O << "namespace autogenerated {\n\n";
3100 // Emit PreprocessOptions() function.
3101 EmitPreprocessOptions(Records, Data.OptDescs, O);
3103 // Emit PopulateLanguageMap() function
3104 // (language map maps from file extensions to language names).
3105 EmitPopulateLanguageMap(Records, O);
3107 // Emit PopulateCompilationGraph() function.
3108 EmitPopulateCompilationGraph(Data.Edges, Data.ToolDescs, O);
3110 O << "} // End namespace autogenerated.\n";
3111 O << "} // End namespace llvmc.\n\n";
3113 // EOF
3117 // End of anonymous namespace
3120 /// run - The back-end entry point.
3121 void LLVMCConfigurationEmitter::run (raw_ostream &O) {
3122 try {
3123 DriverData Data;
3125 CollectDriverData(Records, Data);
3126 CheckDriverData(Data);
3128 this->EmitSourceFileHeader("llvmc-based driver: auto-generated code", O);
3129 EmitDriverCode(Data, O, Records);
3131 } catch (std::exception& Error) {
3132 throw Error.what() + std::string(" - usually this means a syntax error.");