blob: 5db3d03869c2d81ce878879cc08ac0427d1b3709 [file] [log] [blame]
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001//===- LLVMCConfigurationEmitter.cpp - Generate LLVMCC config -------------===//
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 LLVMCC configuration code.
11//
12//===----------------------------------------------------------------------===//
13
14#include "LLVMCCConfigurationEmitter.h"
15#include "Record.h"
16
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"
22
23#include <algorithm>
24#include <cassert>
25#include <functional>
26#include <string>
27
28using namespace llvm;
29
30namespace {
31
32//===----------------------------------------------------------------------===//
33/// Typedefs
34
35typedef std::vector<Record*> RecordVector;
36typedef std::vector<std::string> StrVector;
37
38//===----------------------------------------------------------------------===//
39/// Constants
40
41// Indentation strings
42const char * Indent1 = " ";
43const char * Indent2 = " ";
44const char * Indent3 = " ";
45const char * Indent4 = " ";
46
47// Default help string
48const char * DefaultHelpString = "NO HELP MESSAGE PROVIDED";
49
50// Name for the "sink" option
51const char * SinkOptionName = "AutoGeneratedSinkOption";
52
53//===----------------------------------------------------------------------===//
54/// Helper functions
55
56std::string InitPtrToString(Init* ptr) {
57 StringInit& val = dynamic_cast<StringInit&>(*ptr);
58 return val.getValue();
59}
60
61//===----------------------------------------------------------------------===//
62/// Back-end specific code
63
64// A command-line option can have one of the following types:
65//
66// Switch - a simple switch w/o arguments, e.g. -O2
67//
68// Parameter - an option that takes one(and only one) argument, e.g. -o file,
69// --output=file
70//
71// ParameterList - same as Parameter, but more than one occurence
72// of the option is allowed, e.g. -lm -lpthread
73//
74// Prefix - argument is everything after the prefix,
75// e.g. -Wa,-foo,-bar, -DNAME=VALUE
76//
77// PrefixList - same as Prefix, but more than one option occurence is
78// allowed
79
80namespace OptionType {
81 enum OptionType { Switch, Parameter, ParameterList, Prefix, PrefixList};
82}
83
84bool IsListOptionType (OptionType::OptionType t) {
85 return (t == OptionType::ParameterList || t == OptionType::PrefixList);
86}
87
88// Code duplication here is necessary because one option can affect
89// several tools and those tools may have different actions associated
90// with this option. GlobalOptionDescriptions are used to generate
91// the option registration code, while ToolOptionDescriptions are used
92// to generate tool-specific code.
93
94// Base class for option descriptions
95
96struct OptionDescription {
97 OptionType::OptionType Type;
98 std::string Name;
99
100 OptionDescription(OptionType::OptionType t = OptionType::Switch,
101 const std::string& n = "")
102 : Type(t), Name(n)
103 {}
104
105 const char* GenTypeDeclaration() const {
106 switch (Type) {
107 case OptionType::PrefixList:
108 case OptionType::ParameterList:
109 return "cl::list<std::string>";
110 case OptionType::Switch:
111 return "cl::opt<bool>";
112 case OptionType::Parameter:
113 case OptionType::Prefix:
114 default:
115 return "cl::opt<std::string>";
116 }
117 }
118
119 std::string GenVariableName() const {
120 switch (Type) {
121 case OptionType::Switch:
122 return "AutoGeneratedSwitch" + Name;
123 case OptionType::Prefix:
124 return "AutoGeneratedPrefix" + Name;
125 case OptionType::PrefixList:
126 return "AutoGeneratedPrefixList" + Name;
127 case OptionType::Parameter:
128 return "AutoGeneratedParameter" + Name;
129 case OptionType::ParameterList:
130 default:
131 return "AutoGeneratedParameterList" + Name;
132 }
133 }
134
135};
136
137// Global option description
138
139namespace GlobalOptionDescriptionFlags {
140 enum GlobalOptionDescriptionFlags { Required = 0x1 };
141}
142
143struct GlobalOptionDescription : public OptionDescription {
144 std::string Help;
145 unsigned Flags;
146
147 // StringMap can only store DefaultConstructible objects
148 GlobalOptionDescription() : OptionDescription(), Flags(0)
149 {}
150
151 GlobalOptionDescription (OptionType::OptionType t, const std::string& n)
152 : OptionDescription(t, n), Help(DefaultHelpString), Flags(0)
153 {}
154
155 bool isRequired() const {
156 return Flags & GlobalOptionDescriptionFlags::Required;
157 }
158 void setRequired() {
159 Flags |= GlobalOptionDescriptionFlags::Required;
160 }
161
162 // Merge two option descriptions
163 void Merge (const GlobalOptionDescription& other)
164 {
165 if (other.Type != Type)
166 throw "Conflicting definitions for the option " + Name + "!";
167
168 if (Help.empty() && !other.Help.empty())
169 Help = other.Help;
170 else if (!Help.empty() && !other.Help.empty())
171 cerr << "Warning: more than one help string defined for option "
172 + Name + "\n";
173
174 Flags |= other.Flags;
175 }
176};
177
178// A GlobalOptionDescription array
179// + some flags affecting generation of option declarations
180struct GlobalOptionDescriptions {
181 typedef StringMap<GlobalOptionDescription> container_type;
182 typedef container_type::const_iterator const_iterator;
183
184 // A list of GlobalOptionDescriptions
185 container_type Descriptions;
186 // Should the emitter generate a "cl::sink" option?
187 bool HasSink;
188
189 // Support for STL-style iteration
190 const_iterator begin() const { return Descriptions.begin(); }
191 const_iterator end() const { return Descriptions.end(); }
192};
193
194
195// Tool-local option description
196
197// Properties without arguments are implemented as flags
198namespace ToolOptionDescriptionFlags {
199 enum ToolOptionDescriptionFlags { StopCompilation = 0x1,
200 Forward = 0x2, UnpackValues = 0x4};
201}
202namespace OptionPropertyType {
203 enum OptionPropertyType { AppendCmd };
204}
205
206typedef std::pair<OptionPropertyType::OptionPropertyType, std::string>
207OptionProperty;
208typedef SmallVector<OptionProperty, 4> OptionPropertyList;
209
210struct ToolOptionDescription : public OptionDescription {
211 unsigned Flags;
212 OptionPropertyList Props;
213
214 // StringMap can only store DefaultConstructible objects
Mikhail Glushenkov18cbe892008-03-27 09:53:47 +0000215 ToolOptionDescription() : OptionDescription(), Flags(0) {}
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000216
217 ToolOptionDescription (OptionType::OptionType t, const std::string& n)
218 : OptionDescription(t, n)
219 {}
220
221 // Various boolean properties
222 bool isStopCompilation() const {
223 return Flags & ToolOptionDescriptionFlags::StopCompilation;
224 }
225 void setStopCompilation() {
226 Flags |= ToolOptionDescriptionFlags::StopCompilation;
227 }
228
229 bool isForward() const {
230 return Flags & ToolOptionDescriptionFlags::Forward;
231 }
232 void setForward() {
233 Flags |= ToolOptionDescriptionFlags::Forward;
234 }
235
236 bool isUnpackValues() const {
237 return Flags & ToolOptionDescriptionFlags::UnpackValues;
238 }
239 void setUnpackValues() {
240 Flags |= ToolOptionDescriptionFlags::UnpackValues;
241 }
242
243 void AddProperty (OptionPropertyType::OptionPropertyType t,
244 const std::string& val)
245 {
246 Props.push_back(std::make_pair(t, val));
247 }
248};
249
250typedef StringMap<ToolOptionDescription> ToolOptionDescriptions;
251
252// Tool information record
253
254namespace ToolFlags {
255 enum ToolFlags { Join = 0x1, Sink = 0x2 };
256}
257
258struct ToolProperties : public RefCountedBase<ToolProperties> {
259 std::string Name;
260 StrVector CmdLine;
261 std::string InLanguage;
262 std::string OutLanguage;
263 std::string OutputSuffix;
264 unsigned Flags;
265 ToolOptionDescriptions OptDescs;
266
267 // Various boolean properties
268 void setSink() { Flags |= ToolFlags::Sink; }
269 bool isSink() const { return Flags & ToolFlags::Sink; }
270 void setJoin() { Flags |= ToolFlags::Join; }
271 bool isJoin() const { return Flags & ToolFlags::Join; }
272
273 // Default ctor here is needed because StringMap can only store
274 // DefaultConstructible objects
275 ToolProperties() {}
276 ToolProperties (const std::string& n) : Name(n) {}
277};
278
279
280// A list of Tool information records
281// IntrusiveRefCntPtrs are used because StringMap has no copy constructor
282// (and we want to avoid copying ToolProperties anyway)
283typedef std::vector<IntrusiveRefCntPtr<ToolProperties> > ToolPropertiesList;
284
285
286// Function object for iterating over a list of tool property records
287class CollectProperties {
288private:
289
290 /// Implementation details
291
292 // "Property handler" - a function that extracts information
293 // about a given tool property from its DAG representation
294 typedef void (CollectProperties::*PropertyHandler)(DagInit*);
295
296 // Map from property names -> property handlers
297 typedef StringMap<PropertyHandler> PropertyHandlerMap;
298
299 // "Option property handler" - a function that extracts information
300 // about a given option property from its DAG representation
301 typedef void (CollectProperties::*
302 OptionPropertyHandler)(DagInit*, GlobalOptionDescription &);
303
304 // Map from option property names -> option property handlers
305 typedef StringMap<OptionPropertyHandler> OptionPropertyHandlerMap;
306
307 // Static maps from strings to CollectProperties methods("handlers")
308 static PropertyHandlerMap propertyHandlers_;
309 static OptionPropertyHandlerMap optionPropertyHandlers_;
310 static bool staticMembersInitialized_;
311
312
313 /// This is where the information is stored
314
315 // Current Tool properties
316 ToolProperties& toolProps_;
317 // OptionDescriptions table(used to register options globally)
318 GlobalOptionDescriptions& optDescs_;
319
320public:
321
322 explicit CollectProperties (ToolProperties& p, GlobalOptionDescriptions& d)
323 : toolProps_(p), optDescs_(d)
324 {
325 if (!staticMembersInitialized_) {
326 // Init tool property handlers
327 propertyHandlers_["cmd_line"] = &CollectProperties::onCmdLine;
328 propertyHandlers_["in_language"] = &CollectProperties::onInLanguage;
329 propertyHandlers_["join"] = &CollectProperties::onJoin;
330 propertyHandlers_["out_language"] = &CollectProperties::onOutLanguage;
331 propertyHandlers_["output_suffix"] = &CollectProperties::onOutputSuffix;
332 propertyHandlers_["parameter_option"]
333 = &CollectProperties::onParameter;
334 propertyHandlers_["parameter_list_option"] =
335 &CollectProperties::onParameterList;
336 propertyHandlers_["prefix_option"] = &CollectProperties::onPrefix;
337 propertyHandlers_["prefix_list_option"] =
338 &CollectProperties::onPrefixList;
339 propertyHandlers_["sink"] = &CollectProperties::onSink;
340 propertyHandlers_["switch_option"] = &CollectProperties::onSwitch;
341
342 // Init option property handlers
343 optionPropertyHandlers_["append_cmd"] = &CollectProperties::onAppendCmd;
344 optionPropertyHandlers_["forward"] = &CollectProperties::onForward;
345 optionPropertyHandlers_["help"] = &CollectProperties::onHelp;
346 optionPropertyHandlers_["required"] = &CollectProperties::onRequired;
347 optionPropertyHandlers_["stop_compilation"] =
348 &CollectProperties::onStopCompilation;
349 optionPropertyHandlers_["unpack_values"] =
350 &CollectProperties::onUnpackValues;
351
352 staticMembersInitialized_ = true;
353 }
354 }
355
356 // Gets called for every tool property;
357 // Just forwards to the corresponding property handler.
358 void operator() (Init* i) {
359 DagInit& d = dynamic_cast<DagInit&>(*i);
360 std::string property_name = d.getOperator()->getAsString();
361 PropertyHandlerMap::iterator method
362 = propertyHandlers_.find(property_name);
363
364 if (method != propertyHandlers_.end()) {
365 PropertyHandler h = method->second;
366 (this->*h)(&d);
367 }
368 else {
369 throw "Unknown tool property: " + property_name + "!";
370 }
371 }
372
373private:
374
375 /// Property handlers --
376 /// Functions that extract information about tool properties from
377 /// DAG representation.
378
379 void onCmdLine (DagInit* d) {
380 checkNumberOfArguments(d, 1);
381 SplitString(InitPtrToString(d->getArg(0)), toolProps_.CmdLine);
382 if (toolProps_.CmdLine.empty())
Mikhail Glushenkov2cfd2232008-05-06 16:35:25 +0000383 throw "Tool " + toolProps_.Name + " has empty command line!";
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000384 }
385
386 void onInLanguage (DagInit* d) {
387 checkNumberOfArguments(d, 1);
388 toolProps_.InLanguage = InitPtrToString(d->getArg(0));
389 }
390
391 void onJoin (DagInit* d) {
392 checkNumberOfArguments(d, 0);
393 toolProps_.setJoin();
394 }
395
396 void onOutLanguage (DagInit* d) {
397 checkNumberOfArguments(d, 1);
398 toolProps_.OutLanguage = InitPtrToString(d->getArg(0));
399 }
400
401 void onOutputSuffix (DagInit* d) {
402 checkNumberOfArguments(d, 1);
403 toolProps_.OutputSuffix = InitPtrToString(d->getArg(0));
404 }
405
406 void onSink (DagInit* d) {
407 checkNumberOfArguments(d, 0);
408 optDescs_.HasSink = true;
409 toolProps_.setSink();
410 }
411
412 void onSwitch (DagInit* d) { addOption(d, OptionType::Switch); }
413 void onParameter (DagInit* d) { addOption(d, OptionType::Parameter); }
414 void onParameterList (DagInit* d) { addOption(d, OptionType::ParameterList); }
415 void onPrefix (DagInit* d) { addOption(d, OptionType::Prefix); }
416 void onPrefixList (DagInit* d) { addOption(d, OptionType::PrefixList); }
417
418 /// Option property handlers --
419 /// Methods that handle properties that are common for all types of
420 /// options (like append_cmd, stop_compilation)
421
422 void onAppendCmd (DagInit* d, GlobalOptionDescription& o) {
423 checkNumberOfArguments(d, 1);
424 std::string const& cmd = InitPtrToString(d->getArg(0));
425
426 toolProps_.OptDescs[o.Name].AddProperty(OptionPropertyType::AppendCmd, cmd);
427 }
428
429 void onForward (DagInit* d, GlobalOptionDescription& o) {
430 checkNumberOfArguments(d, 0);
431 toolProps_.OptDescs[o.Name].setForward();
432 }
433
434 void onHelp (DagInit* d, GlobalOptionDescription& o) {
435 checkNumberOfArguments(d, 1);
436 const std::string& help_message = InitPtrToString(d->getArg(0));
437
438 o.Help = help_message;
439 }
440
441 void onRequired (DagInit* d, GlobalOptionDescription& o) {
442 checkNumberOfArguments(d, 0);
443 o.setRequired();
444 }
445
446 void onStopCompilation (DagInit* d, GlobalOptionDescription& o) {
447 checkNumberOfArguments(d, 0);
448 if (o.Type != OptionType::Switch)
449 throw std::string("Only options of type Switch can stop compilation!");
450 toolProps_.OptDescs[o.Name].setStopCompilation();
451 }
452
453 void onUnpackValues (DagInit* d, GlobalOptionDescription& o) {
454 checkNumberOfArguments(d, 0);
455 toolProps_.OptDescs[o.Name].setUnpackValues();
456 }
457
458 /// Helper functions
459
460 // Add an option of type t
461 void addOption (DagInit* d, OptionType::OptionType t) {
462 checkNumberOfArguments(d, 2);
463 const std::string& name = InitPtrToString(d->getArg(0));
464
465 GlobalOptionDescription o(t, name);
466 toolProps_.OptDescs[name].Type = t;
467 toolProps_.OptDescs[name].Name = name;
468 processOptionProperties(d, o);
469 insertDescription(o);
470 }
471
472 // Ensure that the number of args in d is <= min_arguments,
473 // throw exception otherwise
474 void checkNumberOfArguments (DagInit* d, unsigned min_arguments) {
475 if (d->getNumArgs() < min_arguments)
476 throw "Property " + d->getOperator()->getAsString()
477 + " has too few arguments!";
478 }
479
480 // Insert new GlobalOptionDescription into GlobalOptionDescriptions list
481 void insertDescription (const GlobalOptionDescription& o)
482 {
483 if (optDescs_.Descriptions.count(o.Name)) {
484 GlobalOptionDescription& D = optDescs_.Descriptions[o.Name];
485 D.Merge(o);
486 }
487 else {
488 optDescs_.Descriptions[o.Name] = o;
489 }
490 }
491
492 // Go through the list of option properties and call a corresponding
493 // handler for each.
494 //
495 // Parameters:
496 // name - option name
497 // d - option property list
498 void processOptionProperties (DagInit* d, GlobalOptionDescription& o) {
499 // First argument is option name
500 checkNumberOfArguments(d, 2);
501
502 for (unsigned B = 1, E = d->getNumArgs(); B!=E; ++B) {
503 DagInit& option_property
504 = dynamic_cast<DagInit&>(*d->getArg(B));
505 const std::string& option_property_name
506 = option_property.getOperator()->getAsString();
507 OptionPropertyHandlerMap::iterator method
508 = optionPropertyHandlers_.find(option_property_name);
509
510 if (method != optionPropertyHandlers_.end()) {
511 OptionPropertyHandler h = method->second;
512 (this->*h)(&option_property, o);
513 }
514 else {
515 throw "Unknown option property: " + option_property_name + "!";
516 }
517 }
518 }
519};
520
521// Static members of CollectProperties
522CollectProperties::PropertyHandlerMap
523CollectProperties::propertyHandlers_;
524
525CollectProperties::OptionPropertyHandlerMap
526CollectProperties::optionPropertyHandlers_;
527
528bool CollectProperties::staticMembersInitialized_ = false;
529
530
531// Gather information from the parsed TableGen data
532// (Basically a wrapper for CollectProperties)
533void CollectToolProperties (RecordVector::const_iterator B,
534 RecordVector::const_iterator E,
535 ToolPropertiesList& TPList,
536 GlobalOptionDescriptions& OptDescs)
537{
538 // Iterate over a properties list of every Tool definition
539 for (;B!=E;++B) {
540 RecordVector::value_type T = *B;
541 ListInit* PropList = T->getValueAsListInit("properties");
542 if (!PropList)
543 throw std::string("Tool has no property list!");
544
545 IntrusiveRefCntPtr<ToolProperties>
546 ToolProps(new ToolProperties(T->getName()));
547
548 std::for_each(PropList->begin(), PropList->end(),
549 CollectProperties(*ToolProps, OptDescs));
550 TPList.push_back(ToolProps);
551 }
552}
553
554// Used by EmitGenerateActionMethod
555void EmitOptionPropertyHandlingCode (const ToolProperties& P,
556 const ToolOptionDescription& D,
557 std::ostream& O)
558{
559 // if clause
560 O << Indent2 << "if (";
561 if (D.Type == OptionType::Switch)
562 O << D.GenVariableName();
563 else
564 O << '!' << D.GenVariableName() << ".empty()";
565
566 O <<") {\n";
567
568 // Handle option properties that take an argument
569 for (OptionPropertyList::const_iterator B = D.Props.begin(),
570 E = D.Props.end(); B!=E; ++B) {
571 const OptionProperty& val = *B;
572
573 switch (val.first) {
574 // (append_cmd cmd) property
575 case OptionPropertyType::AppendCmd:
576 O << Indent3 << "vec.push_back(\"" << val.second << "\");\n";
577 break;
578 // Other properties with argument
579 default:
580 break;
581 }
582 }
583
584 // Handle flags
585
586 // (forward) property
587 if (D.isForward()) {
588 switch (D.Type) {
589 case OptionType::Switch:
590 O << Indent3 << "vec.push_back(\"-" << D.Name << "\");\n";
591 break;
592 case OptionType::Parameter:
593 O << Indent3 << "vec.push_back(\"-" << D.Name << "\");\n";
594 O << Indent3 << "vec.push_back(" << D.GenVariableName() << ");\n";
595 break;
596 case OptionType::Prefix:
597 O << Indent3 << "vec.push_back(\"-" << D.Name << "\" + "
598 << D.GenVariableName() << ");\n";
599 break;
600 case OptionType::PrefixList:
601 O << Indent3 << "for (" << D.GenTypeDeclaration()
602 << "::iterator B = " << D.GenVariableName() << ".begin(),\n"
603 << Indent3 << "E = " << D.GenVariableName() << ".end(); B != E; ++B)\n"
604 << Indent4 << "vec.push_back(\"-" << D.Name << "\" + "
605 << "*B);\n";
606 break;
607 case OptionType::ParameterList:
608 O << Indent3 << "for (" << D.GenTypeDeclaration()
609 << "::iterator B = " << D.GenVariableName() << ".begin(),\n"
610 << Indent3 << "E = " << D.GenVariableName()
611 << ".end() ; B != E; ++B) {\n"
612 << Indent4 << "vec.push_back(\"-" << D.Name << "\");\n"
613 << Indent4 << "vec.push_back(*B);\n"
614 << Indent3 << "}\n";
615 break;
616 }
617 }
618
619 // (unpack_values) property
620 if (D.isUnpackValues()) {
621 if (IsListOptionType(D.Type)) {
622 O << Indent3 << "for (" << D.GenTypeDeclaration()
623 << "::iterator B = " << D.GenVariableName() << ".begin(),\n"
624 << Indent3 << "E = " << D.GenVariableName()
625 << ".end(); B != E; ++B)\n"
Mikhail Glushenkovafbeae92008-05-06 16:34:12 +0000626 << Indent4 << "Tool::UnpackValues(*B, vec);\n";
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000627 }
628 else if (D.Type == OptionType::Prefix || D.Type == OptionType::Parameter){
Mikhail Glushenkovafbeae92008-05-06 16:34:12 +0000629 O << Indent3 << "Tool::UnpackValues("
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000630 << D.GenVariableName() << ", vec);\n";
631 }
632 else {
633 // TOFIX: move this to the type-checking phase
634 throw std::string("Switches can't have unpack_values property!");
635 }
636 }
637
638 // close if clause
639 O << Indent2 << "}\n";
640}
641
642// Emite one of two versions of GenerateAction method
643void EmitGenerateActionMethod (const ToolProperties& P, int V, std::ostream& O)
644{
645 assert(V==1 || V==2);
646 if (V==1)
647 O << Indent1 << "Action GenerateAction(const PathVector& inFiles,\n";
648 else
649 O << Indent1 << "Action GenerateAction(const sys::Path& inFile,\n";
650
651 O << Indent2 << "const sys::Path& outFile) const\n"
652 << Indent1 << "{\n"
653 << Indent2 << "std::vector<std::string> vec;\n";
654
655 // Parse CmdLine tool property
Mikhail Glushenkov2cfd2232008-05-06 16:35:25 +0000656 if(P.CmdLine.empty())
657 throw "Tool " + P.Name + " has empty command line!";
658
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000659 StrVector::const_iterator I = P.CmdLine.begin();
660 ++I;
661 for (StrVector::const_iterator E = P.CmdLine.end(); I != E; ++I) {
662 const std::string& cmd = *I;
663 O << Indent2;
664 if (cmd == "$INFILE") {
665 if (V==1)
666 O << "for (PathVector::const_iterator B = inFiles.begin()"
667 << ", E = inFiles.end();\n"
668 << Indent2 << "B != E; ++B)\n"
669 << Indent3 << "vec.push_back(B->toString());\n";
670 else
671 O << "vec.push_back(inFile.toString());\n";
672 }
673 else if (cmd == "$OUTFILE") {
674 O << "vec.push_back(outFile.toString());\n";
675 }
676 else {
677 O << "vec.push_back(\"" << cmd << "\");\n";
678 }
679 }
680
681 // For every understood option, emit handling code
682 for (ToolOptionDescriptions::const_iterator B = P.OptDescs.begin(),
683 E = P.OptDescs.end(); B != E; ++B) {
684 const ToolOptionDescription& val = B->second;
685 EmitOptionPropertyHandlingCode(P, val, O);
686 }
687
688 // Handle Sink property
689 if (P.isSink()) {
690 O << Indent2 << "if (!" << SinkOptionName << ".empty()) {\n"
691 << Indent3 << "vec.insert(vec.end(), "
692 << SinkOptionName << ".begin(), " << SinkOptionName << ".end());\n"
693 << Indent2 << "}\n";
694 }
695
696 O << Indent2 << "return Action(\"" << P.CmdLine.at(0) << "\", vec);\n"
697 << Indent1 << "}\n\n";
698}
699
700// Emit GenerateAction methods for Tool classes
701void EmitGenerateActionMethods (const ToolProperties& P, std::ostream& O) {
702
703 if (!P.isJoin())
704 O << Indent1 << "Action GenerateAction(const PathVector& inFiles,\n"
705 << Indent2 << "const llvm::sys::Path& outFile) const\n"
706 << Indent1 << "{\n"
707 << Indent2 << "throw std::runtime_error(\"" << P.Name
708 << " is not a Join tool!\");\n"
709 << Indent1 << "}\n\n";
710 else
711 EmitGenerateActionMethod(P, 1, O);
712
713 EmitGenerateActionMethod(P, 2, O);
714}
715
716// Emit IsLast() method for Tool classes
717void EmitIsLastMethod (const ToolProperties& P, std::ostream& O) {
718 O << Indent1 << "bool IsLast() const {\n"
719 << Indent2 << "bool last = false;\n";
720
721 for (ToolOptionDescriptions::const_iterator B = P.OptDescs.begin(),
722 E = P.OptDescs.end(); B != E; ++B) {
723 const ToolOptionDescription& val = B->second;
724
725 if (val.isStopCompilation())
726 O << Indent2
727 << "if (" << val.GenVariableName()
728 << ")\n" << Indent3 << "last = true;\n";
729 }
730
731 O << Indent2 << "return last;\n"
732 << Indent1 << "}\n\n";
733}
734
735// Emit static [Input,Output]Language() methods for Tool classes
736void EmitInOutLanguageMethods (const ToolProperties& P, std::ostream& O) {
737 O << Indent1 << "std::string InputLanguage() const {\n"
738 << Indent2 << "return \"" << P.InLanguage << "\";\n"
739 << Indent1 << "}\n\n";
740
741 O << Indent1 << "std::string OutputLanguage() const {\n"
742 << Indent2 << "return \"" << P.OutLanguage << "\";\n"
743 << Indent1 << "}\n\n";
744}
745
746// Emit static [Input,Output]Language() methods for Tool classes
747void EmitOutputSuffixMethod (const ToolProperties& P, std::ostream& O) {
748 O << Indent1 << "std::string OutputSuffix() const {\n"
749 << Indent2 << "return \"" << P.OutputSuffix << "\";\n"
750 << Indent1 << "}\n\n";
751}
752
753// Emit static Name() method for Tool classes
754void EmitNameMethod (const ToolProperties& P, std::ostream& O) {
755 O << Indent1 << "std::string Name() const {\n"
756 << Indent2 << "return \"" << P.Name << "\";\n"
757 << Indent1 << "}\n\n";
758}
759
760// Emit static Name() method for Tool classes
761void EmitIsJoinMethod (const ToolProperties& P, std::ostream& O) {
762 O << Indent1 << "bool IsJoin() const {\n";
763 if (P.isJoin())
764 O << Indent2 << "return true;\n";
765 else
766 O << Indent2 << "return false;\n";
767 O << Indent1 << "}\n\n";
768}
769
770// Emit a Tool class definition
771void EmitToolClassDefinition (const ToolProperties& P, std::ostream& O) {
Mikhail Glushenkov2cfd2232008-05-06 16:35:25 +0000772
773 if(P.Name == "root")
774 return;
775
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000776 // Header
777 O << "class " << P.Name << " : public Tool {\n"
778 << "public:\n";
779
780 EmitNameMethod(P, O);
781 EmitInOutLanguageMethods(P, O);
782 EmitOutputSuffixMethod(P, O);
783 EmitIsJoinMethod(P, O);
784 EmitGenerateActionMethods(P, O);
785 EmitIsLastMethod(P, O);
786
787 // Close class definition
788 O << "};\n\n";
789}
790
791// Iterate over a list of option descriptions and emit registration code
792void EmitOptionDescriptions (const GlobalOptionDescriptions& descs,
793 std::ostream& O)
794{
795 // Emit static cl::Option variables
796 for (GlobalOptionDescriptions::const_iterator B = descs.begin(),
797 E = descs.end(); B!=E; ++B) {
798 const GlobalOptionDescription& val = B->second;
799
800 O << val.GenTypeDeclaration() << ' '
801 << val.GenVariableName()
802 << "(\"" << val.Name << '\"';
803
804 if (val.Type == OptionType::Prefix || val.Type == OptionType::PrefixList)
805 O << ", cl::Prefix";
806
807 if (val.isRequired()) {
808 switch (val.Type) {
809 case OptionType::PrefixList:
810 case OptionType::ParameterList:
811 O << ", cl::OneOrMore";
812 break;
813 default:
814 O << ", cl::Required";
815 }
816 }
817
818 O << ", cl::desc(\"" << val.Help << "\"));\n";
819 }
820
821 if (descs.HasSink)
822 O << "cl::list<std::string> " << SinkOptionName << "(cl::Sink);\n";
823
824 O << '\n';
825}
826
827void EmitPopulateLanguageMap (const RecordKeeper& Records, std::ostream& O)
828{
829 // Get the relevant field out of RecordKeeper
830 Record* LangMapRecord = Records.getDef("LanguageMap");
831 if (!LangMapRecord)
832 throw std::string("Language map definition not found!");
833
834 ListInit* LangsToSuffixesList = LangMapRecord->getValueAsListInit("map");
835 if (!LangsToSuffixesList)
836 throw std::string("Error in the language map definition!");
837
838 // Generate code
839 O << "void llvmcc::PopulateLanguageMap(LanguageMap& language_map) {\n";
840
841 for (unsigned i = 0; i < LangsToSuffixesList->size(); ++i) {
842 Record* LangToSuffixes = LangsToSuffixesList->getElementAsRecord(i);
843
844 const std::string& Lang = LangToSuffixes->getValueAsString("lang");
845 const ListInit* Suffixes = LangToSuffixes->getValueAsListInit("suffixes");
846
847 for (unsigned i = 0; i < Suffixes->size(); ++i)
848 O << Indent1 << "language_map[\""
849 << InitPtrToString(Suffixes->getElement(i))
850 << "\"] = \"" << Lang << "\";\n";
851 }
852
853 O << "}\n\n";
854}
855
856void EmitPopulateCompilationGraph (const RecordKeeper& Records,
857 StringMap<std::string>& ToolToLang,
858 std::ostream& O)
859{
860 // Get the relevant field out of RecordKeeper
Mikhail Glushenkov2cfd2232008-05-06 16:35:25 +0000861 Record* CompilationGraph = Records.getDef("CompilationGraph");
862 if (!CompilationGraph)
863 throw std::string("No CompilationGraph specification found!");
864 ListInit* edges = CompilationGraph->getValueAsListInit("edges");
865 if (!edges)
866 throw std::string("Error in compilation graph definition!");
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000867
868 // Generate code
869 O << "void llvmcc::PopulateCompilationGraph(CompilationGraph& G) {\n"
Mikhail Glushenkov2cfd2232008-05-06 16:35:25 +0000870 << Indent1 << "PopulateLanguageMap(G.ExtsToLangs);\n\n";
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000871
Mikhail Glushenkov2cfd2232008-05-06 16:35:25 +0000872 // Insert vertices
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000873
Mikhail Glushenkov2cfd2232008-05-06 16:35:25 +0000874 RecordVector Tools = Records.getAllDerivedDefinitions("Tool");
875 if (Tools.empty())
876 throw std::string("No tool definitions found!");
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000877
Mikhail Glushenkov2cfd2232008-05-06 16:35:25 +0000878 for (RecordVector::iterator B = Tools.begin(), E = Tools.end(); B != E; ++B) {
879 const std::string& Name = (*B)->getName();
880 if(Name != "root")
881 O << Indent1 << "G.insertVertex(IntrusiveRefCntPtr<Tool>(new "
882 << Name << "()));\n";
883 }
884
885 O << '\n';
886
887 // Insert edges
888
889 for (unsigned i = 0; i < edges->size(); ++i) {
890 Record* Edge = edges->getElementAsRecord(i);
891 Record* A = Edge->getValueAsDef("a");
892 Record* B = Edge->getValueAsDef("b");
893 O << Indent1 << "G.insertEdge(\"" << A->getName() << "\", \""
894 << B->getName() << "\");\n";
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000895 }
896
897 O << "}\n\n";
898}
899
900void FillInToolToLang (const ToolPropertiesList& T,
901 StringMap<std::string>& M) {
902 for (ToolPropertiesList::const_iterator B = T.begin(), E = T.end();
903 B != E; ++B) {
904 const ToolProperties& P = *(*B);
905 M[P.Name] = P.InLanguage;
906 }
907}
908
909// End of anonymous namespace
910}
911
912// Back-end entry point
913void LLVMCCConfigurationEmitter::run (std::ostream &O) {
914 // Emit file header
915 EmitSourceFileHeader("LLVMCC Configuration Library", O);
916
917 // Get a list of all defined Tools
918 RecordVector Tools = Records.getAllDerivedDefinitions("Tool");
919 if (Tools.empty())
920 throw std::string("No tool definitions found!");
921
922 // Gather information from the Tool descriptions
923 ToolPropertiesList tool_props;
924 GlobalOptionDescriptions opt_descs;
925 CollectToolProperties(Tools.begin(), Tools.end(), tool_props, opt_descs);
926
927 // Emit global option registration code
928 EmitOptionDescriptions(opt_descs, O);
929
930 // Emit PopulateLanguageMap function
931 // (a language map maps from file extensions to language names)
932 EmitPopulateLanguageMap(Records, O);
933
934 // Emit Tool classes
935 for (ToolPropertiesList::const_iterator B = tool_props.begin(),
936 E = tool_props.end(); B!=E; ++B)
937 EmitToolClassDefinition(*(*B), O);
938
939 // Fill in table that maps tool names to languages
940 StringMap<std::string> ToolToLang;
941 FillInToolToLang(tool_props, ToolToLang);
942
943 // Emit PopulateCompilationGraph function
944 EmitPopulateCompilationGraph(Records, ToolToLang, O);
945
946 // EOF
947}