1 //===- LLVMCConfigurationEmitter.cpp - Generate LLVMC config --------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open
6 // Source License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This tablegen backend is responsible for emitting LLVMC configuration code.
12 //===----------------------------------------------------------------------===//
14 #include "LLVMCConfigurationEmitter.h"
17 #include "llvm/ADT/IntrusiveRefCntPtr.h"
18 #include "llvm/ADT/SmallVector.h"
19 #include "llvm/ADT/StringExtras.h"
20 #include "llvm/ADT/StringMap.h"
21 #include "llvm/Support/Streams.h"
32 //===----------------------------------------------------------------------===//
35 typedef std::vector<Record*> RecordVector;
36 typedef std::vector<std::string> StrVector;
38 //===----------------------------------------------------------------------===//
41 // Indentation strings
42 const char * Indent1 = " ";
43 const char * Indent2 = " ";
44 const char * Indent3 = " ";
45 const char * Indent4 = " ";
47 // Default help string
48 const char * DefaultHelpString = "NO HELP MESSAGE PROVIDED";
50 // Name for the "sink" option
51 const char * SinkOptionName = "AutoGeneratedSinkOption";
53 //===----------------------------------------------------------------------===//
56 std::string InitPtrToString(Init* ptr) {
57 StringInit& val = dynamic_cast<StringInit&>(*ptr);
58 return val.getValue();
61 // Ensure that the number of args in d is <= min_arguments,
62 // throw exception otherwise
63 void checkNumberOfArguments (const DagInit* d, unsigned min_arguments) {
64 if (d->getNumArgs() < min_arguments)
65 throw "Property " + d->getOperator()->getAsString()
66 + " has too few arguments!";
70 //===----------------------------------------------------------------------===//
71 /// Back-end specific code
73 // A command-line option can have one of the following types:
75 // Switch - a simple switch w/o arguments, e.g. -O2
77 // Parameter - an option that takes one(and only one) argument, e.g. -o file,
80 // ParameterList - same as Parameter, but more than one occurence
81 // of the option is allowed, e.g. -lm -lpthread
83 // Prefix - argument is everything after the prefix,
84 // e.g. -Wa,-foo,-bar, -DNAME=VALUE
86 // PrefixList - same as Prefix, but more than one option occurence is
89 namespace OptionType {
90 enum OptionType { Switch, Parameter, ParameterList, Prefix, PrefixList};
93 bool IsListOptionType (OptionType::OptionType t) {
94 return (t == OptionType::ParameterList || t == OptionType::PrefixList);
97 // Code duplication here is necessary because one option can affect
98 // several tools and those tools may have different actions associated
99 // with this option. GlobalOptionDescriptions are used to generate
100 // the option registration code, while ToolOptionDescriptions are used
101 // to generate tool-specific code.
103 // Base class for option descriptions
105 struct OptionDescription {
106 OptionType::OptionType Type;
109 OptionDescription(OptionType::OptionType t = OptionType::Switch,
110 const std::string& n = "")
114 const char* GenTypeDeclaration() const {
116 case OptionType::PrefixList:
117 case OptionType::ParameterList:
118 return "cl::list<std::string>";
119 case OptionType::Switch:
120 return "cl::opt<bool>";
121 case OptionType::Parameter:
122 case OptionType::Prefix:
124 return "cl::opt<std::string>";
128 std::string GenVariableName() const {
130 case OptionType::Switch:
131 return "AutoGeneratedSwitch" + Name;
132 case OptionType::Prefix:
133 return "AutoGeneratedPrefix" + Name;
134 case OptionType::PrefixList:
135 return "AutoGeneratedPrefixList" + Name;
136 case OptionType::Parameter:
137 return "AutoGeneratedParameter" + Name;
138 case OptionType::ParameterList:
140 return "AutoGeneratedParameterList" + Name;
146 // Global option description
148 namespace GlobalOptionDescriptionFlags {
149 enum GlobalOptionDescriptionFlags { Required = 0x1 };
152 struct GlobalOptionDescription : public OptionDescription {
156 // We need t provide a default constructor since
157 // StringMap can only store DefaultConstructible objects
158 GlobalOptionDescription() : OptionDescription(), Flags(0)
161 GlobalOptionDescription (OptionType::OptionType t, const std::string& n)
162 : OptionDescription(t, n), Help(DefaultHelpString), Flags(0)
165 bool isRequired() const {
166 return Flags & GlobalOptionDescriptionFlags::Required;
169 Flags |= GlobalOptionDescriptionFlags::Required;
172 // Merge two option descriptions
173 void Merge (const GlobalOptionDescription& other)
175 if (other.Type != Type)
176 throw "Conflicting definitions for the option " + Name + "!";
178 if (Help == DefaultHelpString)
180 else if (other.Help != DefaultHelpString) {
181 llvm::cerr << "Warning: more than one help string defined for option "
185 Flags |= other.Flags;
189 // A GlobalOptionDescription array
190 // + some flags affecting generation of option declarations
191 struct GlobalOptionDescriptions {
192 typedef StringMap<GlobalOptionDescription> container_type;
193 typedef container_type::const_iterator const_iterator;
195 // A list of GlobalOptionDescriptions
196 container_type Descriptions;
197 // Should the emitter generate a "cl::sink" option?
200 const GlobalOptionDescription& FindOption(const std::string& OptName) const {
201 const_iterator I = Descriptions.find(OptName);
202 if (I != Descriptions.end())
205 throw OptName + ": no such option!";
208 // Support for STL-style iteration
209 const_iterator begin() const { return Descriptions.begin(); }
210 const_iterator end() const { return Descriptions.end(); }
214 // Tool-local option description
216 // Properties without arguments are implemented as flags
217 namespace ToolOptionDescriptionFlags {
218 enum ToolOptionDescriptionFlags { StopCompilation = 0x1,
219 Forward = 0x2, UnpackValues = 0x4};
221 namespace OptionPropertyType {
222 enum OptionPropertyType { AppendCmd };
225 typedef std::pair<OptionPropertyType::OptionPropertyType, std::string>
227 typedef SmallVector<OptionProperty, 4> OptionPropertyList;
229 struct ToolOptionDescription : public OptionDescription {
231 OptionPropertyList Props;
233 // StringMap can only store DefaultConstructible objects
234 ToolOptionDescription() : OptionDescription(), Flags(0) {}
236 ToolOptionDescription (OptionType::OptionType t, const std::string& n)
237 : OptionDescription(t, n)
240 // Various boolean properties
241 bool isStopCompilation() const {
242 return Flags & ToolOptionDescriptionFlags::StopCompilation;
244 void setStopCompilation() {
245 Flags |= ToolOptionDescriptionFlags::StopCompilation;
248 bool isForward() const {
249 return Flags & ToolOptionDescriptionFlags::Forward;
252 Flags |= ToolOptionDescriptionFlags::Forward;
255 bool isUnpackValues() const {
256 return Flags & ToolOptionDescriptionFlags::UnpackValues;
258 void setUnpackValues() {
259 Flags |= ToolOptionDescriptionFlags::UnpackValues;
262 void AddProperty (OptionPropertyType::OptionPropertyType t,
263 const std::string& val)
265 Props.push_back(std::make_pair(t, val));
269 typedef StringMap<ToolOptionDescription> ToolOptionDescriptions;
271 // Tool information record
273 namespace ToolFlags {
274 enum ToolFlags { Join = 0x1, Sink = 0x2 };
277 struct ToolProperties : public RefCountedBase<ToolProperties> {
280 std::string InLanguage;
281 std::string OutLanguage;
282 std::string OutputSuffix;
284 ToolOptionDescriptions OptDescs;
286 // Various boolean properties
287 void setSink() { Flags |= ToolFlags::Sink; }
288 bool isSink() const { return Flags & ToolFlags::Sink; }
289 void setJoin() { Flags |= ToolFlags::Join; }
290 bool isJoin() const { return Flags & ToolFlags::Join; }
292 // Default ctor here is needed because StringMap can only store
293 // DefaultConstructible objects
294 ToolProperties() : Flags(0) {}
295 ToolProperties (const std::string& n) : Name(n), Flags(0) {}
299 // A list of Tool information records
300 // IntrusiveRefCntPtrs are used because StringMap has no copy constructor
301 // (and we want to avoid copying ToolProperties anyway)
302 typedef std::vector<IntrusiveRefCntPtr<ToolProperties> > ToolPropertiesList;
305 // Function object for iterating over a list of tool property records
306 class CollectProperties {
309 /// Implementation details
311 // "Property handler" - a function that extracts information
312 // about a given tool property from its DAG representation
313 typedef void (CollectProperties::*PropertyHandler)(DagInit*);
315 // Map from property names -> property handlers
316 typedef StringMap<PropertyHandler> PropertyHandlerMap;
318 // "Option property handler" - a function that extracts information
319 // about a given option property from its DAG representation
320 typedef void (CollectProperties::*
321 OptionPropertyHandler)(DagInit*, GlobalOptionDescription &);
323 // Map from option property names -> option property handlers
324 typedef StringMap<OptionPropertyHandler> OptionPropertyHandlerMap;
326 // Static maps from strings to CollectProperties methods("handlers")
327 static PropertyHandlerMap propertyHandlers_;
328 static OptionPropertyHandlerMap optionPropertyHandlers_;
329 static bool staticMembersInitialized_;
332 /// This is where the information is stored
334 // Current Tool properties
335 ToolProperties& toolProps_;
336 // OptionDescriptions table(used to register options globally)
337 GlobalOptionDescriptions& optDescs_;
341 explicit CollectProperties (ToolProperties& p, GlobalOptionDescriptions& d)
342 : toolProps_(p), optDescs_(d)
344 if (!staticMembersInitialized_) {
345 // Init tool property handlers
346 propertyHandlers_["cmd_line"] = &CollectProperties::onCmdLine;
347 propertyHandlers_["in_language"] = &CollectProperties::onInLanguage;
348 propertyHandlers_["join"] = &CollectProperties::onJoin;
349 propertyHandlers_["out_language"] = &CollectProperties::onOutLanguage;
350 propertyHandlers_["output_suffix"] = &CollectProperties::onOutputSuffix;
351 propertyHandlers_["parameter_option"]
352 = &CollectProperties::onParameter;
353 propertyHandlers_["parameter_list_option"] =
354 &CollectProperties::onParameterList;
355 propertyHandlers_["prefix_option"] = &CollectProperties::onPrefix;
356 propertyHandlers_["prefix_list_option"] =
357 &CollectProperties::onPrefixList;
358 propertyHandlers_["sink"] = &CollectProperties::onSink;
359 propertyHandlers_["switch_option"] = &CollectProperties::onSwitch;
361 // Init option property handlers
362 optionPropertyHandlers_["append_cmd"] = &CollectProperties::onAppendCmd;
363 optionPropertyHandlers_["forward"] = &CollectProperties::onForward;
364 optionPropertyHandlers_["help"] = &CollectProperties::onHelp;
365 optionPropertyHandlers_["required"] = &CollectProperties::onRequired;
366 optionPropertyHandlers_["stop_compilation"] =
367 &CollectProperties::onStopCompilation;
368 optionPropertyHandlers_["unpack_values"] =
369 &CollectProperties::onUnpackValues;
371 staticMembersInitialized_ = true;
375 // Gets called for every tool property;
376 // Just forwards to the corresponding property handler.
377 void operator() (Init* i) {
378 DagInit& d = dynamic_cast<DagInit&>(*i);
379 const std::string& property_name = d.getOperator()->getAsString();
380 PropertyHandlerMap::iterator method
381 = propertyHandlers_.find(property_name);
383 if (method != propertyHandlers_.end()) {
384 PropertyHandler h = method->second;
388 throw "Unknown tool property: " + property_name + "!";
394 /// Property handlers --
395 /// Functions that extract information about tool properties from
396 /// DAG representation.
398 void onCmdLine (DagInit* d) {
399 checkNumberOfArguments(d, 1);
400 SplitString(InitPtrToString(d->getArg(0)), toolProps_.CmdLine);
401 if (toolProps_.CmdLine.empty())
402 throw "Tool " + toolProps_.Name + " has empty command line!";
405 void onInLanguage (DagInit* d) {
406 checkNumberOfArguments(d, 1);
407 toolProps_.InLanguage = InitPtrToString(d->getArg(0));
410 void onJoin (DagInit* d) {
411 checkNumberOfArguments(d, 0);
412 toolProps_.setJoin();
415 void onOutLanguage (DagInit* d) {
416 checkNumberOfArguments(d, 1);
417 toolProps_.OutLanguage = InitPtrToString(d->getArg(0));
420 void onOutputSuffix (DagInit* d) {
421 checkNumberOfArguments(d, 1);
422 toolProps_.OutputSuffix = InitPtrToString(d->getArg(0));
425 void onSink (DagInit* d) {
426 checkNumberOfArguments(d, 0);
427 optDescs_.HasSink = true;
428 toolProps_.setSink();
431 void onSwitch (DagInit* d) { addOption(d, OptionType::Switch); }
432 void onParameter (DagInit* d) { addOption(d, OptionType::Parameter); }
433 void onParameterList (DagInit* d) { addOption(d, OptionType::ParameterList); }
434 void onPrefix (DagInit* d) { addOption(d, OptionType::Prefix); }
435 void onPrefixList (DagInit* d) { addOption(d, OptionType::PrefixList); }
437 /// Option property handlers --
438 /// Methods that handle properties that are common for all types of
439 /// options (like append_cmd, stop_compilation)
441 void onAppendCmd (DagInit* d, GlobalOptionDescription& o) {
442 checkNumberOfArguments(d, 1);
443 std::string const& cmd = InitPtrToString(d->getArg(0));
445 toolProps_.OptDescs[o.Name].AddProperty(OptionPropertyType::AppendCmd, cmd);
448 void onForward (DagInit* d, GlobalOptionDescription& o) {
449 checkNumberOfArguments(d, 0);
450 toolProps_.OptDescs[o.Name].setForward();
453 void onHelp (DagInit* d, GlobalOptionDescription& o) {
454 checkNumberOfArguments(d, 1);
455 const std::string& help_message = InitPtrToString(d->getArg(0));
457 o.Help = help_message;
460 void onRequired (DagInit* d, GlobalOptionDescription& o) {
461 checkNumberOfArguments(d, 0);
465 void onStopCompilation (DagInit* d, GlobalOptionDescription& o) {
466 checkNumberOfArguments(d, 0);
467 if (o.Type != OptionType::Switch)
468 throw std::string("Only options of type Switch can stop compilation!");
469 toolProps_.OptDescs[o.Name].setStopCompilation();
472 void onUnpackValues (DagInit* d, GlobalOptionDescription& o) {
473 checkNumberOfArguments(d, 0);
474 toolProps_.OptDescs[o.Name].setUnpackValues();
479 // Add an option of type t
480 void addOption (DagInit* d, OptionType::OptionType t) {
481 checkNumberOfArguments(d, 2);
482 const std::string& name = InitPtrToString(d->getArg(0));
484 GlobalOptionDescription o(t, name);
485 toolProps_.OptDescs[name].Type = t;
486 toolProps_.OptDescs[name].Name = name;
487 processOptionProperties(d, o);
488 insertDescription(o);
491 // Insert new GlobalOptionDescription into GlobalOptionDescriptions list
492 void insertDescription (const GlobalOptionDescription& o)
494 if (optDescs_.Descriptions.count(o.Name)) {
495 GlobalOptionDescription& D = optDescs_.Descriptions[o.Name];
499 optDescs_.Descriptions[o.Name] = o;
503 // Go through the list of option properties and call a corresponding
507 // name - option name
508 // d - option property list
509 void processOptionProperties (DagInit* d, GlobalOptionDescription& o) {
510 // First argument is option name
511 checkNumberOfArguments(d, 2);
513 for (unsigned B = 1, E = d->getNumArgs(); B!=E; ++B) {
514 DagInit& option_property
515 = dynamic_cast<DagInit&>(*d->getArg(B));
516 const std::string& option_property_name
517 = option_property.getOperator()->getAsString();
518 OptionPropertyHandlerMap::iterator method
519 = optionPropertyHandlers_.find(option_property_name);
521 if (method != optionPropertyHandlers_.end()) {
522 OptionPropertyHandler h = method->second;
523 (this->*h)(&option_property, o);
526 throw "Unknown option property: " + option_property_name + "!";
532 // Static members of CollectProperties
533 CollectProperties::PropertyHandlerMap
534 CollectProperties::propertyHandlers_;
536 CollectProperties::OptionPropertyHandlerMap
537 CollectProperties::optionPropertyHandlers_;
539 bool CollectProperties::staticMembersInitialized_ = false;
542 // Gather information from the parsed TableGen data
543 // (Basically a wrapper for CollectProperties)
544 void CollectToolProperties (RecordVector::const_iterator B,
545 RecordVector::const_iterator E,
546 ToolPropertiesList& TPList,
547 GlobalOptionDescriptions& OptDescs)
549 // Iterate over a properties list of every Tool definition
551 RecordVector::value_type T = *B;
552 ListInit* PropList = T->getValueAsListInit("properties");
554 IntrusiveRefCntPtr<ToolProperties>
555 ToolProps(new ToolProperties(T->getName()));
557 std::for_each(PropList->begin(), PropList->end(),
558 CollectProperties(*ToolProps, OptDescs));
559 TPList.push_back(ToolProps);
563 // Used by EmitGenerateActionMethod
564 void EmitOptionPropertyHandlingCode (const ToolProperties& P,
565 const ToolOptionDescription& D,
569 O << Indent2 << "if (";
570 if (D.Type == OptionType::Switch)
571 O << D.GenVariableName();
573 O << '!' << D.GenVariableName() << ".empty()";
577 // Handle option properties that take an argument
578 for (OptionPropertyList::const_iterator B = D.Props.begin(),
579 E = D.Props.end(); B!=E; ++B) {
580 const OptionProperty& val = *B;
583 // (append_cmd cmd) property
584 case OptionPropertyType::AppendCmd:
585 O << Indent3 << "vec.push_back(\"" << val.second << "\");\n";
587 // Other properties with argument
595 // (forward) property
598 case OptionType::Switch:
599 O << Indent3 << "vec.push_back(\"-" << D.Name << "\");\n";
601 case OptionType::Parameter:
602 O << Indent3 << "vec.push_back(\"-" << D.Name << "\");\n";
603 O << Indent3 << "vec.push_back(" << D.GenVariableName() << ");\n";
605 case OptionType::Prefix:
606 O << Indent3 << "vec.push_back(\"-" << D.Name << "\" + "
607 << D.GenVariableName() << ");\n";
609 case OptionType::PrefixList:
610 O << Indent3 << "for (" << D.GenTypeDeclaration()
611 << "::iterator B = " << D.GenVariableName() << ".begin(),\n"
612 << Indent3 << "E = " << D.GenVariableName() << ".end(); B != E; ++B)\n"
613 << Indent4 << "vec.push_back(\"-" << D.Name << "\" + "
616 case OptionType::ParameterList:
617 O << Indent3 << "for (" << D.GenTypeDeclaration()
618 << "::iterator B = " << D.GenVariableName() << ".begin(),\n"
619 << Indent3 << "E = " << D.GenVariableName()
620 << ".end() ; B != E; ++B) {\n"
621 << Indent4 << "vec.push_back(\"-" << D.Name << "\");\n"
622 << Indent4 << "vec.push_back(*B);\n"
628 // (unpack_values) property
629 if (D.isUnpackValues()) {
630 if (IsListOptionType(D.Type)) {
631 O << Indent3 << "for (" << D.GenTypeDeclaration()
632 << "::iterator B = " << D.GenVariableName() << ".begin(),\n"
633 << Indent3 << "E = " << D.GenVariableName()
634 << ".end(); B != E; ++B)\n"
635 << Indent4 << "Tool::UnpackValues(*B, vec);\n";
637 else if (D.Type == OptionType::Prefix || D.Type == OptionType::Parameter){
638 O << Indent3 << "Tool::UnpackValues("
639 << D.GenVariableName() << ", vec);\n";
642 // TOFIX: move this to the type-checking phase
643 throw std::string("Switches can't have unpack_values property!");
648 O << Indent2 << "}\n";
651 // Emite one of two versions of GenerateAction method
652 void EmitGenerateActionMethod (const ToolProperties& P, int V, std::ostream& O)
654 assert(V==1 || V==2);
656 O << Indent1 << "Action GenerateAction(const PathVector& inFiles,\n";
658 O << Indent1 << "Action GenerateAction(const sys::Path& inFile,\n";
660 O << Indent2 << "const sys::Path& outFile) const\n"
662 << Indent2 << "std::vector<std::string> vec;\n";
664 // Parse CmdLine tool property
665 if(P.CmdLine.empty())
666 throw "Tool " + P.Name + " has empty command line!";
668 StrVector::const_iterator I = P.CmdLine.begin();
670 for (StrVector::const_iterator E = P.CmdLine.end(); I != E; ++I) {
671 const std::string& cmd = *I;
673 if (cmd == "$INFILE") {
675 O << "for (PathVector::const_iterator B = inFiles.begin()"
676 << ", E = inFiles.end();\n"
677 << Indent2 << "B != E; ++B)\n"
678 << Indent3 << "vec.push_back(B->toString());\n";
680 O << "vec.push_back(inFile.toString());\n";
682 else if (cmd == "$OUTFILE") {
683 O << "vec.push_back(outFile.toString());\n";
686 O << "vec.push_back(\"" << cmd << "\");\n";
690 // For every understood option, emit handling code
691 for (ToolOptionDescriptions::const_iterator B = P.OptDescs.begin(),
692 E = P.OptDescs.end(); B != E; ++B) {
693 const ToolOptionDescription& val = B->second;
694 EmitOptionPropertyHandlingCode(P, val, O);
697 // Handle Sink property
699 O << Indent2 << "if (!" << SinkOptionName << ".empty()) {\n"
700 << Indent3 << "vec.insert(vec.end(), "
701 << SinkOptionName << ".begin(), " << SinkOptionName << ".end());\n"
705 O << Indent2 << "return Action(\"" << P.CmdLine.at(0) << "\", vec);\n"
706 << Indent1 << "}\n\n";
709 // Emit GenerateAction methods for Tool classes
710 void EmitGenerateActionMethods (const ToolProperties& P, std::ostream& O) {
713 O << Indent1 << "Action GenerateAction(const PathVector& inFiles,\n"
714 << Indent2 << "const llvm::sys::Path& outFile) const\n"
716 << Indent2 << "throw std::runtime_error(\"" << P.Name
717 << " is not a Join tool!\");\n"
718 << Indent1 << "}\n\n";
720 EmitGenerateActionMethod(P, 1, O);
722 EmitGenerateActionMethod(P, 2, O);
725 // Emit IsLast() method for Tool classes
726 void EmitIsLastMethod (const ToolProperties& P, std::ostream& O) {
727 O << Indent1 << "bool IsLast() const {\n"
728 << Indent2 << "bool last = false;\n";
730 for (ToolOptionDescriptions::const_iterator B = P.OptDescs.begin(),
731 E = P.OptDescs.end(); B != E; ++B) {
732 const ToolOptionDescription& val = B->second;
734 if (val.isStopCompilation())
736 << "if (" << val.GenVariableName()
737 << ")\n" << Indent3 << "last = true;\n";
740 O << Indent2 << "return last;\n"
741 << Indent1 << "}\n\n";
744 // Emit static [Input,Output]Language() methods for Tool classes
745 void EmitInOutLanguageMethods (const ToolProperties& P, std::ostream& O) {
746 O << Indent1 << "const char* InputLanguage() const {\n"
747 << Indent2 << "return \"" << P.InLanguage << "\";\n"
748 << Indent1 << "}\n\n";
750 O << Indent1 << "const char* OutputLanguage() const {\n"
751 << Indent2 << "return \"" << P.OutLanguage << "\";\n"
752 << Indent1 << "}\n\n";
755 // Emit static [Input,Output]Language() methods for Tool classes
756 void EmitOutputSuffixMethod (const ToolProperties& P, std::ostream& O) {
757 O << Indent1 << "const char* OutputSuffix() const {\n"
758 << Indent2 << "return \"" << P.OutputSuffix << "\";\n"
759 << Indent1 << "}\n\n";
762 // Emit static Name() method for Tool classes
763 void EmitNameMethod (const ToolProperties& P, std::ostream& O) {
764 O << Indent1 << "const char* Name() const {\n"
765 << Indent2 << "return \"" << P.Name << "\";\n"
766 << Indent1 << "}\n\n";
769 // Emit static Name() method for Tool classes
770 void EmitIsJoinMethod (const ToolProperties& P, std::ostream& O) {
771 O << Indent1 << "bool IsJoin() const {\n";
773 O << Indent2 << "return true;\n";
775 O << Indent2 << "return false;\n";
776 O << Indent1 << "}\n\n";
779 // Emit a Tool class definition
780 void EmitToolClassDefinition (const ToolProperties& P, std::ostream& O) {
786 O << "class " << P.Name << " : public ";
791 O << " {\npublic:\n";
793 EmitNameMethod(P, O);
794 EmitInOutLanguageMethods(P, O);
795 EmitOutputSuffixMethod(P, O);
796 EmitIsJoinMethod(P, O);
797 EmitGenerateActionMethods(P, O);
798 EmitIsLastMethod(P, O);
800 // Close class definition
804 // Iterate over a list of option descriptions and emit registration code
805 void EmitOptionDescriptions (const GlobalOptionDescriptions& descs,
808 // Emit static cl::Option variables
809 for (GlobalOptionDescriptions::const_iterator B = descs.begin(),
810 E = descs.end(); B!=E; ++B) {
811 const GlobalOptionDescription& val = B->second;
813 O << val.GenTypeDeclaration() << ' '
814 << val.GenVariableName()
815 << "(\"" << val.Name << '\"';
817 if (val.Type == OptionType::Prefix || val.Type == OptionType::PrefixList)
820 if (val.isRequired()) {
822 case OptionType::PrefixList:
823 case OptionType::ParameterList:
824 O << ", cl::OneOrMore";
827 O << ", cl::Required";
831 O << ", cl::desc(\"" << val.Help << "\"));\n";
835 O << "cl::list<std::string> " << SinkOptionName << "(cl::Sink);\n";
840 void EmitPopulateLanguageMap (const RecordKeeper& Records, std::ostream& O)
842 // Get the relevant field out of RecordKeeper
843 Record* LangMapRecord = Records.getDef("LanguageMap");
845 throw std::string("Language map definition not found!");
847 ListInit* LangsToSuffixesList = LangMapRecord->getValueAsListInit("map");
848 if (!LangsToSuffixesList)
849 throw std::string("Error in the language map definition!");
852 O << "void llvmc::PopulateLanguageMap(LanguageMap& language_map) {\n";
854 for (unsigned i = 0; i < LangsToSuffixesList->size(); ++i) {
855 Record* LangToSuffixes = LangsToSuffixesList->getElementAsRecord(i);
857 const std::string& Lang = LangToSuffixes->getValueAsString("lang");
858 const ListInit* Suffixes = LangToSuffixes->getValueAsListInit("suffixes");
860 for (unsigned i = 0; i < Suffixes->size(); ++i)
861 O << Indent1 << "language_map[\""
862 << InitPtrToString(Suffixes->getElement(i))
863 << "\"] = \"" << Lang << "\";\n";
869 // Fills in two tables that map tool names to (input, output) languages.
870 // Used by the typechecker.
871 void FillInToolToLang (const ToolPropertiesList& TPList,
872 StringMap<std::string>& ToolToInLang,
873 StringMap<std::string>& ToolToOutLang) {
874 for (ToolPropertiesList::const_iterator B = TPList.begin(), E = TPList.end();
876 const ToolProperties& P = *(*B);
877 ToolToInLang[P.Name] = P.InLanguage;
878 ToolToOutLang[P.Name] = P.OutLanguage;
882 // Check that all output and input language names match.
883 // TOFIX: check for cycles.
884 // TOFIX: check for multiple default edges.
885 void TypecheckGraph (Record* CompilationGraph,
886 const ToolPropertiesList& TPList) {
887 StringMap<std::string> ToolToInLang;
888 StringMap<std::string> ToolToOutLang;
890 FillInToolToLang(TPList, ToolToInLang, ToolToOutLang);
891 ListInit* edges = CompilationGraph->getValueAsListInit("edges");
892 StringMap<std::string>::iterator IAE = ToolToInLang.end();
893 StringMap<std::string>::iterator IBE = ToolToOutLang.end();
895 for (unsigned i = 0; i < edges->size(); ++i) {
896 Record* Edge = edges->getElementAsRecord(i);
897 Record* A = Edge->getValueAsDef("a");
898 Record* B = Edge->getValueAsDef("b");
899 StringMap<std::string>::iterator IA = ToolToOutLang.find(A->getName());
900 StringMap<std::string>::iterator IB = ToolToInLang.find(B->getName());
902 throw A->getName() + ": no such tool!";
904 throw B->getName() + ": no such tool!";
905 if(A->getName() != "root" && IA->second != IB->second)
906 throw "Edge " + A->getName() + "->" + B->getName()
907 + ": output->input language mismatch";
908 if(B->getName() == "root")
909 throw std::string("Edges back to the root are not allowed!");
913 // Helper function used by EmitEdgePropertyTest.
914 void EmitEdgePropertyTest1Arg(const DagInit& Prop,
915 const GlobalOptionDescriptions& OptDescs,
917 checkNumberOfArguments(&Prop, 1);
918 const std::string& OptName = InitPtrToString(Prop.getArg(0));
919 const GlobalOptionDescription& OptDesc = OptDescs.FindOption(OptName);
920 if (OptDesc.Type != OptionType::Switch)
921 throw OptName + ": incorrect option type!";
922 O << OptDesc.GenVariableName();
925 // Helper function used by EmitEdgePropertyTest.
926 void EmitEdgePropertyTest2Args(const std::string& PropName,
928 const GlobalOptionDescriptions& OptDescs,
930 checkNumberOfArguments(&Prop, 2);
931 const std::string& OptName = InitPtrToString(Prop.getArg(0));
932 const std::string& OptArg = InitPtrToString(Prop.getArg(1));
933 const GlobalOptionDescription& OptDesc = OptDescs.FindOption(OptName);
935 if (PropName == "parameter_equals") {
936 if (OptDesc.Type != OptionType::Parameter
937 && OptDesc.Type != OptionType::Prefix)
938 throw OptName + ": incorrect option type!";
939 O << OptDesc.GenVariableName() << " == \"" << OptArg << "\"";
941 else if (PropName == "element_in_list") {
942 if (OptDesc.Type != OptionType::ParameterList
943 && OptDesc.Type != OptionType::PrefixList)
944 throw OptName + ": incorrect option type!";
945 const std::string& VarName = OptDesc.GenVariableName();
946 O << "std::find(" << VarName << ".begin(),\n"
947 << Indent3 << VarName << ".end(), \""
948 << OptArg << "\") != " << VarName << ".end()";
951 throw PropName + ": unknown edge property!";
954 // Helper function used by EmitEdgeClass.
955 void EmitEdgePropertyTest(const std::string& PropName,
957 const GlobalOptionDescriptions& OptDescs,
959 if (PropName == "switch_on")
960 EmitEdgePropertyTest1Arg(Prop, OptDescs, O);
962 EmitEdgePropertyTest2Args(PropName, Prop, OptDescs, O);
965 // Emit a single Edge* class.
966 void EmitEdgeClass(unsigned N, const std::string& Target,
967 ListInit* Props, const GlobalOptionDescriptions& OptDescs,
969 bool IsDefault = false;
971 // Class constructor.
972 O << "class Edge" << N << ": public Edge {\n"
974 << Indent1 << "Edge" << N << "() : Edge(\"" << Target
977 // Function isEnabled().
978 << Indent1 << "bool isEnabled() const {\n"
979 << Indent2 << "bool ret = false;\n";
981 for (size_t i = 0, PropsSize = Props->size(); i < PropsSize; ++i) {
982 const DagInit& Prop = dynamic_cast<DagInit&>(*Props->getElement(i));
983 const std::string& PropName = Prop.getOperator()->getAsString();
985 if (PropName == "default")
988 O << Indent2 << "if (ret || (";
989 if (PropName == "and") {
991 for (unsigned j = 0, NumArgs = Prop.getNumArgs(); j < NumArgs; ++j) {
992 const DagInit& InnerProp = dynamic_cast<DagInit&>(*Prop.getArg(j));
993 const std::string& InnerPropName =
994 InnerProp.getOperator()->getAsString();
995 EmitEdgePropertyTest(InnerPropName, InnerProp, OptDescs, O);
996 if (j != NumArgs - 1)
997 O << ")\n" << Indent3 << " && (";
1003 EmitEdgePropertyTest(PropName, Prop, OptDescs, O);
1005 O << "))\n" << Indent3 << "ret = true;\n";
1008 O << Indent2 << "return ret;\n"
1009 << Indent1 << "};\n\n"
1011 // Function isDefault().
1012 << Indent1 << "bool isDefault() const { return ";
1020 // Emit Edge* classes that represent graph edges.
1021 void EmitEdgeClasses (Record* CompilationGraph,
1022 const GlobalOptionDescriptions& OptDescs,
1024 ListInit* edges = CompilationGraph->getValueAsListInit("edges");
1026 for (unsigned i = 0; i < edges->size(); ++i) {
1027 Record* Edge = edges->getElementAsRecord(i);
1028 Record* B = Edge->getValueAsDef("b");
1029 ListInit* Props = Edge->getValueAsListInit("props");
1034 EmitEdgeClass(i, B->getName(), Props, OptDescs, O);
1038 void EmitPopulateCompilationGraph (Record* CompilationGraph,
1041 ListInit* edges = CompilationGraph->getValueAsListInit("edges");
1044 O << "void llvmc::PopulateCompilationGraph(CompilationGraph& G) {\n"
1045 << Indent1 << "PopulateLanguageMap(G.ExtsToLangs);\n\n";
1049 RecordVector Tools = Records.getAllDerivedDefinitions("Tool");
1051 throw std::string("No tool definitions found!");
1053 for (RecordVector::iterator B = Tools.begin(), E = Tools.end(); B != E; ++B) {
1054 const std::string& Name = (*B)->getName();
1056 O << Indent1 << "G.insertNode(new "
1057 << Name << "());\n";
1063 for (unsigned i = 0; i < edges->size(); ++i) {
1064 Record* Edge = edges->getElementAsRecord(i);
1065 Record* A = Edge->getValueAsDef("a");
1066 Record* B = Edge->getValueAsDef("b");
1067 ListInit* Props = Edge->getValueAsListInit("props");
1069 O << Indent1 << "G.insertEdge(\"" << A->getName() << "\", ";
1072 O << "new SimpleEdge(\"" << B->getName() << "\")";
1074 O << "new Edge" << i << "()";
1083 // End of anonymous namespace
1086 // Back-end entry point
1087 void LLVMCConfigurationEmitter::run (std::ostream &O) {
1089 EmitSourceFileHeader("LLVMC Configuration Library", O);
1091 // Get a list of all defined Tools
1092 RecordVector Tools = Records.getAllDerivedDefinitions("Tool");
1094 throw std::string("No tool definitions found!");
1096 // Gather information from the Tool descriptions
1097 ToolPropertiesList tool_props;
1098 GlobalOptionDescriptions opt_descs;
1099 CollectToolProperties(Tools.begin(), Tools.end(), tool_props, opt_descs);
1101 // Emit global option registration code
1102 EmitOptionDescriptions(opt_descs, O);
1104 // Emit PopulateLanguageMap function
1105 // (a language map maps from file extensions to language names)
1106 EmitPopulateLanguageMap(Records, O);
1108 // Emit Tool classes
1109 for (ToolPropertiesList::const_iterator B = tool_props.begin(),
1110 E = tool_props.end(); B!=E; ++B)
1111 EmitToolClassDefinition(*(*B), O);
1113 Record* CompilationGraphRecord = Records.getDef("CompilationGraph");
1114 if (!CompilationGraphRecord)
1115 throw std::string("Compilation graph description not found!");
1117 // Typecheck the compilation graph.
1118 TypecheckGraph(CompilationGraphRecord, tool_props);
1120 // Emit Edge* classes.
1121 EmitEdgeClasses(CompilationGraphRecord, opt_descs, O);
1123 // Emit PopulateCompilationGraph function
1124 EmitPopulateCompilationGraph(CompilationGraphRecord, O);