Fixed some bugs.
[llvm/zpu.git] / utils / TableGen / LLVMCConfigurationEmitter.cpp
blobb7ac85c5ed54489488d9516bcfb143fc083dcb73
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 const std::string& InitPtrToString(const Init* ptr) {
78 const StringInit& val = dynamic_cast<const StringInit&>(*ptr);
79 return val.getValue();
82 const ListInit& InitPtrToList(const Init* ptr) {
83 const ListInit& val = dynamic_cast<const ListInit&>(*ptr);
84 return val;
87 const DagInit& InitPtrToDag(const Init* ptr) {
88 const DagInit& val = dynamic_cast<const DagInit&>(*ptr);
89 return val;
92 const std::string GetOperatorName(const DagInit& D) {
93 return D.getOperator()->getAsString();
96 /// CheckBooleanConstant - Check that the provided value is a boolean constant.
97 void CheckBooleanConstant(const Init* I) {
98 const DefInit& val = dynamic_cast<const DefInit&>(*I);
99 const std::string& str = val.getAsString();
101 if (str != "true" && str != "false") {
102 throw "Incorrect boolean value: '" + str +
103 "': must be either 'true' or 'false'";
107 // CheckNumberOfArguments - Ensure that the number of args in d is
108 // greater than or equal to min_arguments, otherwise throw an exception.
109 void CheckNumberOfArguments (const DagInit& d, unsigned minArgs) {
110 if (d.getNumArgs() < minArgs)
111 throw GetOperatorName(d) + ": too few arguments!";
114 // EscapeVariableName - Escape commas and other symbols not allowed
115 // in the C++ variable names. Makes it possible to use options named
116 // like "Wa," (useful for prefix options).
117 std::string EscapeVariableName (const std::string& Var) {
118 std::string ret;
119 for (unsigned i = 0; i != Var.size(); ++i) {
120 char cur_char = Var[i];
121 if (cur_char == ',') {
122 ret += "_comma_";
124 else if (cur_char == '+') {
125 ret += "_plus_";
127 else if (cur_char == '-') {
128 ret += "_dash_";
130 else {
131 ret.push_back(cur_char);
134 return ret;
137 /// EscapeQuotes - Replace '"' with '\"'.
138 std::string EscapeQuotes (const std::string& Var) {
139 std::string ret;
140 for (unsigned i = 0; i != Var.size(); ++i) {
141 char cur_char = Var[i];
142 if (cur_char == '"') {
143 ret += "\\\"";
145 else {
146 ret.push_back(cur_char);
149 return ret;
152 /// OneOf - Does the input string contain this character?
153 bool OneOf(const char* lst, char c) {
154 while (*lst) {
155 if (*lst++ == c)
156 return true;
158 return false;
161 template <class I, class S>
162 void CheckedIncrement(I& P, I E, S ErrorString) {
163 ++P;
164 if (P == E)
165 throw ErrorString;
168 //===----------------------------------------------------------------------===//
169 /// Back-end specific code
172 /// OptionType - One of six different option types. See the
173 /// documentation for detailed description of differences.
174 namespace OptionType {
176 enum OptionType { Alias, Switch, SwitchList,
177 Parameter, ParameterList, Prefix, PrefixList };
179 bool IsAlias(OptionType t) {
180 return (t == Alias);
183 bool IsList (OptionType t) {
184 return (t == SwitchList || t == ParameterList || t == PrefixList);
187 bool IsSwitch (OptionType t) {
188 return (t == Switch);
191 bool IsSwitchList (OptionType t) {
192 return (t == SwitchList);
195 bool IsParameter (OptionType t) {
196 return (t == Parameter || t == Prefix);
201 OptionType::OptionType stringToOptionType(const std::string& T) {
202 if (T == "alias_option")
203 return OptionType::Alias;
204 else if (T == "switch_option")
205 return OptionType::Switch;
206 else if (T == "switch_list_option")
207 return OptionType::SwitchList;
208 else if (T == "parameter_option")
209 return OptionType::Parameter;
210 else if (T == "parameter_list_option")
211 return OptionType::ParameterList;
212 else if (T == "prefix_option")
213 return OptionType::Prefix;
214 else if (T == "prefix_list_option")
215 return OptionType::PrefixList;
216 else
217 throw "Unknown option type: " + T + '!';
220 namespace OptionDescriptionFlags {
221 enum OptionDescriptionFlags { Required = 0x1, Hidden = 0x2,
222 ReallyHidden = 0x4, OneOrMore = 0x8,
223 Optional = 0x10, CommaSeparated = 0x20,
224 ForwardNotSplit = 0x40, ZeroOrMore = 0x80 };
227 /// OptionDescription - Represents data contained in a single
228 /// OptionList entry.
229 struct OptionDescription {
230 OptionType::OptionType Type;
231 std::string Name;
232 unsigned Flags;
233 std::string Help;
234 unsigned MultiVal;
235 Init* InitVal;
237 OptionDescription(OptionType::OptionType t = OptionType::Switch,
238 const std::string& n = "",
239 const std::string& h = DefaultHelpString)
240 : Type(t), Name(n), Flags(0x0), Help(h), MultiVal(1), InitVal(0)
243 /// GenTypeDeclaration - Returns the C++ variable type of this
244 /// option.
245 const char* GenTypeDeclaration() const;
247 /// GenVariableName - Returns the variable name used in the
248 /// generated C++ code.
249 std::string GenVariableName() const
250 { return "autogenerated::" + GenOptionType() + EscapeVariableName(Name); }
252 /// GenPlainVariableName - Returns the variable name without the namespace
253 /// prefix.
254 std::string GenPlainVariableName() const
255 { return GenOptionType() + EscapeVariableName(Name); }
257 /// Merge - Merge two option descriptions.
258 void Merge (const OptionDescription& other);
260 /// CheckConsistency - Check that the flags are consistent.
261 void CheckConsistency() const;
263 // Misc convenient getters/setters.
265 bool isAlias() const;
267 bool isMultiVal() const;
269 bool isCommaSeparated() const;
270 void setCommaSeparated();
272 bool isForwardNotSplit() const;
273 void setForwardNotSplit();
275 bool isRequired() const;
276 void setRequired();
278 bool isOneOrMore() const;
279 void setOneOrMore();
281 bool isZeroOrMore() const;
282 void setZeroOrMore();
284 bool isOptional() const;
285 void setOptional();
287 bool isHidden() const;
288 void setHidden();
290 bool isReallyHidden() const;
291 void setReallyHidden();
293 bool isSwitch() const
294 { return OptionType::IsSwitch(this->Type); }
296 bool isSwitchList() const
297 { return OptionType::IsSwitchList(this->Type); }
299 bool isParameter() const
300 { return OptionType::IsParameter(this->Type); }
302 bool isList() const
303 { return OptionType::IsList(this->Type); }
305 bool isParameterList() const
306 { return (OptionType::IsList(this->Type)
307 && !OptionType::IsSwitchList(this->Type)); }
309 private:
311 // GenOptionType - Helper function used by GenVariableName().
312 std::string GenOptionType() const;
315 void OptionDescription::CheckConsistency() const {
316 unsigned i = 0;
318 i += this->isRequired();
319 i += this->isOptional();
320 i += this->isOneOrMore();
321 i += this->isZeroOrMore();
323 if (i > 1) {
324 throw "Only one of (required), (optional), (one_or_more) or "
325 "(zero_or_more) properties is allowed!";
329 void OptionDescription::Merge (const OptionDescription& other)
331 if (other.Type != Type)
332 throw "Conflicting definitions for the option " + Name + "!";
334 if (Help == other.Help || Help == DefaultHelpString)
335 Help = other.Help;
336 else if (other.Help != DefaultHelpString) {
337 llvm::errs() << "Warning: several different help strings"
338 " defined for option " + Name + "\n";
341 Flags |= other.Flags;
344 bool OptionDescription::isAlias() const {
345 return OptionType::IsAlias(this->Type);
348 bool OptionDescription::isMultiVal() const {
349 return MultiVal > 1;
352 bool OptionDescription::isCommaSeparated() const {
353 return Flags & OptionDescriptionFlags::CommaSeparated;
355 void OptionDescription::setCommaSeparated() {
356 Flags |= OptionDescriptionFlags::CommaSeparated;
359 bool OptionDescription::isForwardNotSplit() const {
360 return Flags & OptionDescriptionFlags::ForwardNotSplit;
362 void OptionDescription::setForwardNotSplit() {
363 Flags |= OptionDescriptionFlags::ForwardNotSplit;
366 bool OptionDescription::isRequired() const {
367 return Flags & OptionDescriptionFlags::Required;
369 void OptionDescription::setRequired() {
370 Flags |= OptionDescriptionFlags::Required;
373 bool OptionDescription::isOneOrMore() const {
374 return Flags & OptionDescriptionFlags::OneOrMore;
376 void OptionDescription::setOneOrMore() {
377 Flags |= OptionDescriptionFlags::OneOrMore;
380 bool OptionDescription::isZeroOrMore() const {
381 return Flags & OptionDescriptionFlags::ZeroOrMore;
383 void OptionDescription::setZeroOrMore() {
384 Flags |= OptionDescriptionFlags::ZeroOrMore;
387 bool OptionDescription::isOptional() const {
388 return Flags & OptionDescriptionFlags::Optional;
390 void OptionDescription::setOptional() {
391 Flags |= OptionDescriptionFlags::Optional;
394 bool OptionDescription::isHidden() const {
395 return Flags & OptionDescriptionFlags::Hidden;
397 void OptionDescription::setHidden() {
398 Flags |= OptionDescriptionFlags::Hidden;
401 bool OptionDescription::isReallyHidden() const {
402 return Flags & OptionDescriptionFlags::ReallyHidden;
404 void OptionDescription::setReallyHidden() {
405 Flags |= OptionDescriptionFlags::ReallyHidden;
408 const char* OptionDescription::GenTypeDeclaration() const {
409 switch (Type) {
410 case OptionType::Alias:
411 return "cl::alias";
412 case OptionType::PrefixList:
413 case OptionType::ParameterList:
414 return "cl::list<std::string>";
415 case OptionType::Switch:
416 return "cl::opt<bool>";
417 case OptionType::SwitchList:
418 return "cl::list<bool>";
419 case OptionType::Parameter:
420 case OptionType::Prefix:
421 default:
422 return "cl::opt<std::string>";
426 std::string OptionDescription::GenOptionType() const {
427 switch (Type) {
428 case OptionType::Alias:
429 return "Alias_";
430 case OptionType::PrefixList:
431 case OptionType::ParameterList:
432 return "List_";
433 case OptionType::Switch:
434 return "Switch_";
435 case OptionType::SwitchList:
436 return "SwitchList_";
437 case OptionType::Prefix:
438 case OptionType::Parameter:
439 default:
440 return "Parameter_";
444 /// OptionDescriptions - An OptionDescription array plus some helper
445 /// functions.
446 class OptionDescriptions {
447 typedef StringMap<OptionDescription> container_type;
449 /// Descriptions - A list of OptionDescriptions.
450 container_type Descriptions;
452 public:
453 /// FindOption - exception-throwing wrapper for find().
454 const OptionDescription& FindOption(const std::string& OptName) const;
456 // Wrappers for FindOption that throw an exception in case the option has a
457 // wrong type.
458 const OptionDescription& FindSwitch(const std::string& OptName) const;
459 const OptionDescription& FindParameter(const std::string& OptName) const;
460 const OptionDescription& FindParameterList(const std::string& OptName) const;
461 const OptionDescription&
462 FindListOrParameter(const std::string& OptName) const;
463 const OptionDescription&
464 FindParameterListOrParameter(const std::string& OptName) const;
466 /// insertDescription - Insert new OptionDescription into
467 /// OptionDescriptions list
468 void InsertDescription (const OptionDescription& o);
470 // Support for STL-style iteration
471 typedef container_type::const_iterator const_iterator;
472 const_iterator begin() const { return Descriptions.begin(); }
473 const_iterator end() const { return Descriptions.end(); }
476 const OptionDescription&
477 OptionDescriptions::FindOption(const std::string& OptName) const {
478 const_iterator I = Descriptions.find(OptName);
479 if (I != Descriptions.end())
480 return I->second;
481 else
482 throw OptName + ": no such option!";
485 const OptionDescription&
486 OptionDescriptions::FindSwitch(const std::string& OptName) const {
487 const OptionDescription& OptDesc = this->FindOption(OptName);
488 if (!OptDesc.isSwitch())
489 throw OptName + ": incorrect option type - should be a switch!";
490 return OptDesc;
493 const OptionDescription&
494 OptionDescriptions::FindParameterList(const std::string& OptName) const {
495 const OptionDescription& OptDesc = this->FindOption(OptName);
496 if (!OptDesc.isList() || OptDesc.isSwitchList())
497 throw OptName + ": incorrect option type - should be a parameter list!";
498 return OptDesc;
501 const OptionDescription&
502 OptionDescriptions::FindParameter(const std::string& OptName) const {
503 const OptionDescription& OptDesc = this->FindOption(OptName);
504 if (!OptDesc.isParameter())
505 throw OptName + ": incorrect option type - should be a parameter!";
506 return OptDesc;
509 const OptionDescription&
510 OptionDescriptions::FindListOrParameter(const std::string& OptName) const {
511 const OptionDescription& OptDesc = this->FindOption(OptName);
512 if (!OptDesc.isList() && !OptDesc.isParameter())
513 throw OptName
514 + ": incorrect option type - should be a list or parameter!";
515 return OptDesc;
518 const OptionDescription&
519 OptionDescriptions::FindParameterListOrParameter
520 (const std::string& OptName) const {
521 const OptionDescription& OptDesc = this->FindOption(OptName);
522 if ((!OptDesc.isList() && !OptDesc.isParameter()) || OptDesc.isSwitchList())
523 throw OptName
524 + ": incorrect option type - should be a parameter list or parameter!";
525 return OptDesc;
528 void OptionDescriptions::InsertDescription (const OptionDescription& o) {
529 container_type::iterator I = Descriptions.find(o.Name);
530 if (I != Descriptions.end()) {
531 OptionDescription& D = I->second;
532 D.Merge(o);
534 else {
535 Descriptions[o.Name] = o;
539 /// HandlerTable - A base class for function objects implemented as
540 /// 'tables of handlers'.
541 template <typename Handler>
542 class HandlerTable {
543 protected:
544 // Implementation details.
546 /// HandlerMap - A map from property names to property handlers
547 typedef StringMap<Handler> HandlerMap;
549 static HandlerMap Handlers_;
550 static bool staticMembersInitialized_;
552 public:
554 Handler GetHandler (const std::string& HandlerName) const {
555 typename HandlerMap::iterator method = Handlers_.find(HandlerName);
557 if (method != Handlers_.end()) {
558 Handler h = method->second;
559 return h;
561 else {
562 throw "No handler found for property " + HandlerName + "!";
566 void AddHandler(const char* Property, Handler H) {
567 Handlers_[Property] = H;
572 template <class Handler, class FunctionObject>
573 Handler GetHandler(FunctionObject* Obj, const DagInit& Dag) {
574 const std::string& HandlerName = GetOperatorName(Dag);
575 return Obj->GetHandler(HandlerName);
578 template <class FunctionObject>
579 void InvokeDagInitHandler(FunctionObject* Obj, Init* I) {
580 typedef void (FunctionObject::*Handler) (const DagInit&);
582 const DagInit& Dag = InitPtrToDag(I);
583 Handler h = GetHandler<Handler>(Obj, Dag);
585 ((Obj)->*(h))(Dag);
588 template <class FunctionObject>
589 void InvokeDagInitHandler(const FunctionObject* const Obj,
590 const Init* I, unsigned IndentLevel, raw_ostream& O)
592 typedef void (FunctionObject::*Handler)
593 (const DagInit&, unsigned IndentLevel, raw_ostream& O) const;
595 const DagInit& Dag = InitPtrToDag(I);
596 Handler h = GetHandler<Handler>(Obj, Dag);
598 ((Obj)->*(h))(Dag, IndentLevel, O);
601 template <typename H>
602 typename HandlerTable<H>::HandlerMap HandlerTable<H>::Handlers_;
604 template <typename H>
605 bool HandlerTable<H>::staticMembersInitialized_ = false;
608 /// CollectOptionProperties - Function object for iterating over an
609 /// option property list.
610 class CollectOptionProperties;
611 typedef void (CollectOptionProperties::* CollectOptionPropertiesHandler)
612 (const DagInit&);
614 class CollectOptionProperties
615 : public HandlerTable<CollectOptionPropertiesHandler>
617 private:
619 /// optDescs_ - OptionDescriptions table. This is where the
620 /// information is stored.
621 OptionDescription& optDesc_;
623 public:
625 explicit CollectOptionProperties(OptionDescription& OD)
626 : optDesc_(OD)
628 if (!staticMembersInitialized_) {
629 AddHandler("help", &CollectOptionProperties::onHelp);
630 AddHandler("hidden", &CollectOptionProperties::onHidden);
631 AddHandler("init", &CollectOptionProperties::onInit);
632 AddHandler("multi_val", &CollectOptionProperties::onMultiVal);
633 AddHandler("one_or_more", &CollectOptionProperties::onOneOrMore);
634 AddHandler("zero_or_more", &CollectOptionProperties::onZeroOrMore);
635 AddHandler("really_hidden", &CollectOptionProperties::onReallyHidden);
636 AddHandler("required", &CollectOptionProperties::onRequired);
637 AddHandler("optional", &CollectOptionProperties::onOptional);
638 AddHandler("comma_separated", &CollectOptionProperties::onCommaSeparated);
639 AddHandler("forward_not_split",
640 &CollectOptionProperties::onForwardNotSplit);
642 staticMembersInitialized_ = true;
646 /// operator() - Just forwards to the corresponding property
647 /// handler.
648 void operator() (Init* I) {
649 InvokeDagInitHandler(this, I);
652 private:
654 /// Option property handlers --
655 /// Methods that handle option properties such as (help) or (hidden).
657 void onHelp (const DagInit& d) {
658 CheckNumberOfArguments(d, 1);
659 optDesc_.Help = EscapeQuotes(InitPtrToString(d.getArg(0)));
662 void onHidden (const DagInit& d) {
663 CheckNumberOfArguments(d, 0);
664 optDesc_.setHidden();
667 void onReallyHidden (const DagInit& d) {
668 CheckNumberOfArguments(d, 0);
669 optDesc_.setReallyHidden();
672 void onCommaSeparated (const DagInit& d) {
673 CheckNumberOfArguments(d, 0);
674 if (!optDesc_.isParameterList())
675 throw "'comma_separated' is valid only on parameter list options!";
676 optDesc_.setCommaSeparated();
679 void onForwardNotSplit (const DagInit& d) {
680 CheckNumberOfArguments(d, 0);
681 if (!optDesc_.isParameter())
682 throw "'forward_not_split' is valid only for parameter options!";
683 optDesc_.setForwardNotSplit();
686 void onRequired (const DagInit& d) {
687 CheckNumberOfArguments(d, 0);
689 optDesc_.setRequired();
690 optDesc_.CheckConsistency();
693 void onInit (const DagInit& d) {
694 CheckNumberOfArguments(d, 1);
695 Init* i = d.getArg(0);
696 const std::string& str = i->getAsString();
698 bool correct = optDesc_.isParameter() && dynamic_cast<StringInit*>(i);
699 correct |= (optDesc_.isSwitch() && (str == "true" || str == "false"));
701 if (!correct)
702 throw "Incorrect usage of the 'init' option property!";
704 optDesc_.InitVal = i;
707 void onOneOrMore (const DagInit& d) {
708 CheckNumberOfArguments(d, 0);
710 optDesc_.setOneOrMore();
711 optDesc_.CheckConsistency();
714 void onZeroOrMore (const DagInit& d) {
715 CheckNumberOfArguments(d, 0);
717 if (optDesc_.isList())
718 llvm::errs() << "Warning: specifying the 'zero_or_more' property "
719 "on a list option has no effect.\n";
721 optDesc_.setZeroOrMore();
722 optDesc_.CheckConsistency();
725 void onOptional (const DagInit& d) {
726 CheckNumberOfArguments(d, 0);
728 if (!optDesc_.isList())
729 llvm::errs() << "Warning: specifying the 'optional' property"
730 "on a non-list option has no effect.\n";
732 optDesc_.setOptional();
733 optDesc_.CheckConsistency();
736 void onMultiVal (const DagInit& d) {
737 CheckNumberOfArguments(d, 1);
738 int val = InitPtrToInt(d.getArg(0));
739 if (val < 2)
740 throw "Error in the 'multi_val' property: "
741 "the value must be greater than 1!";
742 if (!optDesc_.isParameterList())
743 throw "The multi_val property is valid only on list options!";
744 optDesc_.MultiVal = val;
749 /// AddOption - A function object that is applied to every option
750 /// description. Used by CollectOptionDescriptions.
751 class AddOption {
752 private:
753 OptionDescriptions& OptDescs_;
755 public:
756 explicit AddOption(OptionDescriptions& OD) : OptDescs_(OD)
759 void operator()(const Init* i) {
760 const DagInit& d = InitPtrToDag(i);
761 CheckNumberOfArguments(d, 1);
763 const OptionType::OptionType Type =
764 stringToOptionType(GetOperatorName(d));
765 const std::string& Name = InitPtrToString(d.getArg(0));
767 OptionDescription OD(Type, Name);
769 CheckNumberOfArguments(d, 2);
771 if (OD.isAlias()) {
772 // Aliases store the aliased option name in the 'Help' field.
773 OD.Help = InitPtrToString(d.getArg(1));
775 else {
776 processOptionProperties(d, OD);
779 OptDescs_.InsertDescription(OD);
782 private:
783 /// processOptionProperties - Go through the list of option
784 /// properties and call a corresponding handler for each.
785 static void processOptionProperties (const DagInit& d, OptionDescription& o) {
786 CheckNumberOfArguments(d, 2);
787 DagInit::const_arg_iterator B = d.arg_begin();
788 // Skip the first argument: it's always the option name.
789 ++B;
790 std::for_each(B, d.arg_end(), CollectOptionProperties(o));
795 /// CollectOptionDescriptions - Collects option properties from all
796 /// OptionLists.
797 void CollectOptionDescriptions (const RecordVector& V,
798 OptionDescriptions& OptDescs)
800 // For every OptionList:
801 for (RecordVector::const_iterator B = V.begin(), E = V.end(); B!=E; ++B)
803 // Throws an exception if the value does not exist.
804 ListInit* PropList = (*B)->getValueAsListInit("options");
806 // For every option description in this list: invoke AddOption.
807 std::for_each(PropList->begin(), PropList->end(), AddOption(OptDescs));
811 // Tool information record
813 namespace ToolFlags {
814 enum ToolFlags { Join = 0x1, Sink = 0x2 };
817 struct ToolDescription : public RefCountedBase<ToolDescription> {
818 std::string Name;
819 Init* CmdLine;
820 Init* Actions;
821 StrVector InLanguage;
822 std::string InFileOption;
823 std::string OutFileOption;
824 StrVector OutLanguage;
825 std::string OutputSuffix;
826 unsigned Flags;
827 const Init* OnEmpty;
829 // Various boolean properties
830 void setSink() { Flags |= ToolFlags::Sink; }
831 bool isSink() const { return Flags & ToolFlags::Sink; }
832 void setJoin() { Flags |= ToolFlags::Join; }
833 bool isJoin() const { return Flags & ToolFlags::Join; }
835 // Default ctor here is needed because StringMap can only store
836 // DefaultConstructible objects
837 ToolDescription (const std::string &n = "")
838 : Name(n), CmdLine(0), Actions(0), OutFileOption("-o"),
839 Flags(0), OnEmpty(0)
843 /// ToolDescriptions - A list of Tool information records.
844 typedef std::vector<IntrusiveRefCntPtr<ToolDescription> > ToolDescriptions;
847 /// CollectToolProperties - Function object for iterating over a list of
848 /// tool property records.
850 class CollectToolProperties;
851 typedef void (CollectToolProperties::* CollectToolPropertiesHandler)
852 (const DagInit&);
854 class CollectToolProperties : public HandlerTable<CollectToolPropertiesHandler>
856 private:
858 /// toolDesc_ - Properties of the current Tool. This is where the
859 /// information is stored.
860 ToolDescription& toolDesc_;
862 public:
864 explicit CollectToolProperties (ToolDescription& d)
865 : toolDesc_(d)
867 if (!staticMembersInitialized_) {
869 AddHandler("actions", &CollectToolProperties::onActions);
870 AddHandler("command", &CollectToolProperties::onCommand);
871 AddHandler("in_language", &CollectToolProperties::onInLanguage);
872 AddHandler("join", &CollectToolProperties::onJoin);
873 AddHandler("out_language", &CollectToolProperties::onOutLanguage);
875 AddHandler("out_file_option", &CollectToolProperties::onOutFileOption);
876 AddHandler("in_file_option", &CollectToolProperties::onInFileOption);
878 AddHandler("output_suffix", &CollectToolProperties::onOutputSuffix);
879 AddHandler("sink", &CollectToolProperties::onSink);
880 AddHandler("works_on_empty", &CollectToolProperties::onWorksOnEmpty);
882 staticMembersInitialized_ = true;
886 void operator() (Init* I) {
887 InvokeDagInitHandler(this, I);
890 private:
892 /// Property handlers --
893 /// Functions that extract information about tool properties from
894 /// DAG representation.
896 void onActions (const DagInit& d) {
897 CheckNumberOfArguments(d, 1);
898 Init* Case = d.getArg(0);
899 if (typeid(*Case) != typeid(DagInit) ||
900 GetOperatorName(static_cast<DagInit&>(*Case)) != "case")
901 throw "The argument to (actions) should be a 'case' construct!";
902 toolDesc_.Actions = Case;
905 void onCommand (const DagInit& d) {
906 CheckNumberOfArguments(d, 1);
907 toolDesc_.CmdLine = d.getArg(0);
910 /// onInOutLanguage - Common implementation of on{In,Out}Language().
911 void onInOutLanguage (const DagInit& d, StrVector& OutVec) {
912 CheckNumberOfArguments(d, 1);
914 // Copy strings to the output vector.
915 for (unsigned i = 0, NumArgs = d.getNumArgs(); i < NumArgs; ++i) {
916 OutVec.push_back(InitPtrToString(d.getArg(i)));
919 // Remove duplicates.
920 std::sort(OutVec.begin(), OutVec.end());
921 StrVector::iterator newE = std::unique(OutVec.begin(), OutVec.end());
922 OutVec.erase(newE, OutVec.end());
926 void onInLanguage (const DagInit& d) {
927 this->onInOutLanguage(d, toolDesc_.InLanguage);
930 void onJoin (const DagInit& d) {
931 CheckNumberOfArguments(d, 0);
932 toolDesc_.setJoin();
935 void onOutLanguage (const DagInit& d) {
936 this->onInOutLanguage(d, toolDesc_.OutLanguage);
939 void onOutFileOption (const DagInit& d) {
940 CheckNumberOfArguments(d, 1);
941 toolDesc_.OutFileOption = InitPtrToString(d.getArg(0));
944 void onInFileOption (const DagInit& d) {
945 CheckNumberOfArguments(d, 1);
946 toolDesc_.InFileOption = InitPtrToString(d.getArg(0));
949 void onOutputSuffix (const DagInit& d) {
950 CheckNumberOfArguments(d, 1);
951 toolDesc_.OutputSuffix = InitPtrToString(d.getArg(0));
954 void onSink (const DagInit& d) {
955 CheckNumberOfArguments(d, 0);
956 toolDesc_.setSink();
959 void onWorksOnEmpty (const DagInit& d) {
960 toolDesc_.OnEmpty = d.getArg(0);
965 /// CollectToolDescriptions - Gather information about tool properties
966 /// from the parsed TableGen data (basically a wrapper for the
967 /// CollectToolProperties function object).
968 void CollectToolDescriptions (const RecordVector& Tools,
969 ToolDescriptions& ToolDescs)
971 // Iterate over a properties list of every Tool definition
972 for (RecordVector::const_iterator B = Tools.begin(),
973 E = Tools.end(); B!=E; ++B) {
974 const Record* T = *B;
975 // Throws an exception if the value does not exist.
976 ListInit* PropList = T->getValueAsListInit("properties");
978 IntrusiveRefCntPtr<ToolDescription>
979 ToolDesc(new ToolDescription(T->getName()));
981 std::for_each(PropList->begin(), PropList->end(),
982 CollectToolProperties(*ToolDesc));
983 ToolDescs.push_back(ToolDesc);
987 /// FillInEdgeVector - Merge all compilation graph definitions into
988 /// one single edge list.
989 void FillInEdgeVector(const RecordVector& CompilationGraphs,
990 DagVector& Out) {
991 for (RecordVector::const_iterator B = CompilationGraphs.begin(),
992 E = CompilationGraphs.end(); B != E; ++B) {
993 const ListInit* Edges = (*B)->getValueAsListInit("edges");
995 for (ListInit::const_iterator B = Edges->begin(),
996 E = Edges->end(); B != E; ++B) {
997 Out.push_back(&InitPtrToDag(*B));
1002 /// NotInGraph - Helper function object for FilterNotInGraph.
1003 struct NotInGraph {
1004 private:
1005 const llvm::StringSet<>& ToolsInGraph_;
1007 public:
1008 NotInGraph(const llvm::StringSet<>& ToolsInGraph)
1009 : ToolsInGraph_(ToolsInGraph)
1012 bool operator()(const IntrusiveRefCntPtr<ToolDescription>& x) {
1013 return (ToolsInGraph_.count(x->Name) == 0);
1017 /// FilterNotInGraph - Filter out from ToolDescs all Tools not
1018 /// mentioned in the compilation graph definition.
1019 void FilterNotInGraph (const DagVector& EdgeVector,
1020 ToolDescriptions& ToolDescs) {
1022 // List all tools mentioned in the graph.
1023 llvm::StringSet<> ToolsInGraph;
1025 for (DagVector::const_iterator B = EdgeVector.begin(),
1026 E = EdgeVector.end(); B != E; ++B) {
1028 const DagInit* Edge = *B;
1029 const std::string& NodeA = InitPtrToString(Edge->getArg(0));
1030 const std::string& NodeB = InitPtrToString(Edge->getArg(1));
1032 if (NodeA != "root")
1033 ToolsInGraph.insert(NodeA);
1034 ToolsInGraph.insert(NodeB);
1037 // Filter ToolPropertiesList.
1038 ToolDescriptions::iterator new_end =
1039 std::remove_if(ToolDescs.begin(), ToolDescs.end(),
1040 NotInGraph(ToolsInGraph));
1041 ToolDescs.erase(new_end, ToolDescs.end());
1044 /// FillInToolToLang - Fills in two tables that map tool names to
1045 /// input & output language names. Helper function used by TypecheckGraph().
1046 void FillInToolToLang (const ToolDescriptions& ToolDescs,
1047 StringMap<StringSet<> >& ToolToInLang,
1048 StringMap<StringSet<> >& ToolToOutLang) {
1049 for (ToolDescriptions::const_iterator B = ToolDescs.begin(),
1050 E = ToolDescs.end(); B != E; ++B) {
1051 const ToolDescription& D = *(*B);
1052 for (StrVector::const_iterator B = D.InLanguage.begin(),
1053 E = D.InLanguage.end(); B != E; ++B)
1054 ToolToInLang[D.Name].insert(*B);
1055 for (StrVector::const_iterator B = D.OutLanguage.begin(),
1056 E = D.OutLanguage.end(); B != E; ++B)
1057 ToolToOutLang[D.Name].insert(*B);
1061 /// Intersect - Is set intersection non-empty?
1062 bool Intersect (const StringSet<>& S1, const StringSet<>& S2) {
1063 for (StringSet<>::const_iterator B = S1.begin(), E = S1.end(); B != E; ++B) {
1064 if (S2.count(B->first()) != 0)
1065 return true;
1067 return false;
1070 /// TypecheckGraph - Check that names for output and input languages
1071 /// on all edges do match.
1072 void TypecheckGraph (const DagVector& EdgeVector,
1073 const ToolDescriptions& ToolDescs) {
1074 StringMap<StringSet<> > ToolToInLang;
1075 StringMap<StringSet<> > ToolToOutLang;
1077 FillInToolToLang(ToolDescs, ToolToInLang, ToolToOutLang);
1079 for (DagVector::const_iterator B = EdgeVector.begin(),
1080 E = EdgeVector.end(); B != E; ++B) {
1081 const DagInit* Edge = *B;
1082 const std::string& NodeA = InitPtrToString(Edge->getArg(0));
1083 const std::string& NodeB = InitPtrToString(Edge->getArg(1));
1084 StringMap<StringSet<> >::iterator IA = ToolToOutLang.find(NodeA);
1085 StringMap<StringSet<> >::iterator IB = ToolToInLang.find(NodeB);
1087 if (NodeB == "root")
1088 throw "Edges back to the root are not allowed!";
1090 if (NodeA != "root") {
1091 if (IA == ToolToOutLang.end())
1092 throw NodeA + ": no output language defined!";
1093 if (IB == ToolToInLang.end())
1094 throw NodeB + ": no input language defined!";
1096 if (!Intersect(IA->second, IB->second)) {
1097 throw "Edge " + NodeA + "->" + NodeB
1098 + ": output->input language mismatch";
1104 /// WalkCase - Walks the 'case' expression DAG and invokes
1105 /// TestCallback on every test, and StatementCallback on every
1106 /// statement. Handles 'case' nesting, but not the 'and' and 'or'
1107 /// combinators (that is, they are passed directly to TestCallback).
1108 /// TestCallback must have type 'void TestCallback(const DagInit*, unsigned
1109 /// IndentLevel, bool FirstTest)'.
1110 /// StatementCallback must have type 'void StatementCallback(const Init*,
1111 /// unsigned IndentLevel)'.
1112 template <typename F1, typename F2>
1113 void WalkCase(const Init* Case, F1 TestCallback, F2 StatementCallback,
1114 unsigned IndentLevel = 0)
1116 const DagInit& d = InitPtrToDag(Case);
1118 // Error checks.
1119 if (GetOperatorName(d) != "case")
1120 throw "WalkCase should be invoked only on 'case' expressions!";
1122 if (d.getNumArgs() < 2)
1123 throw "There should be at least one clause in the 'case' expression:\n"
1124 + d.getAsString();
1126 // Main loop.
1127 bool even = false;
1128 const unsigned numArgs = d.getNumArgs();
1129 unsigned i = 1;
1130 for (DagInit::const_arg_iterator B = d.arg_begin(), E = d.arg_end();
1131 B != E; ++B) {
1132 Init* arg = *B;
1134 if (!even)
1136 // Handle test.
1137 const DagInit& Test = InitPtrToDag(arg);
1139 if (GetOperatorName(Test) == "default" && (i+1 != numArgs))
1140 throw "The 'default' clause should be the last in the "
1141 "'case' construct!";
1142 if (i == numArgs)
1143 throw "Case construct handler: no corresponding action "
1144 "found for the test " + Test.getAsString() + '!';
1146 TestCallback(Test, IndentLevel, (i == 1));
1148 else
1150 if (dynamic_cast<DagInit*>(arg)
1151 && GetOperatorName(static_cast<DagInit&>(*arg)) == "case") {
1152 // Nested 'case'.
1153 WalkCase(arg, TestCallback, StatementCallback, IndentLevel + Indent1);
1156 // Handle statement.
1157 StatementCallback(arg, IndentLevel);
1160 ++i;
1161 even = !even;
1165 /// ExtractOptionNames - A helper function object used by
1166 /// CheckForSuperfluousOptions() to walk the 'case' DAG.
1167 class ExtractOptionNames {
1168 llvm::StringSet<>& OptionNames_;
1170 void processDag(const Init* Statement) {
1171 const DagInit& Stmt = InitPtrToDag(Statement);
1172 const std::string& ActionName = GetOperatorName(Stmt);
1173 if (ActionName == "forward" || ActionName == "forward_as" ||
1174 ActionName == "forward_value" ||
1175 ActionName == "forward_transformed_value" ||
1176 ActionName == "parameter_equals" || ActionName == "element_in_list") {
1177 CheckNumberOfArguments(Stmt, 1);
1179 Init* Arg = Stmt.getArg(0);
1180 if (typeid(*Arg) == typeid(StringInit))
1181 OptionNames_.insert(InitPtrToString(Arg));
1183 else if (ActionName == "any_switch_on" || ActionName == "switch_on" ||
1184 ActionName == "any_not_empty" || ActionName == "any_empty" ||
1185 ActionName == "not_empty" || ActionName == "empty") {
1186 for (unsigned i = 0, NumArgs = Stmt.getNumArgs(); i < NumArgs; ++i) {
1187 Init* Arg = Stmt.getArg(i);
1188 if (typeid(*Arg) == typeid(StringInit))
1189 OptionNames_.insert(InitPtrToString(Arg));
1192 else if (ActionName == "and" || ActionName == "or" || ActionName == "not") {
1193 for (unsigned i = 0, NumArgs = Stmt.getNumArgs(); i < NumArgs; ++i) {
1194 this->processDag(Stmt.getArg(i));
1199 public:
1200 ExtractOptionNames(llvm::StringSet<>& OptionNames) : OptionNames_(OptionNames)
1203 void operator()(const Init* Statement) {
1204 // Statement is either a dag, or a list of dags.
1205 if (typeid(*Statement) == typeid(ListInit)) {
1206 const ListInit& DagList = *static_cast<const ListInit*>(Statement);
1207 for (ListInit::const_iterator B = DagList.begin(), E = DagList.end();
1208 B != E; ++B)
1209 this->processDag(*B);
1211 else {
1212 this->processDag(Statement);
1216 void operator()(const DagInit& Test, unsigned, bool) {
1217 this->operator()(&Test);
1219 void operator()(const Init* Statement, unsigned) {
1220 this->operator()(Statement);
1224 /// IsOptionalEdge - Validate that the 'optional_edge' has proper structure.
1225 bool IsOptionalEdge (const DagInit& Edg) {
1226 return (GetOperatorName(Edg) == "optional_edge") && (Edg.getNumArgs() > 2);
1229 /// CheckForSuperfluousOptions - Check that there are no side
1230 /// effect-free options (specified only in the OptionList). Otherwise,
1231 /// output a warning.
1232 void CheckForSuperfluousOptions (const DagVector& EdgeVector,
1233 const ToolDescriptions& ToolDescs,
1234 const OptionDescriptions& OptDescs) {
1235 llvm::StringSet<> nonSuperfluousOptions;
1237 // Add all options mentioned in the ToolDesc.Actions to the set of
1238 // non-superfluous options.
1239 for (ToolDescriptions::const_iterator B = ToolDescs.begin(),
1240 E = ToolDescs.end(); B != E; ++B) {
1241 const ToolDescription& TD = *(*B);
1242 ExtractOptionNames Callback(nonSuperfluousOptions);
1243 if (TD.Actions)
1244 WalkCase(TD.Actions, Callback, Callback);
1247 // Add all options mentioned in the 'case' clauses of the
1248 // OptionalEdges of the compilation graph to the set of
1249 // non-superfluous options.
1250 for (DagVector::const_iterator B = EdgeVector.begin(),
1251 E = EdgeVector.end(); B != E; ++B) {
1252 const DagInit& Edge = **B;
1253 if (IsOptionalEdge(Edge)) {
1254 const DagInit& Weight = InitPtrToDag(Edge.getArg(2));
1255 WalkCase(&Weight, ExtractOptionNames(nonSuperfluousOptions), Id());
1259 // Check that all options in OptDescs belong to the set of
1260 // non-superfluous options.
1261 for (OptionDescriptions::const_iterator B = OptDescs.begin(),
1262 E = OptDescs.end(); B != E; ++B) {
1263 const OptionDescription& Val = B->second;
1264 if (!nonSuperfluousOptions.count(Val.Name)
1265 && Val.Type != OptionType::Alias)
1266 llvm::errs() << "Warning: option '-" << Val.Name << "' has no effect! "
1267 "Probable cause: this option is specified only in the OptionList.\n";
1271 /// EmitCaseTest0Args - Helper function used by EmitCaseConstructHandler().
1272 bool EmitCaseTest0Args(const std::string& TestName, raw_ostream& O) {
1273 if (TestName == "single_input_file") {
1274 O << "InputFilenames.size() == 1";
1275 return true;
1277 else if (TestName == "multiple_input_files") {
1278 O << "InputFilenames.size() > 1";
1279 return true;
1282 return false;
1285 /// EmitMultipleArgumentTest - Helper function used by
1286 /// EmitCaseTestMultipleArgs()
1287 template <typename F>
1288 void EmitMultipleArgumentTest(const DagInit& D, const char* LogicOp,
1289 F Callback, raw_ostream& O)
1291 for (unsigned i = 0, NumArgs = D.getNumArgs(); i < NumArgs; ++i) {
1292 if (i != 0)
1293 O << ' ' << LogicOp << ' ';
1294 Callback(InitPtrToString(D.getArg(i)), O);
1298 // Callbacks for use with EmitMultipleArgumentTest
1300 class EmitSwitchOn {
1301 const OptionDescriptions& OptDescs_;
1302 public:
1303 EmitSwitchOn(const OptionDescriptions& OptDescs) : OptDescs_(OptDescs)
1306 void operator()(const std::string& OptName, raw_ostream& O) const {
1307 const OptionDescription& OptDesc = OptDescs_.FindSwitch(OptName);
1308 O << OptDesc.GenVariableName();
1312 class EmitEmptyTest {
1313 bool EmitNegate_;
1314 const OptionDescriptions& OptDescs_;
1315 public:
1316 EmitEmptyTest(bool EmitNegate, const OptionDescriptions& OptDescs)
1317 : EmitNegate_(EmitNegate), OptDescs_(OptDescs)
1320 void operator()(const std::string& OptName, raw_ostream& O) const {
1321 const char* Neg = (EmitNegate_ ? "!" : "");
1322 if (OptName == "o") {
1323 O << Neg << "OutputFilename.empty()";
1325 else if (OptName == "save-temps") {
1326 O << Neg << "(SaveTemps == SaveTempsEnum::Unset)";
1328 else {
1329 const OptionDescription& OptDesc = OptDescs_.FindListOrParameter(OptName);
1330 O << Neg << OptDesc.GenVariableName() << ".empty()";
1336 /// EmitCaseTestMultipleArgs - Helper function used by EmitCaseTest1Arg()
1337 bool EmitCaseTestMultipleArgs (const std::string& TestName,
1338 const DagInit& d,
1339 const OptionDescriptions& OptDescs,
1340 raw_ostream& O) {
1341 if (TestName == "any_switch_on") {
1342 EmitMultipleArgumentTest(d, "||", EmitSwitchOn(OptDescs), O);
1343 return true;
1345 else if (TestName == "switch_on") {
1346 EmitMultipleArgumentTest(d, "&&", EmitSwitchOn(OptDescs), O);
1347 return true;
1349 else if (TestName == "any_not_empty") {
1350 EmitMultipleArgumentTest(d, "||", EmitEmptyTest(true, OptDescs), O);
1351 return true;
1353 else if (TestName == "any_empty") {
1354 EmitMultipleArgumentTest(d, "||", EmitEmptyTest(false, OptDescs), O);
1355 return true;
1357 else if (TestName == "not_empty") {
1358 EmitMultipleArgumentTest(d, "&&", EmitEmptyTest(true, OptDescs), O);
1359 return true;
1361 else if (TestName == "empty") {
1362 EmitMultipleArgumentTest(d, "&&", EmitEmptyTest(false, OptDescs), O);
1363 return true;
1366 return false;
1369 /// EmitCaseTest1Arg - Helper function used by EmitCaseTest1OrMoreArgs()
1370 bool EmitCaseTest1Arg (const std::string& TestName,
1371 const DagInit& d,
1372 const OptionDescriptions& OptDescs,
1373 raw_ostream& O) {
1374 const std::string& Arg = InitPtrToString(d.getArg(0));
1376 if (TestName == "input_languages_contain") {
1377 O << "InLangs.count(\"" << Arg << "\") != 0";
1378 return true;
1380 else if (TestName == "in_language") {
1381 // This works only for single-argument Tool::GenerateAction. Join
1382 // tools can process several files in different languages simultaneously.
1384 // TODO: make this work with Edge::Weight (if possible).
1385 O << "LangMap.GetLanguage(inFile) == \"" << Arg << '\"';
1386 return true;
1389 return false;
1392 /// EmitCaseTest1OrMoreArgs - Helper function used by
1393 /// EmitCaseConstructHandler()
1394 bool EmitCaseTest1OrMoreArgs(const std::string& TestName,
1395 const DagInit& d,
1396 const OptionDescriptions& OptDescs,
1397 raw_ostream& O) {
1398 CheckNumberOfArguments(d, 1);
1399 return EmitCaseTest1Arg(TestName, d, OptDescs, O) ||
1400 EmitCaseTestMultipleArgs(TestName, d, OptDescs, O);
1403 /// EmitCaseTest2Args - Helper function used by EmitCaseConstructHandler().
1404 bool EmitCaseTest2Args(const std::string& TestName,
1405 const DagInit& d,
1406 unsigned IndentLevel,
1407 const OptionDescriptions& OptDescs,
1408 raw_ostream& O) {
1409 CheckNumberOfArguments(d, 2);
1410 const std::string& OptName = InitPtrToString(d.getArg(0));
1411 const std::string& OptArg = InitPtrToString(d.getArg(1));
1413 if (TestName == "parameter_equals") {
1414 const OptionDescription& OptDesc = OptDescs.FindParameter(OptName);
1415 O << OptDesc.GenVariableName() << " == \"" << OptArg << "\"";
1416 return true;
1418 else if (TestName == "element_in_list") {
1419 const OptionDescription& OptDesc = OptDescs.FindParameterList(OptName);
1420 const std::string& VarName = OptDesc.GenVariableName();
1421 O << "std::find(" << VarName << ".begin(),\n";
1422 O.indent(IndentLevel + Indent1)
1423 << VarName << ".end(), \""
1424 << OptArg << "\") != " << VarName << ".end()";
1425 return true;
1428 return false;
1431 // Forward declaration.
1432 // EmitLogicalOperationTest and EmitCaseTest are mutually recursive.
1433 void EmitCaseTest(const DagInit& d, unsigned IndentLevel,
1434 const OptionDescriptions& OptDescs,
1435 raw_ostream& O);
1437 /// EmitLogicalOperationTest - Helper function used by
1438 /// EmitCaseConstructHandler.
1439 void EmitLogicalOperationTest(const DagInit& d, const char* LogicOp,
1440 unsigned IndentLevel,
1441 const OptionDescriptions& OptDescs,
1442 raw_ostream& O) {
1443 O << '(';
1444 for (unsigned i = 0, NumArgs = d.getNumArgs(); i < NumArgs; ++i) {
1445 const DagInit& InnerTest = InitPtrToDag(d.getArg(i));
1446 EmitCaseTest(InnerTest, IndentLevel, OptDescs, O);
1447 if (i != NumArgs - 1) {
1448 O << ")\n";
1449 O.indent(IndentLevel + Indent1) << ' ' << LogicOp << " (";
1451 else {
1452 O << ')';
1457 void EmitLogicalNot(const DagInit& d, unsigned IndentLevel,
1458 const OptionDescriptions& OptDescs, raw_ostream& O)
1460 CheckNumberOfArguments(d, 1);
1461 const DagInit& InnerTest = InitPtrToDag(d.getArg(0));
1462 O << "! (";
1463 EmitCaseTest(InnerTest, IndentLevel, OptDescs, O);
1464 O << ")";
1467 /// EmitCaseTest - Helper function used by EmitCaseConstructHandler.
1468 void EmitCaseTest(const DagInit& d, unsigned IndentLevel,
1469 const OptionDescriptions& OptDescs,
1470 raw_ostream& O) {
1471 const std::string& TestName = GetOperatorName(d);
1473 if (TestName == "and")
1474 EmitLogicalOperationTest(d, "&&", IndentLevel, OptDescs, O);
1475 else if (TestName == "or")
1476 EmitLogicalOperationTest(d, "||", IndentLevel, OptDescs, O);
1477 else if (TestName == "not")
1478 EmitLogicalNot(d, IndentLevel, OptDescs, O);
1479 else if (EmitCaseTest0Args(TestName, O))
1480 return;
1481 else if (EmitCaseTest1OrMoreArgs(TestName, d, OptDescs, O))
1482 return;
1483 else if (EmitCaseTest2Args(TestName, d, IndentLevel, OptDescs, O))
1484 return;
1485 else
1486 throw "Unknown test '" + TestName + "' used in the 'case' construct!";
1490 /// EmitCaseTestCallback - Callback used by EmitCaseConstructHandler.
1491 class EmitCaseTestCallback {
1492 bool EmitElseIf_;
1493 const OptionDescriptions& OptDescs_;
1494 raw_ostream& O_;
1495 public:
1497 EmitCaseTestCallback(bool EmitElseIf,
1498 const OptionDescriptions& OptDescs, raw_ostream& O)
1499 : EmitElseIf_(EmitElseIf), OptDescs_(OptDescs), O_(O)
1502 void operator()(const DagInit& Test, unsigned IndentLevel, bool FirstTest)
1504 if (GetOperatorName(Test) == "default") {
1505 O_.indent(IndentLevel) << "else {\n";
1507 else {
1508 O_.indent(IndentLevel)
1509 << ((!FirstTest && EmitElseIf_) ? "else if (" : "if (");
1510 EmitCaseTest(Test, IndentLevel, OptDescs_, O_);
1511 O_ << ") {\n";
1516 /// EmitCaseStatementCallback - Callback used by EmitCaseConstructHandler.
1517 template <typename F>
1518 class EmitCaseStatementCallback {
1519 F Callback_;
1520 raw_ostream& O_;
1521 public:
1523 EmitCaseStatementCallback(F Callback, raw_ostream& O)
1524 : Callback_(Callback), O_(O)
1527 void operator() (const Init* Statement, unsigned IndentLevel) {
1528 // Is this a nested 'case'?
1529 bool IsCase = dynamic_cast<const DagInit*>(Statement) &&
1530 GetOperatorName(static_cast<const DagInit&>(*Statement)) == "case";
1532 // If so, ignore it, it is handled by our caller, WalkCase.
1533 if (!IsCase) {
1534 if (typeid(*Statement) == typeid(ListInit)) {
1535 const ListInit& DagList = *static_cast<const ListInit*>(Statement);
1536 for (ListInit::const_iterator B = DagList.begin(), E = DagList.end();
1537 B != E; ++B)
1538 Callback_(*B, (IndentLevel + Indent1), O_);
1540 else {
1541 Callback_(Statement, (IndentLevel + Indent1), O_);
1544 O_.indent(IndentLevel) << "}\n";
1549 /// EmitCaseConstructHandler - Emit code that handles the 'case'
1550 /// construct. Takes a function object that should emit code for every case
1551 /// clause. Implemented on top of WalkCase.
1552 /// Callback's type is void F(const Init* Statement, unsigned IndentLevel,
1553 /// raw_ostream& O).
1554 /// EmitElseIf parameter controls the type of condition that is emitted ('if
1555 /// (..) {..} else if (..) {} .. else {..}' vs. 'if (..) {..} if(..) {..}
1556 /// .. else {..}').
1557 template <typename F>
1558 void EmitCaseConstructHandler(const Init* Case, unsigned IndentLevel,
1559 F Callback, bool EmitElseIf,
1560 const OptionDescriptions& OptDescs,
1561 raw_ostream& O) {
1562 WalkCase(Case, EmitCaseTestCallback(EmitElseIf, OptDescs, O),
1563 EmitCaseStatementCallback<F>(Callback, O), IndentLevel);
1566 /// TokenizeCmdLine - converts from
1567 /// "$CALL(HookName, 'Arg1', 'Arg2')/path -arg1 -arg2" to
1568 /// ["$CALL(", "HookName", "Arg1", "Arg2", ")/path", "-arg1", "-arg2"].
1569 void TokenizeCmdLine(const std::string& CmdLine, StrVector& Out) {
1570 const char* Delimiters = " \t\n\v\f\r";
1571 enum TokenizerState
1572 { Normal, SpecialCommand, InsideSpecialCommand, InsideQuotationMarks }
1573 cur_st = Normal;
1575 if (CmdLine.empty())
1576 return;
1577 Out.push_back("");
1579 std::string::size_type B = CmdLine.find_first_not_of(Delimiters),
1580 E = CmdLine.size();
1582 for (; B != E; ++B) {
1583 char cur_ch = CmdLine[B];
1585 switch (cur_st) {
1586 case Normal:
1587 if (cur_ch == '$') {
1588 cur_st = SpecialCommand;
1589 break;
1591 if (OneOf(Delimiters, cur_ch)) {
1592 // Skip whitespace
1593 B = CmdLine.find_first_not_of(Delimiters, B);
1594 if (B == std::string::npos) {
1595 B = E-1;
1596 continue;
1598 --B;
1599 Out.push_back("");
1600 continue;
1602 break;
1605 case SpecialCommand:
1606 if (OneOf(Delimiters, cur_ch)) {
1607 cur_st = Normal;
1608 Out.push_back("");
1609 continue;
1611 if (cur_ch == '(') {
1612 Out.push_back("");
1613 cur_st = InsideSpecialCommand;
1614 continue;
1616 break;
1618 case InsideSpecialCommand:
1619 if (OneOf(Delimiters, cur_ch)) {
1620 continue;
1622 if (cur_ch == '\'') {
1623 cur_st = InsideQuotationMarks;
1624 Out.push_back("");
1625 continue;
1627 if (cur_ch == ')') {
1628 cur_st = Normal;
1629 Out.push_back("");
1631 if (cur_ch == ',') {
1632 continue;
1635 break;
1637 case InsideQuotationMarks:
1638 if (cur_ch == '\'') {
1639 cur_st = InsideSpecialCommand;
1640 continue;
1642 break;
1645 Out.back().push_back(cur_ch);
1649 /// SubstituteCall - Given "$CALL(HookName, [Arg1 [, Arg2 [...]]])", output
1650 /// "hooks::HookName([Arg1 [, Arg2 [, ...]]])". Helper function used by
1651 /// SubstituteSpecialCommands().
1652 StrVector::const_iterator
1653 SubstituteCall (StrVector::const_iterator Pos,
1654 StrVector::const_iterator End,
1655 bool IsJoin, raw_ostream& O)
1657 const char* errorMessage = "Syntax error in $CALL invocation!";
1658 CheckedIncrement(Pos, End, errorMessage);
1659 const std::string& CmdName = *Pos;
1661 if (CmdName == ")")
1662 throw "$CALL invocation: empty argument list!";
1664 O << "hooks::";
1665 O << CmdName << "(";
1668 bool firstIteration = true;
1669 while (true) {
1670 CheckedIncrement(Pos, End, errorMessage);
1671 const std::string& Arg = *Pos;
1672 assert(Arg.size() != 0);
1674 if (Arg[0] == ')')
1675 break;
1677 if (firstIteration)
1678 firstIteration = false;
1679 else
1680 O << ", ";
1682 if (Arg == "$INFILE") {
1683 if (IsJoin)
1684 throw "$CALL(Hook, $INFILE) can't be used with a Join tool!";
1685 else
1686 O << "inFile.c_str()";
1688 else {
1689 O << '"' << Arg << '"';
1693 O << ')';
1695 return Pos;
1698 /// SubstituteEnv - Given '$ENV(VAR_NAME)', output 'getenv("VAR_NAME")'. Helper
1699 /// function used by SubstituteSpecialCommands().
1700 StrVector::const_iterator
1701 SubstituteEnv (StrVector::const_iterator Pos,
1702 StrVector::const_iterator End, raw_ostream& O)
1704 const char* errorMessage = "Syntax error in $ENV invocation!";
1705 CheckedIncrement(Pos, End, errorMessage);
1706 const std::string& EnvName = *Pos;
1708 if (EnvName == ")")
1709 throw "$ENV invocation: empty argument list!";
1711 O << "checkCString(std::getenv(\"";
1712 O << EnvName;
1713 O << "\"))";
1715 CheckedIncrement(Pos, End, errorMessage);
1717 return Pos;
1720 /// SubstituteSpecialCommands - Given an invocation of $CALL or $ENV, output
1721 /// handler code. Helper function used by EmitCmdLineVecFill().
1722 StrVector::const_iterator
1723 SubstituteSpecialCommands (StrVector::const_iterator Pos,
1724 StrVector::const_iterator End,
1725 bool IsJoin, raw_ostream& O)
1728 const std::string& cmd = *Pos;
1730 // Perform substitution.
1731 if (cmd == "$CALL") {
1732 Pos = SubstituteCall(Pos, End, IsJoin, O);
1734 else if (cmd == "$ENV") {
1735 Pos = SubstituteEnv(Pos, End, O);
1737 else {
1738 throw "Unknown special command: " + cmd;
1741 // Handle '$CMD(ARG)/additional/text'.
1742 const std::string& Leftover = *Pos;
1743 assert(Leftover.at(0) == ')');
1744 if (Leftover.size() != 1)
1745 O << " + std::string(\"" << (Leftover.c_str() + 1) << "\")";
1747 return Pos;
1750 /// EmitCmdLineVecFill - Emit code that fills in the command line
1751 /// vector. Helper function used by EmitGenerateActionMethod().
1752 void EmitCmdLineVecFill(const Init* CmdLine, const std::string& ToolName,
1753 bool IsJoin, unsigned IndentLevel,
1754 raw_ostream& O) {
1755 StrVector StrVec;
1756 TokenizeCmdLine(InitPtrToString(CmdLine), StrVec);
1758 if (StrVec.empty())
1759 throw "Tool '" + ToolName + "' has empty command line!";
1761 StrVector::const_iterator B = StrVec.begin(), E = StrVec.end();
1763 // Emit the command itself.
1764 assert(!StrVec[0].empty());
1765 O.indent(IndentLevel) << "cmd = ";
1766 if (StrVec[0][0] == '$') {
1767 B = SubstituteSpecialCommands(B, E, IsJoin, O);
1768 ++B;
1770 else {
1771 O << '"' << StrVec[0] << '"';
1772 ++B;
1774 O << ";\n";
1776 // Go through the command arguments.
1777 assert(B <= E);
1778 for (; B != E; ++B) {
1779 const std::string& cmd = *B;
1781 assert(!cmd.empty());
1782 O.indent(IndentLevel);
1784 if (cmd.at(0) == '$') {
1785 O << "vec.push_back(std::make_pair(0, ";
1786 B = SubstituteSpecialCommands(B, E, IsJoin, O);
1787 O << "));\n";
1789 else {
1790 O << "vec.push_back(std::make_pair(0, \"" << cmd << "\"));\n";
1796 /// EmitForEachListElementCycleHeader - Emit common code for iterating through
1797 /// all elements of a list. Helper function used by
1798 /// EmitForwardOptionPropertyHandlingCode.
1799 void EmitForEachListElementCycleHeader (const OptionDescription& D,
1800 unsigned IndentLevel,
1801 raw_ostream& O) {
1802 unsigned IndentLevel1 = IndentLevel + Indent1;
1804 O.indent(IndentLevel)
1805 << "for (" << D.GenTypeDeclaration()
1806 << "::iterator B = " << D.GenVariableName() << ".begin(),\n";
1807 O.indent(IndentLevel)
1808 << "E = " << D.GenVariableName() << ".end(); B != E;) {\n";
1809 O.indent(IndentLevel1) << "unsigned pos = " << D.GenVariableName()
1810 << ".getPosition(B - " << D.GenVariableName()
1811 << ".begin());\n";
1814 /// EmitForwardOptionPropertyHandlingCode - Helper function used to
1815 /// implement EmitActionHandler. Emits code for
1816 /// handling the (forward) and (forward_as) option properties.
1817 void EmitForwardOptionPropertyHandlingCode (const OptionDescription& D,
1818 unsigned IndentLevel,
1819 const std::string& NewName,
1820 raw_ostream& O) {
1821 const std::string& Name = NewName.empty()
1822 ? ("-" + D.Name)
1823 : NewName;
1824 unsigned IndentLevel1 = IndentLevel + Indent1;
1826 switch (D.Type) {
1827 case OptionType::Switch:
1828 O.indent(IndentLevel)
1829 << "vec.push_back(std::make_pair(" << D.GenVariableName()
1830 << ".getPosition(), \"" << Name << "\"));\n";
1831 break;
1832 case OptionType::Parameter:
1833 O.indent(IndentLevel) << "vec.push_back(std::make_pair("
1834 << D.GenVariableName()
1835 <<".getPosition(), \"" << Name;
1837 if (!D.isForwardNotSplit()) {
1838 O << "\"));\n";
1839 O.indent(IndentLevel) << "vec.push_back(std::make_pair("
1840 << D.GenVariableName() << ".getPosition(), "
1841 << D.GenVariableName() << "));\n";
1843 else {
1844 O << "=\" + " << D.GenVariableName() << "));\n";
1846 break;
1847 case OptionType::Prefix:
1848 O.indent(IndentLevel) << "vec.push_back(std::make_pair("
1849 << D.GenVariableName() << ".getPosition(), \""
1850 << Name << "\" + "
1851 << D.GenVariableName() << "));\n";
1852 break;
1853 case OptionType::PrefixList:
1854 EmitForEachListElementCycleHeader(D, IndentLevel, O);
1855 O.indent(IndentLevel1) << "vec.push_back(std::make_pair(pos, \""
1856 << Name << "\" + " << "*B));\n";
1857 O.indent(IndentLevel1) << "++B;\n";
1859 for (int i = 1, j = D.MultiVal; i < j; ++i) {
1860 O.indent(IndentLevel1) << "vec.push_back(std::make_pair(pos, *B));\n";
1861 O.indent(IndentLevel1) << "++B;\n";
1864 O.indent(IndentLevel) << "}\n";
1865 break;
1866 case OptionType::ParameterList:
1867 EmitForEachListElementCycleHeader(D, IndentLevel, O);
1868 O.indent(IndentLevel1) << "vec.push_back(std::make_pair(pos, \""
1869 << Name << "\"));\n";
1871 for (int i = 0, j = D.MultiVal; i < j; ++i) {
1872 O.indent(IndentLevel1) << "vec.push_back(std::make_pair(pos, *B));\n";
1873 O.indent(IndentLevel1) << "++B;\n";
1876 O.indent(IndentLevel) << "}\n";
1877 break;
1878 case OptionType::SwitchList:
1879 EmitForEachListElementCycleHeader(D, IndentLevel, O);
1880 O.indent(IndentLevel1) << "vec.push_back(std::make_pair(pos, \""
1881 << Name << "\"));\n";
1882 O.indent(IndentLevel1) << "++B;\n";
1883 O.indent(IndentLevel) << "}\n";
1884 break;
1885 case OptionType::Alias:
1886 default:
1887 throw "Aliases are not allowed in tool option descriptions!";
1891 /// ActionHandlingCallbackBase - Base class of EmitActionHandlersCallback and
1892 /// EmitPreprocessOptionsCallback.
1893 struct ActionHandlingCallbackBase
1896 void onErrorDag(const DagInit& d,
1897 unsigned IndentLevel, raw_ostream& O) const
1899 O.indent(IndentLevel)
1900 << "PrintError(\""
1901 << (d.getNumArgs() >= 1 ? InitPtrToString(d.getArg(0)) : "Unknown error!")
1902 << "\");\n";
1903 O.indent(IndentLevel) << "return 1;\n";
1906 void onWarningDag(const DagInit& d,
1907 unsigned IndentLevel, raw_ostream& O) const
1909 CheckNumberOfArguments(d, 1);
1910 O.indent(IndentLevel) << "llvm::errs() << \""
1911 << InitPtrToString(d.getArg(0)) << "\";\n";
1916 /// EmitActionHandlersCallback - Emit code that handles actions. Used by
1917 /// EmitGenerateActionMethod() as an argument to EmitCaseConstructHandler().
1918 class EmitActionHandlersCallback;
1920 typedef void (EmitActionHandlersCallback::* EmitActionHandlersCallbackHandler)
1921 (const DagInit&, unsigned, raw_ostream&) const;
1923 class EmitActionHandlersCallback :
1924 public ActionHandlingCallbackBase,
1925 public HandlerTable<EmitActionHandlersCallbackHandler>
1927 typedef EmitActionHandlersCallbackHandler Handler;
1929 const OptionDescriptions& OptDescs;
1931 /// EmitHookInvocation - Common code for hook invocation from actions. Used by
1932 /// onAppendCmd and onOutputSuffix.
1933 void EmitHookInvocation(const std::string& Str,
1934 const char* BlockOpen, const char* BlockClose,
1935 unsigned IndentLevel, raw_ostream& O) const
1937 StrVector Out;
1938 TokenizeCmdLine(Str, Out);
1940 for (StrVector::const_iterator B = Out.begin(), E = Out.end();
1941 B != E; ++B) {
1942 const std::string& cmd = *B;
1944 O.indent(IndentLevel) << BlockOpen;
1946 if (cmd.at(0) == '$')
1947 B = SubstituteSpecialCommands(B, E, /* IsJoin = */ true, O);
1948 else
1949 O << '"' << cmd << '"';
1951 O << BlockClose;
1955 void onAppendCmd (const DagInit& Dag,
1956 unsigned IndentLevel, raw_ostream& O) const
1958 CheckNumberOfArguments(Dag, 1);
1959 this->EmitHookInvocation(InitPtrToString(Dag.getArg(0)),
1960 "vec.push_back(std::make_pair(65536, ", "));\n",
1961 IndentLevel, O);
1964 void onForward (const DagInit& Dag,
1965 unsigned IndentLevel, raw_ostream& O) const
1967 CheckNumberOfArguments(Dag, 1);
1968 const std::string& Name = InitPtrToString(Dag.getArg(0));
1969 EmitForwardOptionPropertyHandlingCode(OptDescs.FindOption(Name),
1970 IndentLevel, "", O);
1973 void onForwardAs (const DagInit& Dag,
1974 unsigned IndentLevel, raw_ostream& O) const
1976 CheckNumberOfArguments(Dag, 2);
1977 const std::string& Name = InitPtrToString(Dag.getArg(0));
1978 const std::string& NewName = InitPtrToString(Dag.getArg(1));
1979 EmitForwardOptionPropertyHandlingCode(OptDescs.FindOption(Name),
1980 IndentLevel, NewName, O);
1983 void onForwardValue (const DagInit& Dag,
1984 unsigned IndentLevel, raw_ostream& O) const
1986 CheckNumberOfArguments(Dag, 1);
1987 const std::string& Name = InitPtrToString(Dag.getArg(0));
1988 const OptionDescription& D = OptDescs.FindParameterListOrParameter(Name);
1990 if (D.isSwitchList()) {
1991 throw std::runtime_error
1992 ("forward_value is not allowed with switch_list");
1995 if (D.isParameter()) {
1996 O.indent(IndentLevel) << "vec.push_back(std::make_pair("
1997 << D.GenVariableName() << ".getPosition(), "
1998 << D.GenVariableName() << "));\n";
2000 else {
2001 O.indent(IndentLevel) << "for (" << D.GenTypeDeclaration()
2002 << "::iterator B = " << D.GenVariableName()
2003 << ".begin(), \n";
2004 O.indent(IndentLevel + Indent1) << " E = " << D.GenVariableName()
2005 << ".end(); B != E; ++B)\n";
2006 O.indent(IndentLevel) << "{\n";
2007 O.indent(IndentLevel + Indent1)
2008 << "unsigned pos = " << D.GenVariableName()
2009 << ".getPosition(B - " << D.GenVariableName()
2010 << ".begin());\n";
2011 O.indent(IndentLevel + Indent1)
2012 << "vec.push_back(std::make_pair(pos, *B));\n";
2013 O.indent(IndentLevel) << "}\n";
2017 void onForwardTransformedValue (const DagInit& Dag,
2018 unsigned IndentLevel, raw_ostream& O) const
2020 CheckNumberOfArguments(Dag, 2);
2021 const std::string& Name = InitPtrToString(Dag.getArg(0));
2022 const std::string& Hook = InitPtrToString(Dag.getArg(1));
2023 const OptionDescription& D = OptDescs.FindParameterListOrParameter(Name);
2025 O.indent(IndentLevel) << "vec.push_back(std::make_pair("
2026 << D.GenVariableName() << ".getPosition("
2027 << (D.isList() ? "0" : "") << "), "
2028 << "hooks::" << Hook << "(" << D.GenVariableName()
2029 << (D.isParameter() ? ".c_str()" : "") << ")));\n";
2032 void onNoOutFile (const DagInit& Dag,
2033 unsigned IndentLevel, raw_ostream& O) const
2035 CheckNumberOfArguments(Dag, 0);
2036 O.indent(IndentLevel) << "no_out_file = true;\n";
2039 void onOutputSuffix (const DagInit& Dag,
2040 unsigned IndentLevel, raw_ostream& O) const
2042 CheckNumberOfArguments(Dag, 1);
2043 this->EmitHookInvocation(InitPtrToString(Dag.getArg(0)),
2044 "output_suffix = ", ";\n", IndentLevel, O);
2047 void onStopCompilation (const DagInit& Dag,
2048 unsigned IndentLevel, raw_ostream& O) const
2050 O.indent(IndentLevel) << "stop_compilation = true;\n";
2054 void onUnpackValues (const DagInit& Dag,
2055 unsigned IndentLevel, raw_ostream& O) const
2057 throw "'unpack_values' is deprecated. "
2058 "Use 'comma_separated' + 'forward_value' instead!";
2061 public:
2063 explicit EmitActionHandlersCallback(const OptionDescriptions& OD)
2064 : OptDescs(OD)
2066 if (!staticMembersInitialized_) {
2067 AddHandler("error", &EmitActionHandlersCallback::onErrorDag);
2068 AddHandler("warning", &EmitActionHandlersCallback::onWarningDag);
2069 AddHandler("append_cmd", &EmitActionHandlersCallback::onAppendCmd);
2070 AddHandler("forward", &EmitActionHandlersCallback::onForward);
2071 AddHandler("forward_as", &EmitActionHandlersCallback::onForwardAs);
2072 AddHandler("forward_value", &EmitActionHandlersCallback::onForwardValue);
2073 AddHandler("forward_transformed_value",
2074 &EmitActionHandlersCallback::onForwardTransformedValue);
2075 AddHandler("no_out_file",
2076 &EmitActionHandlersCallback::onNoOutFile);
2077 AddHandler("output_suffix", &EmitActionHandlersCallback::onOutputSuffix);
2078 AddHandler("stop_compilation",
2079 &EmitActionHandlersCallback::onStopCompilation);
2080 AddHandler("unpack_values",
2081 &EmitActionHandlersCallback::onUnpackValues);
2084 staticMembersInitialized_ = true;
2088 void operator()(const Init* I,
2089 unsigned IndentLevel, raw_ostream& O) const
2091 InvokeDagInitHandler(this, I, IndentLevel, O);
2095 void EmitGenerateActionMethodHeader(const ToolDescription& D,
2096 bool IsJoin, bool Naked,
2097 raw_ostream& O)
2099 O.indent(Indent1) << "int GenerateAction(Action& Out,\n";
2101 if (IsJoin)
2102 O.indent(Indent2) << "const PathVector& inFiles,\n";
2103 else
2104 O.indent(Indent2) << "const sys::Path& inFile,\n";
2106 O.indent(Indent2) << "const bool HasChildren,\n";
2107 O.indent(Indent2) << "const llvm::sys::Path& TempDir,\n";
2108 O.indent(Indent2) << "const InputLanguagesSet& InLangs,\n";
2109 O.indent(Indent2) << "const LanguageMap& LangMap) const\n";
2110 O.indent(Indent1) << "{\n";
2112 if (!Naked) {
2113 O.indent(Indent2) << "std::string cmd;\n";
2114 O.indent(Indent2) << "std::string out_file;\n";
2115 O.indent(Indent2)
2116 << "std::vector<std::pair<unsigned, std::string> > vec;\n";
2117 O.indent(Indent2) << "bool stop_compilation = !HasChildren;\n";
2118 O.indent(Indent2) << "bool no_out_file = false;\n";
2119 O.indent(Indent2) << "std::string output_suffix(\""
2120 << D.OutputSuffix << "\");\n";
2124 // EmitGenerateActionMethod - Emit either a normal or a "join" version of the
2125 // Tool::GenerateAction() method.
2126 void EmitGenerateActionMethod (const ToolDescription& D,
2127 const OptionDescriptions& OptDescs,
2128 bool IsJoin, raw_ostream& O) {
2130 EmitGenerateActionMethodHeader(D, IsJoin, /* Naked = */ false, O);
2132 if (!D.CmdLine)
2133 throw "Tool " + D.Name + " has no cmd_line property!";
2135 // Process the 'command' property.
2136 O << '\n';
2137 EmitCmdLineVecFill(D.CmdLine, D.Name, IsJoin, Indent2, O);
2138 O << '\n';
2140 // Process the 'actions' list of this tool.
2141 if (D.Actions)
2142 EmitCaseConstructHandler(D.Actions, Indent2,
2143 EmitActionHandlersCallback(OptDescs),
2144 false, OptDescs, O);
2145 O << '\n';
2147 // Input file (s)
2148 if (!D.InFileOption.empty()) {
2149 O.indent(Indent2)
2150 << "vec.push_back(std::make_pair(InputFilenames.getPosition(0), \""
2151 << D.InFileOption << "\");\n";
2154 if (IsJoin) {
2155 O.indent(Indent2)
2156 << "for (PathVector::const_iterator B = inFiles.begin(),\n";
2157 O.indent(Indent3) << "E = inFiles.end(); B != E; ++B)\n";
2158 O.indent(Indent2) << "{\n";
2159 O.indent(Indent3) << "vec.push_back(std::make_pair("
2160 << "InputFilenames.getPosition(B - inFiles.begin()), "
2161 << "B->str()));\n";
2162 O.indent(Indent2) << "}\n";
2164 else {
2165 O.indent(Indent2) << "vec.push_back(std::make_pair("
2166 << "InputFilenames.getPosition(0), inFile.str()));\n";
2169 // Output file
2170 O.indent(Indent2) << "if (!no_out_file) {\n";
2171 if (!D.OutFileOption.empty())
2172 O.indent(Indent3) << "vec.push_back(std::make_pair(65536, \""
2173 << D.OutFileOption << "\"));\n";
2175 O.indent(Indent3) << "out_file = this->OutFilename("
2176 << (IsJoin ? "sys::Path(),\n" : "inFile,\n");
2177 O.indent(Indent4) <<
2178 "TempDir, stop_compilation, output_suffix.c_str()).str();\n\n";
2179 O.indent(Indent3) << "vec.push_back(std::make_pair(65536, out_file));\n";
2181 O.indent(Indent2) << "}\n\n";
2183 // Handle the Sink property.
2184 std::string SinkOption("autogenerated::");
2185 SinkOption += SinkOptionName;
2186 if (D.isSink()) {
2187 O.indent(Indent2) << "if (!" << SinkOption << ".empty()) {\n";
2188 O.indent(Indent3) << "for (cl::list<std::string>::iterator B = "
2189 << SinkOption << ".begin(), E = " << SinkOption
2190 << ".end(); B != E; ++B)\n";
2191 O.indent(Indent4) << "vec.push_back(std::make_pair(" << SinkOption
2192 << ".getPosition(B - " << SinkOption
2193 << ".begin()), *B));\n";
2194 O.indent(Indent2) << "}\n";
2197 O.indent(Indent2) << "Out.Construct(cmd, this->SortArgs(vec), "
2198 << "stop_compilation, out_file);\n";
2199 O.indent(Indent2) << "return 0;\n";
2200 O.indent(Indent1) << "}\n\n";
2203 /// EmitGenerateActionMethods - Emit two GenerateAction() methods for
2204 /// a given Tool class.
2205 void EmitGenerateActionMethods (const ToolDescription& ToolDesc,
2206 const OptionDescriptions& OptDescs,
2207 raw_ostream& O) {
2208 if (!ToolDesc.isJoin()) {
2209 EmitGenerateActionMethodHeader(ToolDesc, /* IsJoin = */ true,
2210 /* Naked = */ true, O);
2211 O.indent(Indent2) << "PrintError(\"" << ToolDesc.Name
2212 << " is not a Join tool!\");\n";
2213 O.indent(Indent2) << "return -1;\n";
2214 O.indent(Indent1) << "}\n\n";
2216 else {
2217 EmitGenerateActionMethod(ToolDesc, OptDescs, true, O);
2220 EmitGenerateActionMethod(ToolDesc, OptDescs, false, O);
2223 /// EmitInOutLanguageMethods - Emit the [Input,Output]Language()
2224 /// methods for a given Tool class.
2225 void EmitInOutLanguageMethods (const ToolDescription& D, raw_ostream& O) {
2226 O.indent(Indent1) << "const char** InputLanguages() const {\n";
2227 O.indent(Indent2) << "return InputLanguages_;\n";
2228 O.indent(Indent1) << "}\n\n";
2230 O.indent(Indent1) << "const char** OutputLanguages() const {\n";
2231 O.indent(Indent2) << "return OutputLanguages_;\n";
2232 O.indent(Indent1) << "}\n\n";
2235 /// EmitNameMethod - Emit the Name() method for a given Tool class.
2236 void EmitNameMethod (const ToolDescription& D, raw_ostream& O) {
2237 O.indent(Indent1) << "const char* Name() const {\n";
2238 O.indent(Indent2) << "return \"" << D.Name << "\";\n";
2239 O.indent(Indent1) << "}\n\n";
2242 /// EmitIsJoinMethod - Emit the IsJoin() method for a given Tool
2243 /// class.
2244 void EmitIsJoinMethod (const ToolDescription& D, raw_ostream& O) {
2245 O.indent(Indent1) << "bool IsJoin() const {\n";
2246 if (D.isJoin())
2247 O.indent(Indent2) << "return true;\n";
2248 else
2249 O.indent(Indent2) << "return false;\n";
2250 O.indent(Indent1) << "}\n\n";
2253 /// EmitWorksOnEmptyCallback - Callback used by EmitWorksOnEmptyMethod in
2254 /// conjunction with EmitCaseConstructHandler.
2255 void EmitWorksOnEmptyCallback (const Init* Value,
2256 unsigned IndentLevel, raw_ostream& O) {
2257 CheckBooleanConstant(Value);
2258 O.indent(IndentLevel) << "return " << Value->getAsString() << ";\n";
2261 /// EmitWorksOnEmptyMethod - Emit the WorksOnEmpty() method for a given Tool
2262 /// class.
2263 void EmitWorksOnEmptyMethod (const ToolDescription& D,
2264 const OptionDescriptions& OptDescs,
2265 raw_ostream& O)
2267 O.indent(Indent1) << "bool WorksOnEmpty() const {\n";
2268 if (D.OnEmpty == 0)
2269 O.indent(Indent2) << "return false;\n";
2270 else
2271 EmitCaseConstructHandler(D.OnEmpty, Indent2, EmitWorksOnEmptyCallback,
2272 /*EmitElseIf = */ true, OptDescs, O);
2273 O.indent(Indent1) << "}\n\n";
2276 /// EmitStrArray - Emit definition of a 'const char**' static member
2277 /// variable. Helper used by EmitStaticMemberDefinitions();
2278 void EmitStrArray(const std::string& Name, const std::string& VarName,
2279 const StrVector& StrVec, raw_ostream& O) {
2280 O << "const char* " << Name << "::" << VarName << "[] = {";
2281 for (StrVector::const_iterator B = StrVec.begin(), E = StrVec.end();
2282 B != E; ++B)
2283 O << '\"' << *B << "\", ";
2284 O << "0};\n";
2287 /// EmitStaticMemberDefinitions - Emit static member definitions for a
2288 /// given Tool class.
2289 void EmitStaticMemberDefinitions(const ToolDescription& D, raw_ostream& O) {
2290 if (D.InLanguage.empty())
2291 throw "Tool " + D.Name + " has no 'in_language' property!";
2292 if (D.OutLanguage.empty())
2293 throw "Tool " + D.Name + " has no 'out_language' property!";
2295 EmitStrArray(D.Name, "InputLanguages_", D.InLanguage, O);
2296 EmitStrArray(D.Name, "OutputLanguages_", D.OutLanguage, O);
2297 O << '\n';
2300 /// EmitToolClassDefinition - Emit a Tool class definition.
2301 void EmitToolClassDefinition (const ToolDescription& D,
2302 const OptionDescriptions& OptDescs,
2303 raw_ostream& O) {
2304 if (D.Name == "root")
2305 return;
2307 // Header
2308 O << "class " << D.Name << " : public ";
2309 if (D.isJoin())
2310 O << "JoinTool";
2311 else
2312 O << "Tool";
2314 O << " {\nprivate:\n";
2315 O.indent(Indent1) << "static const char* InputLanguages_[];\n";
2316 O.indent(Indent1) << "static const char* OutputLanguages_[];\n\n";
2318 O << "public:\n";
2319 EmitNameMethod(D, O);
2320 EmitInOutLanguageMethods(D, O);
2321 EmitIsJoinMethod(D, O);
2322 EmitWorksOnEmptyMethod(D, OptDescs, O);
2323 EmitGenerateActionMethods(D, OptDescs, O);
2325 // Close class definition
2326 O << "};\n";
2328 EmitStaticMemberDefinitions(D, O);
2332 /// EmitOptionDefinitions - Iterate over a list of option descriptions
2333 /// and emit registration code.
2334 void EmitOptionDefinitions (const OptionDescriptions& descs,
2335 bool HasSink, raw_ostream& O)
2337 std::vector<OptionDescription> Aliases;
2339 // Emit static cl::Option variables.
2340 for (OptionDescriptions::const_iterator B = descs.begin(),
2341 E = descs.end(); B!=E; ++B) {
2342 const OptionDescription& val = B->second;
2344 if (val.Type == OptionType::Alias) {
2345 Aliases.push_back(val);
2346 continue;
2349 O << val.GenTypeDeclaration() << ' '
2350 << val.GenPlainVariableName();
2352 O << "(\"" << val.Name << "\"\n";
2354 if (val.Type == OptionType::Prefix || val.Type == OptionType::PrefixList)
2355 O << ", cl::Prefix";
2357 if (val.isRequired()) {
2358 if (val.isList() && !val.isMultiVal())
2359 O << ", cl::OneOrMore";
2360 else
2361 O << ", cl::Required";
2364 if (val.isOptional())
2365 O << ", cl::Optional";
2367 if (val.isOneOrMore())
2368 O << ", cl::OneOrMore";
2370 if (val.isZeroOrMore())
2371 O << ", cl::ZeroOrMore";
2373 if (val.isReallyHidden())
2374 O << ", cl::ReallyHidden";
2375 else if (val.isHidden())
2376 O << ", cl::Hidden";
2378 if (val.isCommaSeparated())
2379 O << ", cl::CommaSeparated";
2381 if (val.MultiVal > 1)
2382 O << ", cl::multi_val(" << val.MultiVal << ')';
2384 if (val.InitVal) {
2385 const std::string& str = val.InitVal->getAsString();
2386 O << ", cl::init(" << str << ')';
2389 if (!val.Help.empty())
2390 O << ", cl::desc(\"" << val.Help << "\")";
2392 O << ");\n\n";
2395 // Emit the aliases (they should go after all the 'proper' options).
2396 for (std::vector<OptionDescription>::const_iterator
2397 B = Aliases.begin(), E = Aliases.end(); B != E; ++B) {
2398 const OptionDescription& val = *B;
2400 O << val.GenTypeDeclaration() << ' '
2401 << val.GenPlainVariableName()
2402 << "(\"" << val.Name << '\"';
2404 const OptionDescription& D = descs.FindOption(val.Help);
2405 O << ", cl::aliasopt(" << D.GenVariableName() << ")";
2407 O << ", cl::desc(\"" << "An alias for -" + val.Help << "\"));\n";
2410 // Emit the sink option.
2411 if (HasSink)
2412 O << "cl::list<std::string> " << SinkOptionName << "(cl::Sink);\n";
2414 O << '\n';
2417 /// EmitPreprocessOptionsCallback - Helper function passed to
2418 /// EmitCaseConstructHandler() by EmitPreprocessOptions().
2420 class EmitPreprocessOptionsCallback;
2422 typedef void
2423 (EmitPreprocessOptionsCallback::* EmitPreprocessOptionsCallbackHandler)
2424 (const DagInit&, unsigned, raw_ostream&) const;
2426 class EmitPreprocessOptionsCallback :
2427 public ActionHandlingCallbackBase,
2428 public HandlerTable<EmitPreprocessOptionsCallbackHandler>
2430 typedef EmitPreprocessOptionsCallbackHandler Handler;
2431 typedef void
2432 (EmitPreprocessOptionsCallback::* HandlerImpl)
2433 (const Init*, unsigned, raw_ostream&) const;
2435 const OptionDescriptions& OptDescs_;
2437 void onEachArgument(const DagInit& d, HandlerImpl h,
2438 unsigned IndentLevel, raw_ostream& O) const
2440 CheckNumberOfArguments(d, 1);
2442 for (unsigned i = 0, NumArgs = d.getNumArgs(); i < NumArgs; ++i) {
2443 ((this)->*(h))(d.getArg(i), IndentLevel, O);
2447 void onUnsetOptionImpl(const Init* I,
2448 unsigned IndentLevel, raw_ostream& O) const
2450 const std::string& OptName = InitPtrToString(I);
2451 const OptionDescription& OptDesc = OptDescs_.FindOption(OptName);
2453 if (OptDesc.isSwitch()) {
2454 O.indent(IndentLevel) << OptDesc.GenVariableName() << " = false;\n";
2456 else if (OptDesc.isParameter()) {
2457 O.indent(IndentLevel) << OptDesc.GenVariableName() << " = \"\";\n";
2459 else if (OptDesc.isList()) {
2460 O.indent(IndentLevel) << OptDesc.GenVariableName() << ".clear();\n";
2462 else {
2463 throw "Can't apply 'unset_option' to alias option '" + OptName + "'!";
2467 void onUnsetOption(const DagInit& d,
2468 unsigned IndentLevel, raw_ostream& O) const
2470 this->onEachArgument(d, &EmitPreprocessOptionsCallback::onUnsetOptionImpl,
2471 IndentLevel, O);
2474 void onSetOptionImpl(const DagInit& D,
2475 unsigned IndentLevel, raw_ostream& O) const {
2476 CheckNumberOfArguments(D, 2);
2478 const std::string& OptName = InitPtrToString(D.getArg(0));
2479 const OptionDescription& OptDesc = OptDescs_.FindOption(OptName);
2480 const Init* Value = D.getArg(1);
2482 if (OptDesc.isList()) {
2483 const ListInit& List = InitPtrToList(Value);
2485 O.indent(IndentLevel) << OptDesc.GenVariableName() << ".clear();\n";
2486 for (ListInit::const_iterator B = List.begin(), E = List.end();
2487 B != E; ++B) {
2488 const Init* CurElem = *B;
2489 if (OptDesc.isSwitchList())
2490 CheckBooleanConstant(CurElem);
2492 O.indent(IndentLevel)
2493 << OptDesc.GenVariableName() << ".push_back(\""
2494 << (OptDesc.isSwitchList() ? CurElem->getAsString()
2495 : InitPtrToString(CurElem))
2496 << "\");\n";
2499 else if (OptDesc.isSwitch()) {
2500 CheckBooleanConstant(Value);
2501 O.indent(IndentLevel) << OptDesc.GenVariableName()
2502 << " = " << Value->getAsString() << ";\n";
2504 else if (OptDesc.isParameter()) {
2505 const std::string& Str = InitPtrToString(Value);
2506 O.indent(IndentLevel) << OptDesc.GenVariableName()
2507 << " = \"" << Str << "\";\n";
2509 else {
2510 throw "Can't apply 'set_option' to alias option '" + OptName + "'!";
2514 void onSetSwitch(const Init* I,
2515 unsigned IndentLevel, raw_ostream& O) const {
2516 const std::string& OptName = InitPtrToString(I);
2517 const OptionDescription& OptDesc = OptDescs_.FindOption(OptName);
2519 if (OptDesc.isSwitch())
2520 O.indent(IndentLevel) << OptDesc.GenVariableName() << " = true;\n";
2521 else
2522 throw "set_option: -" + OptName + " is not a switch option!";
2525 void onSetOption(const DagInit& d,
2526 unsigned IndentLevel, raw_ostream& O) const
2528 CheckNumberOfArguments(d, 1);
2530 // 2-argument form: (set_option "A", true), (set_option "B", "C"),
2531 // (set_option "D", ["E", "F"])
2532 if (d.getNumArgs() == 2) {
2533 const OptionDescription& OptDesc =
2534 OptDescs_.FindOption(InitPtrToString(d.getArg(0)));
2535 const Init* Opt2 = d.getArg(1);
2537 if (!OptDesc.isSwitch() || typeid(*Opt2) != typeid(StringInit)) {
2538 this->onSetOptionImpl(d, IndentLevel, O);
2539 return;
2543 // Multiple argument form: (set_option "A"), (set_option "B", "C", "D")
2544 this->onEachArgument(d, &EmitPreprocessOptionsCallback::onSetSwitch,
2545 IndentLevel, O);
2548 public:
2550 EmitPreprocessOptionsCallback(const OptionDescriptions& OptDescs)
2551 : OptDescs_(OptDescs)
2553 if (!staticMembersInitialized_) {
2554 AddHandler("error", &EmitPreprocessOptionsCallback::onErrorDag);
2555 AddHandler("warning", &EmitPreprocessOptionsCallback::onWarningDag);
2556 AddHandler("unset_option", &EmitPreprocessOptionsCallback::onUnsetOption);
2557 AddHandler("set_option", &EmitPreprocessOptionsCallback::onSetOption);
2559 staticMembersInitialized_ = true;
2563 void operator()(const Init* I,
2564 unsigned IndentLevel, raw_ostream& O) const
2566 InvokeDagInitHandler(this, I, IndentLevel, O);
2571 /// EmitPreprocessOptions - Emit the PreprocessOptions() function.
2572 void EmitPreprocessOptions (const RecordKeeper& Records,
2573 const OptionDescriptions& OptDecs, raw_ostream& O)
2575 O << "int PreprocessOptions () {\n";
2577 const RecordVector& OptionPreprocessors =
2578 Records.getAllDerivedDefinitions("OptionPreprocessor");
2580 for (RecordVector::const_iterator B = OptionPreprocessors.begin(),
2581 E = OptionPreprocessors.end(); B!=E; ++B) {
2582 DagInit* Case = (*B)->getValueAsDag("preprocessor");
2583 EmitCaseConstructHandler(Case, Indent1,
2584 EmitPreprocessOptionsCallback(OptDecs),
2585 false, OptDecs, O);
2588 O << '\n';
2589 O.indent(Indent1) << "return 0;\n";
2590 O << "}\n\n";
2593 class DoEmitPopulateLanguageMap;
2594 typedef void (DoEmitPopulateLanguageMap::* DoEmitPopulateLanguageMapHandler)
2595 (const DagInit& D);
2597 class DoEmitPopulateLanguageMap
2598 : public HandlerTable<DoEmitPopulateLanguageMapHandler>
2600 private:
2601 raw_ostream& O_;
2603 public:
2605 explicit DoEmitPopulateLanguageMap (raw_ostream& O) : O_(O) {
2606 if (!staticMembersInitialized_) {
2607 AddHandler("lang_to_suffixes",
2608 &DoEmitPopulateLanguageMap::onLangToSuffixes);
2610 staticMembersInitialized_ = true;
2614 void operator() (Init* I) {
2615 InvokeDagInitHandler(this, I);
2618 private:
2620 void onLangToSuffixes (const DagInit& d) {
2621 CheckNumberOfArguments(d, 2);
2623 const std::string& Lang = InitPtrToString(d.getArg(0));
2624 Init* Suffixes = d.getArg(1);
2626 // Second argument to lang_to_suffixes is either a single string...
2627 if (typeid(*Suffixes) == typeid(StringInit)) {
2628 O_.indent(Indent1) << "langMap[\"" << InitPtrToString(Suffixes)
2629 << "\"] = \"" << Lang << "\";\n";
2631 // ...or a list of strings.
2632 else {
2633 const ListInit& Lst = InitPtrToList(Suffixes);
2634 assert(Lst.size() != 0);
2635 for (ListInit::const_iterator B = Lst.begin(), E = Lst.end();
2636 B != E; ++B) {
2637 O_.indent(Indent1) << "langMap[\"" << InitPtrToString(*B)
2638 << "\"] = \"" << Lang << "\";\n";
2645 /// EmitPopulateLanguageMap - Emit the PopulateLanguageMap() function.
2646 void EmitPopulateLanguageMap (const RecordKeeper& Records, raw_ostream& O)
2648 O << "int PopulateLanguageMap (LanguageMap& langMap) {\n";
2650 // For each LanguageMap:
2651 const RecordVector& LangMaps =
2652 Records.getAllDerivedDefinitions("LanguageMap");
2654 // Call DoEmitPopulateLanguageMap.
2655 for (RecordVector::const_iterator B = LangMaps.begin(),
2656 E = LangMaps.end(); B!=E; ++B) {
2657 ListInit* LangMap = (*B)->getValueAsListInit("map");
2658 std::for_each(LangMap->begin(), LangMap->end(),
2659 DoEmitPopulateLanguageMap(O));
2662 O << '\n';
2663 O.indent(Indent1) << "return 0;\n";
2664 O << "}\n\n";
2667 /// EmitEdgePropertyHandlerCallback - Emits code that handles edge
2668 /// properties. Helper function passed to EmitCaseConstructHandler() by
2669 /// EmitEdgeClass().
2670 void EmitEdgePropertyHandlerCallback (const Init* i, unsigned IndentLevel,
2671 raw_ostream& O) {
2672 const DagInit& d = InitPtrToDag(i);
2673 const std::string& OpName = GetOperatorName(d);
2675 if (OpName == "inc_weight") {
2676 O.indent(IndentLevel) << "ret += ";
2678 else if (OpName == "error") {
2679 CheckNumberOfArguments(d, 1);
2680 O.indent(IndentLevel) << "PrintError(\""
2681 << InitPtrToString(d.getArg(0))
2682 << "\");\n";
2683 O.indent(IndentLevel) << "return -1;\n";
2684 return;
2686 else {
2687 throw "Unknown operator in edge properties list: '" + OpName + "'!"
2688 "\nOnly 'inc_weight', 'dec_weight' and 'error' are allowed.";
2691 if (d.getNumArgs() > 0)
2692 O << InitPtrToInt(d.getArg(0)) << ";\n";
2693 else
2694 O << "2;\n";
2698 /// EmitEdgeClass - Emit a single Edge# class.
2699 void EmitEdgeClass (unsigned N, const std::string& Target,
2700 const DagInit& Case, const OptionDescriptions& OptDescs,
2701 raw_ostream& O) {
2703 // Class constructor.
2704 O << "class Edge" << N << ": public Edge {\n"
2705 << "public:\n";
2706 O.indent(Indent1) << "Edge" << N << "() : Edge(\"" << Target
2707 << "\") {}\n\n";
2709 // Function Weight().
2710 O.indent(Indent1)
2711 << "int Weight(const InputLanguagesSet& InLangs) const {\n";
2712 O.indent(Indent2) << "unsigned ret = 0;\n";
2714 // Handle the 'case' construct.
2715 EmitCaseConstructHandler(&Case, Indent2, EmitEdgePropertyHandlerCallback,
2716 false, OptDescs, O);
2718 O.indent(Indent2) << "return ret;\n";
2719 O.indent(Indent1) << "}\n\n};\n\n";
2722 /// EmitEdgeClasses - Emit Edge* classes that represent graph edges.
2723 void EmitEdgeClasses (const DagVector& EdgeVector,
2724 const OptionDescriptions& OptDescs,
2725 raw_ostream& O) {
2726 int i = 0;
2727 for (DagVector::const_iterator B = EdgeVector.begin(),
2728 E = EdgeVector.end(); B != E; ++B) {
2729 const DagInit& Edge = **B;
2730 const std::string& Name = GetOperatorName(Edge);
2732 if (Name == "optional_edge") {
2733 assert(IsOptionalEdge(Edge));
2734 const std::string& NodeB = InitPtrToString(Edge.getArg(1));
2736 const DagInit& Weight = InitPtrToDag(Edge.getArg(2));
2737 EmitEdgeClass(i, NodeB, Weight, OptDescs, O);
2739 else if (Name != "edge") {
2740 throw "Unknown edge class: '" + Name + "'!";
2743 ++i;
2747 /// EmitPopulateCompilationGraph - Emit the PopulateCompilationGraph() function.
2748 void EmitPopulateCompilationGraph (const DagVector& EdgeVector,
2749 const ToolDescriptions& ToolDescs,
2750 raw_ostream& O)
2752 O << "int PopulateCompilationGraph (CompilationGraph& G) {\n";
2754 for (ToolDescriptions::const_iterator B = ToolDescs.begin(),
2755 E = ToolDescs.end(); B != E; ++B)
2756 O.indent(Indent1) << "G.insertNode(new " << (*B)->Name << "());\n";
2758 O << '\n';
2760 // Insert edges.
2762 int i = 0;
2763 for (DagVector::const_iterator B = EdgeVector.begin(),
2764 E = EdgeVector.end(); B != E; ++B) {
2765 const DagInit& Edge = **B;
2766 const std::string& NodeA = InitPtrToString(Edge.getArg(0));
2767 const std::string& NodeB = InitPtrToString(Edge.getArg(1));
2769 O.indent(Indent1) << "if (int ret = G.insertEdge(\"" << NodeA << "\", ";
2771 if (IsOptionalEdge(Edge))
2772 O << "new Edge" << i << "()";
2773 else
2774 O << "new SimpleEdge(\"" << NodeB << "\")";
2776 O << "))\n";
2777 O.indent(Indent2) << "return ret;\n";
2779 ++i;
2782 O << '\n';
2783 O.indent(Indent1) << "return 0;\n";
2784 O << "}\n\n";
2787 /// HookInfo - Information about the hook type and number of arguments.
2788 struct HookInfo {
2790 // A hook can either have a single parameter of type std::vector<std::string>,
2791 // or NumArgs parameters of type const char*.
2792 enum HookType { ListHook, ArgHook };
2794 HookType Type;
2795 unsigned NumArgs;
2797 HookInfo() : Type(ArgHook), NumArgs(1)
2800 HookInfo(HookType T) : Type(T), NumArgs(1)
2803 HookInfo(unsigned N) : Type(ArgHook), NumArgs(N)
2807 typedef llvm::StringMap<HookInfo> HookInfoMap;
2809 /// ExtractHookNames - Extract the hook names from all instances of
2810 /// $CALL(HookName) in the provided command line string/action. Helper
2811 /// function used by FillInHookNames().
2812 class ExtractHookNames {
2813 HookInfoMap& HookNames_;
2814 const OptionDescriptions& OptDescs_;
2815 public:
2816 ExtractHookNames(HookInfoMap& HookNames, const OptionDescriptions& OptDescs)
2817 : HookNames_(HookNames), OptDescs_(OptDescs)
2820 void onAction (const DagInit& Dag) {
2821 const std::string& Name = GetOperatorName(Dag);
2823 if (Name == "forward_transformed_value") {
2824 CheckNumberOfArguments(Dag, 2);
2825 const std::string& OptName = InitPtrToString(Dag.getArg(0));
2826 const std::string& HookName = InitPtrToString(Dag.getArg(1));
2827 const OptionDescription& D =
2828 OptDescs_.FindParameterListOrParameter(OptName);
2830 HookNames_[HookName] = HookInfo(D.isList() ? HookInfo::ListHook
2831 : HookInfo::ArgHook);
2833 else if (Name == "append_cmd" || Name == "output_suffix") {
2834 CheckNumberOfArguments(Dag, 1);
2835 this->onCmdLine(InitPtrToString(Dag.getArg(0)));
2839 void onCmdLine(const std::string& Cmd) {
2840 StrVector cmds;
2841 TokenizeCmdLine(Cmd, cmds);
2843 for (StrVector::const_iterator B = cmds.begin(), E = cmds.end();
2844 B != E; ++B) {
2845 const std::string& cmd = *B;
2847 if (cmd == "$CALL") {
2848 unsigned NumArgs = 0;
2849 CheckedIncrement(B, E, "Syntax error in $CALL invocation!");
2850 const std::string& HookName = *B;
2852 if (HookName.at(0) == ')')
2853 throw "$CALL invoked with no arguments!";
2855 while (++B != E && B->at(0) != ')') {
2856 ++NumArgs;
2859 HookInfoMap::const_iterator H = HookNames_.find(HookName);
2861 if (H != HookNames_.end() && H->second.NumArgs != NumArgs &&
2862 H->second.Type != HookInfo::ArgHook)
2863 throw "Overloading of hooks is not allowed. Overloaded hook: "
2864 + HookName;
2865 else
2866 HookNames_[HookName] = HookInfo(NumArgs);
2871 void operator()(const Init* Arg) {
2873 // We're invoked on an action (either a dag or a dag list).
2874 if (typeid(*Arg) == typeid(DagInit)) {
2875 const DagInit& Dag = InitPtrToDag(Arg);
2876 this->onAction(Dag);
2877 return;
2879 else if (typeid(*Arg) == typeid(ListInit)) {
2880 const ListInit& List = InitPtrToList(Arg);
2881 for (ListInit::const_iterator B = List.begin(), E = List.end(); B != E;
2882 ++B) {
2883 const DagInit& Dag = InitPtrToDag(*B);
2884 this->onAction(Dag);
2886 return;
2889 // We're invoked on a command line string.
2890 this->onCmdLine(InitPtrToString(Arg));
2893 void operator()(const Init* Statement, unsigned) {
2894 this->operator()(Statement);
2898 /// FillInHookNames - Actually extract the hook names from all command
2899 /// line strings. Helper function used by EmitHookDeclarations().
2900 void FillInHookNames(const ToolDescriptions& ToolDescs,
2901 const OptionDescriptions& OptDescs,
2902 HookInfoMap& HookNames)
2904 // For all tool descriptions:
2905 for (ToolDescriptions::const_iterator B = ToolDescs.begin(),
2906 E = ToolDescs.end(); B != E; ++B) {
2907 const ToolDescription& D = *(*B);
2909 // Look for 'forward_transformed_value' in 'actions'.
2910 if (D.Actions)
2911 WalkCase(D.Actions, Id(), ExtractHookNames(HookNames, OptDescs));
2913 // Look for hook invocations in 'cmd_line'.
2914 if (!D.CmdLine)
2915 continue;
2916 if (dynamic_cast<StringInit*>(D.CmdLine))
2917 // This is a string.
2918 ExtractHookNames(HookNames, OptDescs).operator()(D.CmdLine);
2919 else
2920 // This is a 'case' construct.
2921 WalkCase(D.CmdLine, Id(), ExtractHookNames(HookNames, OptDescs));
2925 /// EmitHookDeclarations - Parse CmdLine fields of all the tool
2926 /// property records and emit hook function declaration for each
2927 /// instance of $CALL(HookName).
2928 void EmitHookDeclarations(const ToolDescriptions& ToolDescs,
2929 const OptionDescriptions& OptDescs, raw_ostream& O) {
2930 HookInfoMap HookNames;
2932 FillInHookNames(ToolDescs, OptDescs, HookNames);
2933 if (HookNames.empty())
2934 return;
2936 for (HookInfoMap::const_iterator B = HookNames.begin(),
2937 E = HookNames.end(); B != E; ++B) {
2938 const char* HookName = B->first();
2939 const HookInfo& Info = B->second;
2941 O.indent(Indent1) << "std::string " << HookName << "(";
2943 if (Info.Type == HookInfo::ArgHook) {
2944 for (unsigned i = 0, j = Info.NumArgs; i < j; ++i) {
2945 O << "const char* Arg" << i << (i+1 == j ? "" : ", ");
2948 else {
2949 O << "const std::vector<std::string>& Arg";
2952 O <<");\n";
2956 /// EmitIncludes - Emit necessary #include directives and some
2957 /// additional declarations.
2958 void EmitIncludes(raw_ostream& O) {
2959 O << "#include \"llvm/CompilerDriver/BuiltinOptions.h\"\n"
2960 << "#include \"llvm/CompilerDriver/CompilationGraph.h\"\n"
2961 << "#include \"llvm/CompilerDriver/Error.h\"\n"
2962 << "#include \"llvm/CompilerDriver/Tool.h\"\n\n"
2964 << "#include \"llvm/Support/CommandLine.h\"\n"
2965 << "#include \"llvm/Support/raw_ostream.h\"\n\n"
2967 << "#include <algorithm>\n"
2968 << "#include <cstdlib>\n"
2969 << "#include <iterator>\n"
2970 << "#include <stdexcept>\n\n"
2972 << "using namespace llvm;\n"
2973 << "using namespace llvmc;\n\n"
2975 << "inline const char* checkCString(const char* s)\n"
2976 << "{ return s == NULL ? \"\" : s; }\n\n";
2980 /// DriverData - Holds all information about the driver.
2981 struct DriverData {
2982 OptionDescriptions OptDescs;
2983 ToolDescriptions ToolDescs;
2984 DagVector Edges;
2985 bool HasSink;
2988 /// HasSink - Go through the list of tool descriptions and check if
2989 /// there are any with the 'sink' property set.
2990 bool HasSink(const ToolDescriptions& ToolDescs) {
2991 for (ToolDescriptions::const_iterator B = ToolDescs.begin(),
2992 E = ToolDescs.end(); B != E; ++B)
2993 if ((*B)->isSink())
2994 return true;
2996 return false;
2999 /// CollectDriverData - Collect compilation graph edges, tool properties and
3000 /// option properties from the parse tree.
3001 void CollectDriverData (const RecordKeeper& Records, DriverData& Data) {
3002 // Collect option properties.
3003 const RecordVector& OptionLists =
3004 Records.getAllDerivedDefinitions("OptionList");
3005 CollectOptionDescriptions(OptionLists, Data.OptDescs);
3007 // Collect tool properties.
3008 const RecordVector& Tools = Records.getAllDerivedDefinitions("Tool");
3009 CollectToolDescriptions(Tools, Data.ToolDescs);
3010 Data.HasSink = HasSink(Data.ToolDescs);
3012 // Collect compilation graph edges.
3013 const RecordVector& CompilationGraphs =
3014 Records.getAllDerivedDefinitions("CompilationGraph");
3015 FillInEdgeVector(CompilationGraphs, Data.Edges);
3018 /// CheckDriverData - Perform some sanity checks on the collected data.
3019 void CheckDriverData(DriverData& Data) {
3020 // Filter out all tools not mentioned in the compilation graph.
3021 FilterNotInGraph(Data.Edges, Data.ToolDescs);
3023 // Typecheck the compilation graph.
3024 TypecheckGraph(Data.Edges, Data.ToolDescs);
3026 // Check that there are no options without side effects (specified
3027 // only in the OptionList).
3028 CheckForSuperfluousOptions(Data.Edges, Data.ToolDescs, Data.OptDescs);
3031 void EmitDriverCode(const DriverData& Data, raw_ostream& O) {
3032 // Emit file header.
3033 EmitIncludes(O);
3035 // Emit global option registration code.
3036 O << "namespace llvmc {\n"
3037 << "namespace autogenerated {\n\n";
3038 EmitOptionDefinitions(Data.OptDescs, Data.HasSink, O);
3039 O << "} // End namespace autogenerated.\n"
3040 << "} // End namespace llvmc.\n\n";
3042 // Emit hook declarations.
3043 O << "namespace hooks {\n";
3044 EmitHookDeclarations(Data.ToolDescs, Data.OptDescs, O);
3045 O << "} // End namespace hooks.\n\n";
3047 O << "namespace {\n\n";
3048 O << "using namespace llvmc::autogenerated;\n\n";
3050 // Emit Tool classes.
3051 for (ToolDescriptions::const_iterator B = Data.ToolDescs.begin(),
3052 E = Data.ToolDescs.end(); B!=E; ++B)
3053 EmitToolClassDefinition(*(*B), Data.OptDescs, O);
3055 // Emit Edge# classes.
3056 EmitEdgeClasses(Data.Edges, Data.OptDescs, O);
3058 O << "} // End anonymous namespace.\n\n";
3060 O << "namespace llvmc {\n";
3061 O << "namespace autogenerated {\n\n";
3063 // Emit PreprocessOptions() function.
3064 EmitPreprocessOptions(Records, Data.OptDescs, O);
3066 // Emit PopulateLanguageMap() function
3067 // (language map maps from file extensions to language names).
3068 EmitPopulateLanguageMap(Records, O);
3070 // Emit PopulateCompilationGraph() function.
3071 EmitPopulateCompilationGraph(Data.Edges, Data.ToolDescs, O);
3073 O << "} // End namespace autogenerated.\n";
3074 O << "} // End namespace llvmc.\n\n";
3076 // EOF
3080 // End of anonymous namespace
3083 /// run - The back-end entry point.
3084 void LLVMCConfigurationEmitter::run (raw_ostream &O) {
3085 try {
3086 DriverData Data;
3088 CollectDriverData(Records, Data);
3089 CheckDriverData(Data);
3091 this->EmitSourceFileHeader("llvmc-based driver: auto-generated code", O);
3092 EmitDriverCode(Data, O);
3094 } catch (std::exception& Error) {
3095 throw Error.what() + std::string(" - usually this means a syntax error.");