blob: ab6f2efc484072e4da5f1d16f397e9d51a3e7259 [file] [log] [blame]
Mikhail Glushenkov34307a92008-05-06 18:08:59 +00001//===- LLVMCConfigurationEmitter.cpp - Generate LLVMC config --------------===//
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00002//
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//
Mikhail Glushenkov34307a92008-05-06 18:08:59 +000010// This tablegen backend is responsible for emitting LLVMC configuration code.
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +000011//
12//===----------------------------------------------------------------------===//
13
Mikhail Glushenkov41405722008-05-06 18:09:29 +000014#include "LLVMCConfigurationEmitter.h"
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +000015#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
Mikhail Glushenkovc1f738d2008-05-06 18:12:03 +000030namespace {
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +000031
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
Mikhail Glushenkova5922cc2008-05-06 17:22:03 +000061// Ensure that the number of args in d is <= min_arguments,
62// throw exception otherwise
63void checkNumberOfArguments (const DagInit* d, unsigned min_arguments) {
64 if (d->getNumArgs() < min_arguments)
65 throw "Property " + d->getOperator()->getAsString()
66 + " has too few arguments!";
67}
68
69
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +000070//===----------------------------------------------------------------------===//
71/// Back-end specific code
72
73// A command-line option can have one of the following types:
74//
75// Switch - a simple switch w/o arguments, e.g. -O2
76//
77// Parameter - an option that takes one(and only one) argument, e.g. -o file,
78// --output=file
79//
80// ParameterList - same as Parameter, but more than one occurence
81// of the option is allowed, e.g. -lm -lpthread
82//
83// Prefix - argument is everything after the prefix,
84// e.g. -Wa,-foo,-bar, -DNAME=VALUE
85//
86// PrefixList - same as Prefix, but more than one option occurence is
87// allowed
88
89namespace OptionType {
90 enum OptionType { Switch, Parameter, ParameterList, Prefix, PrefixList};
91}
92
93bool IsListOptionType (OptionType::OptionType t) {
94 return (t == OptionType::ParameterList || t == OptionType::PrefixList);
95}
96
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.
102
103// Base class for option descriptions
104
105struct OptionDescription {
106 OptionType::OptionType Type;
107 std::string Name;
108
109 OptionDescription(OptionType::OptionType t = OptionType::Switch,
110 const std::string& n = "")
111 : Type(t), Name(n)
112 {}
113
114 const char* GenTypeDeclaration() const {
115 switch (Type) {
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:
123 default:
124 return "cl::opt<std::string>";
125 }
126 }
127
128 std::string GenVariableName() const {
129 switch (Type) {
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:
139 default:
140 return "AutoGeneratedParameterList" + Name;
141 }
142 }
143
144};
145
146// Global option description
147
148namespace GlobalOptionDescriptionFlags {
149 enum GlobalOptionDescriptionFlags { Required = 0x1 };
150}
151
152struct GlobalOptionDescription : public OptionDescription {
153 std::string Help;
154 unsigned Flags;
155
Mikhail Glushenkov46d4e972008-05-06 16:36:06 +0000156 // We need t provide a default constructor since
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000157 // StringMap can only store DefaultConstructible objects
158 GlobalOptionDescription() : OptionDescription(), Flags(0)
159 {}
160
161 GlobalOptionDescription (OptionType::OptionType t, const std::string& n)
162 : OptionDescription(t, n), Help(DefaultHelpString), Flags(0)
163 {}
164
165 bool isRequired() const {
166 return Flags & GlobalOptionDescriptionFlags::Required;
167 }
168 void setRequired() {
169 Flags |= GlobalOptionDescriptionFlags::Required;
170 }
171
172 // Merge two option descriptions
173 void Merge (const GlobalOptionDescription& other)
174 {
175 if (other.Type != Type)
176 throw "Conflicting definitions for the option " + Name + "!";
177
Mikhail Glushenkov434816d2008-05-06 18:13:00 +0000178 if (Help == DefaultHelpString)
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000179 Help = other.Help;
Mikhail Glushenkov434816d2008-05-06 18:13:00 +0000180 else if (other.Help != DefaultHelpString) {
181 llvm::cerr << "Warning: more than one help string defined for option "
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000182 + Name + "\n";
Mikhail Glushenkov434816d2008-05-06 18:13:00 +0000183 }
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000184
185 Flags |= other.Flags;
186 }
187};
188
189// A GlobalOptionDescription array
190// + some flags affecting generation of option declarations
191struct GlobalOptionDescriptions {
192 typedef StringMap<GlobalOptionDescription> container_type;
193 typedef container_type::const_iterator const_iterator;
194
195 // A list of GlobalOptionDescriptions
196 container_type Descriptions;
197 // Should the emitter generate a "cl::sink" option?
198 bool HasSink;
199
Mikhail Glushenkova5922cc2008-05-06 17:22:03 +0000200 const GlobalOptionDescription& FindOption(const std::string& OptName) const {
201 const_iterator I = Descriptions.find(OptName);
202 if (I != Descriptions.end())
203 return I->second;
204 else
205 throw OptName + ": no such option!";
206 }
207
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000208 // Support for STL-style iteration
209 const_iterator begin() const { return Descriptions.begin(); }
210 const_iterator end() const { return Descriptions.end(); }
211};
212
213
214// Tool-local option description
215
216// Properties without arguments are implemented as flags
217namespace ToolOptionDescriptionFlags {
218 enum ToolOptionDescriptionFlags { StopCompilation = 0x1,
219 Forward = 0x2, UnpackValues = 0x4};
220}
221namespace OptionPropertyType {
222 enum OptionPropertyType { AppendCmd };
223}
224
225typedef std::pair<OptionPropertyType::OptionPropertyType, std::string>
226OptionProperty;
227typedef SmallVector<OptionProperty, 4> OptionPropertyList;
228
229struct ToolOptionDescription : public OptionDescription {
230 unsigned Flags;
231 OptionPropertyList Props;
232
233 // StringMap can only store DefaultConstructible objects
Mikhail Glushenkov18cbe892008-03-27 09:53:47 +0000234 ToolOptionDescription() : OptionDescription(), Flags(0) {}
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000235
236 ToolOptionDescription (OptionType::OptionType t, const std::string& n)
237 : OptionDescription(t, n)
238 {}
239
240 // Various boolean properties
241 bool isStopCompilation() const {
242 return Flags & ToolOptionDescriptionFlags::StopCompilation;
243 }
244 void setStopCompilation() {
245 Flags |= ToolOptionDescriptionFlags::StopCompilation;
246 }
247
248 bool isForward() const {
249 return Flags & ToolOptionDescriptionFlags::Forward;
250 }
251 void setForward() {
252 Flags |= ToolOptionDescriptionFlags::Forward;
253 }
254
255 bool isUnpackValues() const {
256 return Flags & ToolOptionDescriptionFlags::UnpackValues;
257 }
258 void setUnpackValues() {
259 Flags |= ToolOptionDescriptionFlags::UnpackValues;
260 }
261
262 void AddProperty (OptionPropertyType::OptionPropertyType t,
263 const std::string& val)
264 {
265 Props.push_back(std::make_pair(t, val));
266 }
267};
268
269typedef StringMap<ToolOptionDescription> ToolOptionDescriptions;
270
271// Tool information record
272
273namespace ToolFlags {
274 enum ToolFlags { Join = 0x1, Sink = 0x2 };
275}
276
277struct ToolProperties : public RefCountedBase<ToolProperties> {
278 std::string Name;
279 StrVector CmdLine;
280 std::string InLanguage;
281 std::string OutLanguage;
282 std::string OutputSuffix;
283 unsigned Flags;
284 ToolOptionDescriptions OptDescs;
285
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; }
291
292 // Default ctor here is needed because StringMap can only store
293 // DefaultConstructible objects
Mikhail Glushenkov434816d2008-05-06 18:13:00 +0000294 ToolProperties() : Flags(0) {}
295 ToolProperties (const std::string& n) : Name(n), Flags(0) {}
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000296};
297
298
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)
302typedef std::vector<IntrusiveRefCntPtr<ToolProperties> > ToolPropertiesList;
303
304
305// Function object for iterating over a list of tool property records
306class CollectProperties {
307private:
308
309 /// Implementation details
310
311 // "Property handler" - a function that extracts information
312 // about a given tool property from its DAG representation
313 typedef void (CollectProperties::*PropertyHandler)(DagInit*);
314
315 // Map from property names -> property handlers
316 typedef StringMap<PropertyHandler> PropertyHandlerMap;
317
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 &);
322
323 // Map from option property names -> option property handlers
324 typedef StringMap<OptionPropertyHandler> OptionPropertyHandlerMap;
325
326 // Static maps from strings to CollectProperties methods("handlers")
327 static PropertyHandlerMap propertyHandlers_;
328 static OptionPropertyHandlerMap optionPropertyHandlers_;
329 static bool staticMembersInitialized_;
330
331
332 /// This is where the information is stored
333
334 // Current Tool properties
335 ToolProperties& toolProps_;
336 // OptionDescriptions table(used to register options globally)
337 GlobalOptionDescriptions& optDescs_;
338
339public:
340
341 explicit CollectProperties (ToolProperties& p, GlobalOptionDescriptions& d)
342 : toolProps_(p), optDescs_(d)
343 {
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;
360
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;
370
371 staticMembersInitialized_ = true;
372 }
373 }
374
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);
Mikhail Glushenkova5922cc2008-05-06 17:22:03 +0000379 const std::string& property_name = d.getOperator()->getAsString();
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000380 PropertyHandlerMap::iterator method
381 = propertyHandlers_.find(property_name);
382
383 if (method != propertyHandlers_.end()) {
384 PropertyHandler h = method->second;
385 (this->*h)(&d);
386 }
387 else {
388 throw "Unknown tool property: " + property_name + "!";
389 }
390 }
391
392private:
393
394 /// Property handlers --
395 /// Functions that extract information about tool properties from
396 /// DAG representation.
397
398 void onCmdLine (DagInit* d) {
399 checkNumberOfArguments(d, 1);
400 SplitString(InitPtrToString(d->getArg(0)), toolProps_.CmdLine);
401 if (toolProps_.CmdLine.empty())
Mikhail Glushenkov2cfd2232008-05-06 16:35:25 +0000402 throw "Tool " + toolProps_.Name + " has empty command line!";
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000403 }
404
405 void onInLanguage (DagInit* d) {
406 checkNumberOfArguments(d, 1);
407 toolProps_.InLanguage = InitPtrToString(d->getArg(0));
408 }
409
410 void onJoin (DagInit* d) {
411 checkNumberOfArguments(d, 0);
412 toolProps_.setJoin();
413 }
414
415 void onOutLanguage (DagInit* d) {
416 checkNumberOfArguments(d, 1);
417 toolProps_.OutLanguage = InitPtrToString(d->getArg(0));
418 }
419
420 void onOutputSuffix (DagInit* d) {
421 checkNumberOfArguments(d, 1);
422 toolProps_.OutputSuffix = InitPtrToString(d->getArg(0));
423 }
424
425 void onSink (DagInit* d) {
426 checkNumberOfArguments(d, 0);
427 optDescs_.HasSink = true;
428 toolProps_.setSink();
429 }
430
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); }
436
437 /// Option property handlers --
438 /// Methods that handle properties that are common for all types of
439 /// options (like append_cmd, stop_compilation)
440
441 void onAppendCmd (DagInit* d, GlobalOptionDescription& o) {
442 checkNumberOfArguments(d, 1);
443 std::string const& cmd = InitPtrToString(d->getArg(0));
444
445 toolProps_.OptDescs[o.Name].AddProperty(OptionPropertyType::AppendCmd, cmd);
446 }
447
448 void onForward (DagInit* d, GlobalOptionDescription& o) {
449 checkNumberOfArguments(d, 0);
450 toolProps_.OptDescs[o.Name].setForward();
451 }
452
453 void onHelp (DagInit* d, GlobalOptionDescription& o) {
454 checkNumberOfArguments(d, 1);
455 const std::string& help_message = InitPtrToString(d->getArg(0));
456
457 o.Help = help_message;
458 }
459
460 void onRequired (DagInit* d, GlobalOptionDescription& o) {
461 checkNumberOfArguments(d, 0);
462 o.setRequired();
463 }
464
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();
470 }
471
472 void onUnpackValues (DagInit* d, GlobalOptionDescription& o) {
473 checkNumberOfArguments(d, 0);
474 toolProps_.OptDescs[o.Name].setUnpackValues();
475 }
476
477 /// Helper functions
478
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));
483
484 GlobalOptionDescription o(t, name);
485 toolProps_.OptDescs[name].Type = t;
486 toolProps_.OptDescs[name].Name = name;
487 processOptionProperties(d, o);
488 insertDescription(o);
489 }
490
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000491 // Insert new GlobalOptionDescription into GlobalOptionDescriptions list
492 void insertDescription (const GlobalOptionDescription& o)
493 {
494 if (optDescs_.Descriptions.count(o.Name)) {
495 GlobalOptionDescription& D = optDescs_.Descriptions[o.Name];
496 D.Merge(o);
497 }
498 else {
499 optDescs_.Descriptions[o.Name] = o;
500 }
501 }
502
503 // Go through the list of option properties and call a corresponding
504 // handler for each.
505 //
506 // Parameters:
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);
512
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);
520
521 if (method != optionPropertyHandlers_.end()) {
522 OptionPropertyHandler h = method->second;
523 (this->*h)(&option_property, o);
524 }
525 else {
526 throw "Unknown option property: " + option_property_name + "!";
527 }
528 }
529 }
530};
531
532// Static members of CollectProperties
533CollectProperties::PropertyHandlerMap
534CollectProperties::propertyHandlers_;
535
536CollectProperties::OptionPropertyHandlerMap
537CollectProperties::optionPropertyHandlers_;
538
539bool CollectProperties::staticMembersInitialized_ = false;
540
541
542// Gather information from the parsed TableGen data
543// (Basically a wrapper for CollectProperties)
544void CollectToolProperties (RecordVector::const_iterator B,
545 RecordVector::const_iterator E,
546 ToolPropertiesList& TPList,
547 GlobalOptionDescriptions& OptDescs)
548{
549 // Iterate over a properties list of every Tool definition
550 for (;B!=E;++B) {
551 RecordVector::value_type T = *B;
552 ListInit* PropList = T->getValueAsListInit("properties");
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000553
554 IntrusiveRefCntPtr<ToolProperties>
555 ToolProps(new ToolProperties(T->getName()));
556
557 std::for_each(PropList->begin(), PropList->end(),
558 CollectProperties(*ToolProps, OptDescs));
559 TPList.push_back(ToolProps);
560 }
561}
562
563// Used by EmitGenerateActionMethod
564void EmitOptionPropertyHandlingCode (const ToolProperties& P,
565 const ToolOptionDescription& D,
566 std::ostream& O)
567{
568 // if clause
569 O << Indent2 << "if (";
570 if (D.Type == OptionType::Switch)
571 O << D.GenVariableName();
572 else
573 O << '!' << D.GenVariableName() << ".empty()";
574
575 O <<") {\n";
576
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;
581
582 switch (val.first) {
583 // (append_cmd cmd) property
584 case OptionPropertyType::AppendCmd:
585 O << Indent3 << "vec.push_back(\"" << val.second << "\");\n";
586 break;
587 // Other properties with argument
588 default:
589 break;
590 }
591 }
592
593 // Handle flags
594
595 // (forward) property
596 if (D.isForward()) {
597 switch (D.Type) {
598 case OptionType::Switch:
599 O << Indent3 << "vec.push_back(\"-" << D.Name << "\");\n";
600 break;
601 case OptionType::Parameter:
602 O << Indent3 << "vec.push_back(\"-" << D.Name << "\");\n";
603 O << Indent3 << "vec.push_back(" << D.GenVariableName() << ");\n";
604 break;
605 case OptionType::Prefix:
606 O << Indent3 << "vec.push_back(\"-" << D.Name << "\" + "
607 << D.GenVariableName() << ");\n";
608 break;
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 << "\" + "
614 << "*B);\n";
615 break;
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"
623 << Indent3 << "}\n";
624 break;
625 }
626 }
627
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"
Mikhail Glushenkov028f18e2008-05-06 18:13:45 +0000635 << Indent4 << "llvm::SplitString(*B, vec, \",\");\n";
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000636 }
637 else if (D.Type == OptionType::Prefix || D.Type == OptionType::Parameter){
Mikhail Glushenkov028f18e2008-05-06 18:13:45 +0000638 O << Indent3 << "llvm::SplitString("
639 << D.GenVariableName() << ", vec, \",\");\n";
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000640 }
641 else {
642 // TOFIX: move this to the type-checking phase
643 throw std::string("Switches can't have unpack_values property!");
644 }
645 }
646
647 // close if clause
648 O << Indent2 << "}\n";
649}
650
651// Emite one of two versions of GenerateAction method
652void EmitGenerateActionMethod (const ToolProperties& P, int V, std::ostream& O)
653{
654 assert(V==1 || V==2);
655 if (V==1)
656 O << Indent1 << "Action GenerateAction(const PathVector& inFiles,\n";
657 else
658 O << Indent1 << "Action GenerateAction(const sys::Path& inFile,\n";
659
660 O << Indent2 << "const sys::Path& outFile) const\n"
661 << Indent1 << "{\n"
662 << Indent2 << "std::vector<std::string> vec;\n";
663
664 // Parse CmdLine tool property
Mikhail Glushenkov2cfd2232008-05-06 16:35:25 +0000665 if(P.CmdLine.empty())
666 throw "Tool " + P.Name + " has empty command line!";
667
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000668 StrVector::const_iterator I = P.CmdLine.begin();
669 ++I;
670 for (StrVector::const_iterator E = P.CmdLine.end(); I != E; ++I) {
671 const std::string& cmd = *I;
672 O << Indent2;
673 if (cmd == "$INFILE") {
674 if (V==1)
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";
679 else
680 O << "vec.push_back(inFile.toString());\n";
681 }
682 else if (cmd == "$OUTFILE") {
683 O << "vec.push_back(outFile.toString());\n";
684 }
685 else {
686 O << "vec.push_back(\"" << cmd << "\");\n";
687 }
688 }
689
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);
695 }
696
697 // Handle Sink property
698 if (P.isSink()) {
699 O << Indent2 << "if (!" << SinkOptionName << ".empty()) {\n"
700 << Indent3 << "vec.insert(vec.end(), "
701 << SinkOptionName << ".begin(), " << SinkOptionName << ".end());\n"
702 << Indent2 << "}\n";
703 }
704
705 O << Indent2 << "return Action(\"" << P.CmdLine.at(0) << "\", vec);\n"
706 << Indent1 << "}\n\n";
707}
708
709// Emit GenerateAction methods for Tool classes
710void EmitGenerateActionMethods (const ToolProperties& P, std::ostream& O) {
711
712 if (!P.isJoin())
713 O << Indent1 << "Action GenerateAction(const PathVector& inFiles,\n"
714 << Indent2 << "const llvm::sys::Path& outFile) const\n"
715 << Indent1 << "{\n"
716 << Indent2 << "throw std::runtime_error(\"" << P.Name
717 << " is not a Join tool!\");\n"
718 << Indent1 << "}\n\n";
719 else
720 EmitGenerateActionMethod(P, 1, O);
721
722 EmitGenerateActionMethod(P, 2, O);
723}
724
725// Emit IsLast() method for Tool classes
726void EmitIsLastMethod (const ToolProperties& P, std::ostream& O) {
727 O << Indent1 << "bool IsLast() const {\n"
728 << Indent2 << "bool last = false;\n";
729
730 for (ToolOptionDescriptions::const_iterator B = P.OptDescs.begin(),
731 E = P.OptDescs.end(); B != E; ++B) {
732 const ToolOptionDescription& val = B->second;
733
734 if (val.isStopCompilation())
735 O << Indent2
736 << "if (" << val.GenVariableName()
737 << ")\n" << Indent3 << "last = true;\n";
738 }
739
740 O << Indent2 << "return last;\n"
741 << Indent1 << "}\n\n";
742}
743
744// Emit static [Input,Output]Language() methods for Tool classes
745void EmitInOutLanguageMethods (const ToolProperties& P, std::ostream& O) {
Mikhail Glushenkovd379d162008-05-06 17:24:26 +0000746 O << Indent1 << "const char* InputLanguage() const {\n"
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000747 << Indent2 << "return \"" << P.InLanguage << "\";\n"
748 << Indent1 << "}\n\n";
749
Mikhail Glushenkovd379d162008-05-06 17:24:26 +0000750 O << Indent1 << "const char* OutputLanguage() const {\n"
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000751 << Indent2 << "return \"" << P.OutLanguage << "\";\n"
752 << Indent1 << "}\n\n";
753}
754
755// Emit static [Input,Output]Language() methods for Tool classes
756void EmitOutputSuffixMethod (const ToolProperties& P, std::ostream& O) {
Mikhail Glushenkovd379d162008-05-06 17:24:26 +0000757 O << Indent1 << "const char* OutputSuffix() const {\n"
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000758 << Indent2 << "return \"" << P.OutputSuffix << "\";\n"
759 << Indent1 << "}\n\n";
760}
761
762// Emit static Name() method for Tool classes
763void EmitNameMethod (const ToolProperties& P, std::ostream& O) {
Mikhail Glushenkovd379d162008-05-06 17:24:26 +0000764 O << Indent1 << "const char* Name() const {\n"
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000765 << Indent2 << "return \"" << P.Name << "\";\n"
766 << Indent1 << "}\n\n";
767}
768
769// Emit static Name() method for Tool classes
770void EmitIsJoinMethod (const ToolProperties& P, std::ostream& O) {
771 O << Indent1 << "bool IsJoin() const {\n";
772 if (P.isJoin())
773 O << Indent2 << "return true;\n";
774 else
775 O << Indent2 << "return false;\n";
776 O << Indent1 << "}\n\n";
777}
778
779// Emit a Tool class definition
780void EmitToolClassDefinition (const ToolProperties& P, std::ostream& O) {
Mikhail Glushenkov2cfd2232008-05-06 16:35:25 +0000781
782 if(P.Name == "root")
783 return;
784
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000785 // Header
Mikhail Glushenkov121889c2008-05-06 17:26:53 +0000786 O << "class " << P.Name << " : public ";
787 if (P.isJoin())
788 O << "JoinTool";
789 else
790 O << "Tool";
Mikhail Glushenkovd14857f2008-05-06 17:27:15 +0000791 O << " {\npublic:\n";
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000792
793 EmitNameMethod(P, O);
794 EmitInOutLanguageMethods(P, O);
795 EmitOutputSuffixMethod(P, O);
796 EmitIsJoinMethod(P, O);
797 EmitGenerateActionMethods(P, O);
798 EmitIsLastMethod(P, O);
799
800 // Close class definition
801 O << "};\n\n";
802}
803
804// Iterate over a list of option descriptions and emit registration code
805void EmitOptionDescriptions (const GlobalOptionDescriptions& descs,
806 std::ostream& O)
807{
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;
812
813 O << val.GenTypeDeclaration() << ' '
814 << val.GenVariableName()
815 << "(\"" << val.Name << '\"';
816
817 if (val.Type == OptionType::Prefix || val.Type == OptionType::PrefixList)
818 O << ", cl::Prefix";
819
820 if (val.isRequired()) {
821 switch (val.Type) {
822 case OptionType::PrefixList:
823 case OptionType::ParameterList:
824 O << ", cl::OneOrMore";
825 break;
826 default:
827 O << ", cl::Required";
828 }
829 }
830
831 O << ", cl::desc(\"" << val.Help << "\"));\n";
832 }
833
834 if (descs.HasSink)
835 O << "cl::list<std::string> " << SinkOptionName << "(cl::Sink);\n";
836
837 O << '\n';
838}
839
840void EmitPopulateLanguageMap (const RecordKeeper& Records, std::ostream& O)
841{
842 // Get the relevant field out of RecordKeeper
843 Record* LangMapRecord = Records.getDef("LanguageMap");
844 if (!LangMapRecord)
845 throw std::string("Language map definition not found!");
846
847 ListInit* LangsToSuffixesList = LangMapRecord->getValueAsListInit("map");
848 if (!LangsToSuffixesList)
849 throw std::string("Error in the language map definition!");
850
851 // Generate code
Mikhail Glushenkov34307a92008-05-06 18:08:59 +0000852 O << "void llvmc::PopulateLanguageMap(LanguageMap& language_map) {\n";
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000853
854 for (unsigned i = 0; i < LangsToSuffixesList->size(); ++i) {
855 Record* LangToSuffixes = LangsToSuffixesList->getElementAsRecord(i);
856
857 const std::string& Lang = LangToSuffixes->getValueAsString("lang");
858 const ListInit* Suffixes = LangToSuffixes->getValueAsListInit("suffixes");
859
860 for (unsigned i = 0; i < Suffixes->size(); ++i)
861 O << Indent1 << "language_map[\""
862 << InitPtrToString(Suffixes->getElement(i))
863 << "\"] = \"" << Lang << "\";\n";
864 }
865
866 O << "}\n\n";
867}
868
Mikhail Glushenkov46d4e972008-05-06 16:36:06 +0000869// Fills in two tables that map tool names to (input, output) languages.
870// Used by the typechecker.
871void 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();
875 B != E; ++B) {
876 const ToolProperties& P = *(*B);
877 ToolToInLang[P.Name] = P.InLanguage;
878 ToolToOutLang[P.Name] = P.OutLanguage;
879 }
880}
881
882// Check that all output and input language names match.
Mikhail Glushenkov761958d2008-05-06 16:36:50 +0000883// TOFIX: check for cycles.
884// TOFIX: check for multiple default edges.
Mikhail Glushenkov46d4e972008-05-06 16:36:06 +0000885void TypecheckGraph (Record* CompilationGraph,
886 const ToolPropertiesList& TPList) {
887 StringMap<std::string> ToolToInLang;
888 StringMap<std::string> ToolToOutLang;
889
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();
894
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());
901 if(IA == IAE)
902 throw A->getName() + ": no such tool!";
903 if(IB == IBE)
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";
Mikhail Glushenkov761958d2008-05-06 16:36:50 +0000908 if(B->getName() == "root")
909 throw std::string("Edges back to the root are not allowed!");
Mikhail Glushenkov46d4e972008-05-06 16:36:06 +0000910 }
911}
912
Mikhail Glushenkov3f6743e2008-05-06 17:22:47 +0000913// Helper function used by EmitEdgePropertyTest.
914void EmitEdgePropertyTest1Arg(const DagInit& Prop,
915 const GlobalOptionDescriptions& OptDescs,
916 std::ostream& O) {
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();
923}
924
925// Helper function used by EmitEdgePropertyTest.
926void EmitEdgePropertyTest2Args(const std::string& PropName,
927 const DagInit& Prop,
928 const GlobalOptionDescriptions& OptDescs,
929 std::ostream& O) {
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);
934
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 << "\"";
940 }
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()";
949 }
950 else
951 throw PropName + ": unknown edge property!";
952}
953
Mikhail Glushenkov8d0d5d22008-05-06 17:23:14 +0000954// Helper function used by EmitEdgeClass.
Mikhail Glushenkov3f6743e2008-05-06 17:22:47 +0000955void EmitEdgePropertyTest(const std::string& PropName,
956 const DagInit& Prop,
957 const GlobalOptionDescriptions& OptDescs,
958 std::ostream& O) {
959 if (PropName == "switch_on")
960 EmitEdgePropertyTest1Arg(Prop, OptDescs, O);
961 else
962 EmitEdgePropertyTest2Args(PropName, Prop, OptDescs, O);
963}
964
Mikhail Glushenkov8d0d5d22008-05-06 17:23:14 +0000965// Emit a single Edge* class.
966void EmitEdgeClass(unsigned N, const std::string& Target,
967 ListInit* Props, const GlobalOptionDescriptions& OptDescs,
968 std::ostream& O) {
969 bool IsDefault = false;
970
971 // Class constructor.
972 O << "class Edge" << N << ": public Edge {\n"
973 << "public:\n"
974 << Indent1 << "Edge" << N << "() : Edge(\"" << Target
975 << "\") {}\n\n"
976
977 // Function isEnabled().
978 << Indent1 << "bool isEnabled() const {\n"
979 << Indent2 << "bool ret = false;\n";
980
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();
984
985 if (PropName == "default")
986 IsDefault = true;
987
988 O << Indent2 << "if (ret || (";
989 if (PropName == "and") {
990 O << '(';
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 << " && (";
998 else
999 O << ')';
1000 }
1001 }
1002 else {
1003 EmitEdgePropertyTest(PropName, Prop, OptDescs, O);
1004 }
1005 O << "))\n" << Indent3 << "ret = true;\n";
1006 }
1007
1008 O << Indent2 << "return ret;\n"
1009 << Indent1 << "};\n\n"
1010
1011 // Function isDefault().
1012 << Indent1 << "bool isDefault() const { return ";
1013 if (IsDefault)
1014 O << "true";
1015 else
1016 O << "false";
1017 O <<"; }\n};\n\n";
1018}
1019
1020// Emit Edge* classes that represent graph edges.
Mikhail Glushenkov46d4e972008-05-06 16:36:06 +00001021void EmitEdgeClasses (Record* CompilationGraph,
1022 const GlobalOptionDescriptions& OptDescs,
1023 std::ostream& O) {
1024 ListInit* edges = CompilationGraph->getValueAsListInit("edges");
1025
1026 for (unsigned i = 0; i < edges->size(); ++i) {
Mikhail Glushenkov761958d2008-05-06 16:36:50 +00001027 Record* Edge = edges->getElementAsRecord(i);
1028 Record* B = Edge->getValueAsDef("b");
1029 ListInit* Props = Edge->getValueAsListInit("props");
Mikhail Glushenkov46d4e972008-05-06 16:36:06 +00001030
Mikhail Glushenkov761958d2008-05-06 16:36:50 +00001031 if (Props->empty())
1032 continue;
1033
Mikhail Glushenkov8d0d5d22008-05-06 17:23:14 +00001034 EmitEdgeClass(i, B->getName(), Props, OptDescs, O);
Mikhail Glushenkov46d4e972008-05-06 16:36:06 +00001035 }
1036}
1037
1038void EmitPopulateCompilationGraph (Record* CompilationGraph,
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001039 std::ostream& O)
1040{
Mikhail Glushenkov2cfd2232008-05-06 16:35:25 +00001041 ListInit* edges = CompilationGraph->getValueAsListInit("edges");
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001042
1043 // Generate code
Mikhail Glushenkov34307a92008-05-06 18:08:59 +00001044 O << "void llvmc::PopulateCompilationGraph(CompilationGraph& G) {\n"
Mikhail Glushenkov2cfd2232008-05-06 16:35:25 +00001045 << Indent1 << "PopulateLanguageMap(G.ExtsToLangs);\n\n";
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001046
Mikhail Glushenkov2cfd2232008-05-06 16:35:25 +00001047 // Insert vertices
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001048
Mikhail Glushenkov2cfd2232008-05-06 16:35:25 +00001049 RecordVector Tools = Records.getAllDerivedDefinitions("Tool");
1050 if (Tools.empty())
1051 throw std::string("No tool definitions found!");
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001052
Mikhail Glushenkov2cfd2232008-05-06 16:35:25 +00001053 for (RecordVector::iterator B = Tools.begin(), E = Tools.end(); B != E; ++B) {
1054 const std::string& Name = (*B)->getName();
1055 if(Name != "root")
Mikhail Glushenkov46d4e972008-05-06 16:36:06 +00001056 O << Indent1 << "G.insertNode(new "
1057 << Name << "());\n";
Mikhail Glushenkov2cfd2232008-05-06 16:35:25 +00001058 }
1059
1060 O << '\n';
1061
1062 // Insert edges
Mikhail Glushenkov2cfd2232008-05-06 16:35:25 +00001063 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");
Mikhail Glushenkov761958d2008-05-06 16:36:50 +00001067 ListInit* Props = Edge->getValueAsListInit("props");
1068
1069 O << Indent1 << "G.insertEdge(\"" << A->getName() << "\", ";
1070
1071 if (Props->empty())
1072 O << "new SimpleEdge(\"" << B->getName() << "\")";
1073 else
1074 O << "new Edge" << i << "()";
1075
1076 O << ");\n";
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001077 }
1078
1079 O << "}\n\n";
1080}
1081
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001082
1083// End of anonymous namespace
Mikhail Glushenkovc1f738d2008-05-06 18:12:03 +00001084}
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001085
1086// Back-end entry point
Mikhail Glushenkovc1f738d2008-05-06 18:12:03 +00001087void LLVMCConfigurationEmitter::run (std::ostream &O) {
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001088 // Emit file header
Mikhail Glushenkov34307a92008-05-06 18:08:59 +00001089 EmitSourceFileHeader("LLVMC Configuration Library", O);
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001090
1091 // Get a list of all defined Tools
1092 RecordVector Tools = Records.getAllDerivedDefinitions("Tool");
1093 if (Tools.empty())
1094 throw std::string("No tool definitions found!");
1095
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);
1100
1101 // Emit global option registration code
1102 EmitOptionDescriptions(opt_descs, O);
1103
1104 // Emit PopulateLanguageMap function
1105 // (a language map maps from file extensions to language names)
1106 EmitPopulateLanguageMap(Records, O);
1107
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);
1112
Mikhail Glushenkov46d4e972008-05-06 16:36:06 +00001113 Record* CompilationGraphRecord = Records.getDef("CompilationGraph");
1114 if (!CompilationGraphRecord)
1115 throw std::string("Compilation graph description not found!");
1116
1117 // Typecheck the compilation graph.
1118 TypecheckGraph(CompilationGraphRecord, tool_props);
1119
1120 // Emit Edge* classes.
1121 EmitEdgeClasses(CompilationGraphRecord, opt_descs, O);
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001122
1123 // Emit PopulateCompilationGraph function
Mikhail Glushenkov46d4e972008-05-06 16:36:06 +00001124 EmitPopulateCompilationGraph(CompilationGraphRecord, O);
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001125
1126 // EOF
1127}