blob: b1fdc4f29b7d6855c2b0977ab7388b0ad2221311 [file] [log] [blame]
Mikhail Glushenkov2d3327f2008-05-30 06:20:54 +00001//===- LLVMCConfigurationEmitter.cpp - Generate LLVMC config ----*- C++ -*-===//
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"
Mikhail Glushenkov0e92d2f2008-05-30 06:18:16 +000021#include "llvm/ADT/StringSet.h"
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +000022#include <algorithm>
23#include <cassert>
24#include <functional>
Mikhail Glushenkovffe736e2008-05-30 06:21:48 +000025#include <stdexcept>
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +000026#include <string>
Chris Lattner52aa6862008-06-04 04:46:14 +000027#include <typeinfo>
Mikhail Glushenkovb08aafd2008-11-12 00:04:46 +000028
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +000029using namespace llvm;
30
Mikhail Glushenkovc1f738d2008-05-06 18:12:03 +000031namespace {
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +000032
33//===----------------------------------------------------------------------===//
34/// Typedefs
35
36typedef std::vector<Record*> RecordVector;
37typedef std::vector<std::string> StrVector;
38
39//===----------------------------------------------------------------------===//
40/// Constants
41
Mikhail Glushenkovbe46ae12008-05-07 21:50:19 +000042// Indentation strings.
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +000043const char * Indent1 = " ";
44const char * Indent2 = " ";
45const char * Indent3 = " ";
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +000046
Mikhail Glushenkovbe46ae12008-05-07 21:50:19 +000047// Default help string.
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +000048const char * DefaultHelpString = "NO HELP MESSAGE PROVIDED";
49
Mikhail Glushenkovbe46ae12008-05-07 21:50:19 +000050// Name for the "sink" option.
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +000051const char * SinkOptionName = "AutoGeneratedSinkOption";
52
53//===----------------------------------------------------------------------===//
54/// Helper functions
55
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +000056/// Id - An 'identity' function object.
57struct Id {
58 template<typename T>
59 void operator()(const T&) const {
60 }
61};
62
Mikhail Glushenkov35576b02008-05-30 06:10:19 +000063int InitPtrToInt(const Init* ptr) {
64 const IntInit& val = dynamic_cast<const IntInit&>(*ptr);
Mikhail Glushenkovdfcad6c2008-05-06 18:18:20 +000065 return val.getValue();
66}
67
Mikhail Glushenkov0e92d2f2008-05-30 06:18:16 +000068const std::string& InitPtrToString(const Init* ptr) {
69 const StringInit& val = dynamic_cast<const StringInit&>(*ptr);
70 return val.getValue();
71}
72
73const ListInit& InitPtrToList(const Init* ptr) {
74 const ListInit& val = dynamic_cast<const ListInit&>(*ptr);
75 return val;
76}
77
78const DagInit& InitPtrToDag(const Init* ptr) {
Mikhail Glushenkov35576b02008-05-30 06:10:19 +000079 const DagInit& val = dynamic_cast<const DagInit&>(*ptr);
Mikhail Glushenkovdfcad6c2008-05-06 18:18:20 +000080 return val;
81}
82
Mikhail Glushenkovbe46ae12008-05-07 21:50:19 +000083// checkNumberOfArguments - Ensure that the number of args in d is
Mikhail Glushenkova964b032009-07-07 16:07:36 +000084// greater than or equal to min_arguments, otherwise throw an exception.
Mikhail Glushenkova5922cc2008-05-06 17:22:03 +000085void checkNumberOfArguments (const DagInit* d, unsigned min_arguments) {
Mikhail Glushenkov0e70fb52008-12-07 16:47:12 +000086 if (!d || d->getNumArgs() < min_arguments)
Mikhail Glushenkova964b032009-07-07 16:07:36 +000087 throw d->getOperator()->getAsString() + ": too few arguments!";
Mikhail Glushenkova5922cc2008-05-06 17:22:03 +000088}
89
Mikhail Glushenkovdedba642008-05-30 06:08:50 +000090// isDagEmpty - is this DAG marked with an empty marker?
91bool isDagEmpty (const DagInit* d) {
92 return d->getOperator()->getAsString() == "empty";
93}
Mikhail Glushenkova5922cc2008-05-06 17:22:03 +000094
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +000095// EscapeVariableName - Escape commas and other symbols not allowed
96// in the C++ variable names. Makes it possible to use options named
97// like "Wa," (useful for prefix options).
98std::string EscapeVariableName(const std::string& Var) {
99 std::string ret;
100 for (unsigned i = 0; i != Var.size(); ++i) {
101 char cur_char = Var[i];
102 if (cur_char == ',') {
103 ret += "_comma_";
104 }
105 else if (cur_char == '+') {
106 ret += "_plus_";
107 }
108 else if (cur_char == '-') {
109 ret += "_dash_";
110 }
111 else {
112 ret.push_back(cur_char);
113 }
114 }
115 return ret;
116}
117
Mikhail Glushenkovab0f3cb2009-01-21 13:04:00 +0000118/// oneOf - Does the input string contain this character?
119bool oneOf(const char* lst, char c) {
120 while (*lst) {
121 if (*lst++ == c)
122 return true;
123 }
124 return false;
125}
126
Mikhail Glushenkov8139ba32009-01-28 03:47:20 +0000127template <class I, class S>
128void checkedIncrement(I& P, I E, S ErrorString) {
129 ++P;
130 if (P == E)
131 throw ErrorString;
132}
133
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000134//===----------------------------------------------------------------------===//
135/// Back-end specific code
136
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000137
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +0000138/// OptionType - One of six different option types. See the
139/// documentation for detailed description of differences.
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000140namespace OptionType {
Mikhail Glushenkov753e8c52009-07-07 16:08:11 +0000141
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +0000142 enum OptionType { Alias, Switch, Parameter, ParameterList,
Mikhail Glushenkov0e70fb52008-12-07 16:47:12 +0000143 Prefix, PrefixList};
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +0000144
Mikhail Glushenkov753e8c52009-07-07 16:08:11 +0000145 bool IsList (OptionType t) {
146 return (t == ParameterList || t == PrefixList);
147 }
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000148
Mikhail Glushenkov753e8c52009-07-07 16:08:11 +0000149 bool IsSwitch (OptionType t) {
150 return (t == Switch);
151 }
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000152
Mikhail Glushenkov753e8c52009-07-07 16:08:11 +0000153 bool IsParameter (OptionType t) {
154 return (t == Parameter || t == Prefix);
155 }
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000156
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +0000157}
158
159OptionType::OptionType stringToOptionType(const std::string& T) {
160 if (T == "alias_option")
161 return OptionType::Alias;
162 else if (T == "switch_option")
163 return OptionType::Switch;
164 else if (T == "parameter_option")
165 return OptionType::Parameter;
166 else if (T == "parameter_list_option")
167 return OptionType::ParameterList;
168 else if (T == "prefix_option")
169 return OptionType::Prefix;
170 else if (T == "prefix_list_option")
171 return OptionType::PrefixList;
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +0000172 else
173 throw "Unknown option type: " + T + '!';
174}
175
176namespace OptionDescriptionFlags {
177 enum OptionDescriptionFlags { Required = 0x1, Hidden = 0x2,
Mikhail Glushenkov8139ba32009-01-28 03:47:20 +0000178 ReallyHidden = 0x4, Extern = 0x8,
179 OneOrMore = 0x10, ZeroOrOne = 0x20 };
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +0000180}
181
182/// OptionDescription - Represents data contained in a single
183/// OptionList entry.
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000184struct OptionDescription {
185 OptionType::OptionType Type;
186 std::string Name;
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +0000187 unsigned Flags;
188 std::string Help;
Mikhail Glushenkov8139ba32009-01-28 03:47:20 +0000189 unsigned MultiVal;
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000190
191 OptionDescription(OptionType::OptionType t = OptionType::Switch,
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +0000192 const std::string& n = "",
193 const std::string& h = DefaultHelpString)
Mikhail Glushenkov8139ba32009-01-28 03:47:20 +0000194 : Type(t), Name(n), Flags(0x0), Help(h), MultiVal(1)
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000195 {}
196
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +0000197 /// GenTypeDeclaration - Returns the C++ variable type of this
198 /// option.
199 const char* GenTypeDeclaration() const;
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000200
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +0000201 /// GenVariableName - Returns the variable name used in the
202 /// generated C++ code.
203 std::string GenVariableName() const;
Mikhail Glushenkovc9b650d2008-11-28 00:13:25 +0000204
Mikhail Glushenkovbe46ae12008-05-07 21:50:19 +0000205 /// Merge - Merge two option descriptions.
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +0000206 void Merge (const OptionDescription& other);
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000207
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +0000208 // Misc convenient getters/setters.
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000209
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +0000210 bool isAlias() const;
Mikhail Glushenkov0e70fb52008-12-07 16:47:12 +0000211
Mikhail Glushenkov8139ba32009-01-28 03:47:20 +0000212 bool isMultiVal() const;
213
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +0000214 bool isExtern() const;
Mikhail Glushenkov0e70fb52008-12-07 16:47:12 +0000215 void setExtern();
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +0000216
217 bool isRequired() const;
218 void setRequired();
219
Mikhail Glushenkov8139ba32009-01-28 03:47:20 +0000220 bool isOneOrMore() const;
221 void setOneOrMore();
222
223 bool isZeroOrOne() const;
224 void setZeroOrOne();
225
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +0000226 bool isHidden() const;
227 void setHidden();
228
229 bool isReallyHidden() const;
230 void setReallyHidden();
Mikhail Glushenkov8139ba32009-01-28 03:47:20 +0000231
Mikhail Glushenkov753e8c52009-07-07 16:08:11 +0000232 bool isParameter() const
233 { return OptionType::IsParameter(this->Type); }
234
235 bool isSwitch() const
236 { return OptionType::IsSwitch(this->Type); }
237
238 bool isList() const
239 { return OptionType::IsList(this->Type); }
240
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000241};
242
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +0000243void OptionDescription::Merge (const OptionDescription& other)
244{
245 if (other.Type != Type)
246 throw "Conflicting definitions for the option " + Name + "!";
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000247
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +0000248 if (Help == other.Help || Help == DefaultHelpString)
249 Help = other.Help;
250 else if (other.Help != DefaultHelpString) {
Daniel Dunbard4287062009-07-03 00:10:29 +0000251 llvm::errs() << "Warning: several different help strings"
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +0000252 " defined for option " + Name + "\n";
253 }
254
255 Flags |= other.Flags;
256}
257
258bool OptionDescription::isAlias() const {
259 return Type == OptionType::Alias;
260}
261
Mikhail Glushenkov8139ba32009-01-28 03:47:20 +0000262bool OptionDescription::isMultiVal() const {
Mikhail Glushenkove3649982009-01-28 03:47:58 +0000263 return MultiVal > 1;
Mikhail Glushenkov8139ba32009-01-28 03:47:20 +0000264}
265
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +0000266bool OptionDescription::isExtern() const {
Mikhail Glushenkov0e70fb52008-12-07 16:47:12 +0000267 return Flags & OptionDescriptionFlags::Extern;
268}
269void OptionDescription::setExtern() {
270 Flags |= OptionDescriptionFlags::Extern;
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +0000271}
272
273bool OptionDescription::isRequired() const {
274 return Flags & OptionDescriptionFlags::Required;
275}
276void OptionDescription::setRequired() {
277 Flags |= OptionDescriptionFlags::Required;
278}
279
Mikhail Glushenkov8139ba32009-01-28 03:47:20 +0000280bool OptionDescription::isOneOrMore() const {
281 return Flags & OptionDescriptionFlags::OneOrMore;
282}
283void OptionDescription::setOneOrMore() {
284 Flags |= OptionDescriptionFlags::OneOrMore;
285}
286
287bool OptionDescription::isZeroOrOne() const {
288 return Flags & OptionDescriptionFlags::ZeroOrOne;
289}
290void OptionDescription::setZeroOrOne() {
291 Flags |= OptionDescriptionFlags::ZeroOrOne;
292}
293
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +0000294bool OptionDescription::isHidden() const {
295 return Flags & OptionDescriptionFlags::Hidden;
296}
297void OptionDescription::setHidden() {
298 Flags |= OptionDescriptionFlags::Hidden;
299}
300
301bool OptionDescription::isReallyHidden() const {
302 return Flags & OptionDescriptionFlags::ReallyHidden;
303}
304void OptionDescription::setReallyHidden() {
305 Flags |= OptionDescriptionFlags::ReallyHidden;
306}
307
308const char* OptionDescription::GenTypeDeclaration() const {
309 switch (Type) {
310 case OptionType::Alias:
311 return "cl::alias";
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +0000312 case OptionType::PrefixList:
313 case OptionType::ParameterList:
314 return "cl::list<std::string>";
315 case OptionType::Switch:
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +0000316 return "cl::opt<bool>";
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +0000317 case OptionType::Parameter:
318 case OptionType::Prefix:
319 default:
320 return "cl::opt<std::string>";
321 }
322}
323
324std::string OptionDescription::GenVariableName() const {
325 const std::string& EscapedName = EscapeVariableName(Name);
326 switch (Type) {
327 case OptionType::Alias:
328 return "AutoGeneratedAlias_" + EscapedName;
329 case OptionType::PrefixList:
330 case OptionType::ParameterList:
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +0000331 return "AutoGeneratedList_" + EscapedName;
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +0000332 case OptionType::Switch:
333 return "AutoGeneratedSwitch_" + EscapedName;
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +0000334 case OptionType::Prefix:
335 case OptionType::Parameter:
336 default:
337 return "AutoGeneratedParameter_" + EscapedName;
338 }
339}
340
341/// OptionDescriptions - An OptionDescription array plus some helper
342/// functions.
343class OptionDescriptions {
344 typedef StringMap<OptionDescription> container_type;
345
346 /// Descriptions - A list of OptionDescriptions.
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000347 container_type Descriptions;
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000348
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +0000349public:
Mikhail Glushenkove5fcb552008-05-30 06:28:37 +0000350 /// FindOption - exception-throwing wrapper for find().
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +0000351 const OptionDescription& FindOption(const std::string& OptName) const;
Mikhail Glushenkova5922cc2008-05-06 17:22:03 +0000352
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +0000353 /// insertDescription - Insert new OptionDescription into
354 /// OptionDescriptions list
355 void InsertDescription (const OptionDescription& o);
Mikhail Glushenkovbf774352008-05-30 06:27:02 +0000356
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000357 // Support for STL-style iteration
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +0000358 typedef container_type::const_iterator const_iterator;
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000359 const_iterator begin() const { return Descriptions.begin(); }
360 const_iterator end() const { return Descriptions.end(); }
361};
362
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +0000363const OptionDescription&
364OptionDescriptions::FindOption(const std::string& OptName) const
365{
366 const_iterator I = Descriptions.find(OptName);
367 if (I != Descriptions.end())
368 return I->second;
369 else
370 throw OptName + ": no such option!";
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000371}
372
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +0000373void OptionDescriptions::InsertDescription (const OptionDescription& o)
374{
375 container_type::iterator I = Descriptions.find(o.Name);
376 if (I != Descriptions.end()) {
377 OptionDescription& D = I->second;
378 D.Merge(o);
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000379 }
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +0000380 else {
381 Descriptions[o.Name] = o;
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000382 }
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000383}
384
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +0000385/// HandlerTable - A base class for function objects implemented as
386/// 'tables of handlers'.
387template <class T>
388class HandlerTable {
389protected:
Mikhail Glushenkovbf774352008-05-30 06:27:02 +0000390 // Implementation details.
391
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +0000392 /// Handler -
393 typedef void (T::* Handler) (const DagInit*);
394 /// HandlerMap - A map from property names to property handlers
395 typedef StringMap<Handler> HandlerMap;
Mikhail Glushenkovbf774352008-05-30 06:27:02 +0000396
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +0000397 static HandlerMap Handlers_;
Mikhail Glushenkovbf774352008-05-30 06:27:02 +0000398 static bool staticMembersInitialized_;
399
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +0000400 T* childPtr;
401public:
Mikhail Glushenkovbf774352008-05-30 06:27:02 +0000402
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +0000403 HandlerTable(T* cp) : childPtr(cp)
404 {}
405
406 /// operator() - Just forwards to the corresponding property
407 /// handler.
408 void operator() (Init* i) {
409 const DagInit& property = InitPtrToDag(i);
410 const std::string& property_name = property.getOperator()->getAsString();
411 typename HandlerMap::iterator method = Handlers_.find(property_name);
412
413 if (method != Handlers_.end()) {
414 Handler h = method->second;
415 (childPtr->*h)(&property);
416 }
417 else {
418 throw "No handler found for property " + property_name + "!";
419 }
420 }
421
422 void AddHandler(const char* Property, Handler Handl) {
423 Handlers_[Property] = Handl;
424 }
425};
426
427template <class T> typename HandlerTable<T>::HandlerMap
428HandlerTable<T>::Handlers_;
429template <class T> bool HandlerTable<T>::staticMembersInitialized_ = false;
430
431
432/// CollectOptionProperties - Function object for iterating over an
433/// option property list.
434class CollectOptionProperties : public HandlerTable<CollectOptionProperties> {
435private:
436
437 /// optDescs_ - OptionDescriptions table. This is where the
438 /// information is stored.
439 OptionDescription& optDesc_;
Mikhail Glushenkovbf774352008-05-30 06:27:02 +0000440
441public:
442
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +0000443 explicit CollectOptionProperties(OptionDescription& OD)
444 : HandlerTable<CollectOptionProperties>(this), optDesc_(OD)
Mikhail Glushenkovbf774352008-05-30 06:27:02 +0000445 {
446 if (!staticMembersInitialized_) {
Mikhail Glushenkov0e70fb52008-12-07 16:47:12 +0000447 AddHandler("extern", &CollectOptionProperties::onExtern);
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +0000448 AddHandler("help", &CollectOptionProperties::onHelp);
449 AddHandler("hidden", &CollectOptionProperties::onHidden);
Mikhail Glushenkov8139ba32009-01-28 03:47:20 +0000450 AddHandler("multi_val", &CollectOptionProperties::onMultiVal);
451 AddHandler("one_or_more", &CollectOptionProperties::onOneOrMore);
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +0000452 AddHandler("really_hidden", &CollectOptionProperties::onReallyHidden);
453 AddHandler("required", &CollectOptionProperties::onRequired);
Mikhail Glushenkov8139ba32009-01-28 03:47:20 +0000454 AddHandler("zero_or_one", &CollectOptionProperties::onZeroOrOne);
Mikhail Glushenkovbf774352008-05-30 06:27:02 +0000455
456 staticMembersInitialized_ = true;
457 }
458 }
459
Mikhail Glushenkovbf774352008-05-30 06:27:02 +0000460private:
461
462 /// Option property handlers --
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +0000463 /// Methods that handle option properties such as (help) or (hidden).
Mikhail Glushenkov50084e82008-09-22 20:46:19 +0000464
Mikhail Glushenkov0e70fb52008-12-07 16:47:12 +0000465 void onExtern (const DagInit* d) {
466 checkNumberOfArguments(d, 0);
467 optDesc_.setExtern();
468 }
469
Mikhail Glushenkovbf774352008-05-30 06:27:02 +0000470 void onHelp (const DagInit* d) {
471 checkNumberOfArguments(d, 1);
Mikhail Glushenkov0e70fb52008-12-07 16:47:12 +0000472 optDesc_.Help = InitPtrToString(d->getArg(0));
Mikhail Glushenkovbf774352008-05-30 06:27:02 +0000473 }
474
Mikhail Glushenkovc9b650d2008-11-28 00:13:25 +0000475 void onHidden (const DagInit* d) {
476 checkNumberOfArguments(d, 0);
Mikhail Glushenkovc9b650d2008-11-28 00:13:25 +0000477 optDesc_.setHidden();
478 }
479
480 void onReallyHidden (const DagInit* d) {
481 checkNumberOfArguments(d, 0);
Mikhail Glushenkovc9b650d2008-11-28 00:13:25 +0000482 optDesc_.setReallyHidden();
483 }
484
Mikhail Glushenkovbf774352008-05-30 06:27:02 +0000485 void onRequired (const DagInit* d) {
486 checkNumberOfArguments(d, 0);
Mikhail Glushenkov8139ba32009-01-28 03:47:20 +0000487 if (optDesc_.isOneOrMore())
488 throw std::string("An option can't have both (required) "
489 "and (one_or_more) properties!");
Mikhail Glushenkovbf774352008-05-30 06:27:02 +0000490 optDesc_.setRequired();
491 }
492
Mikhail Glushenkov8139ba32009-01-28 03:47:20 +0000493 void onOneOrMore (const DagInit* d) {
494 checkNumberOfArguments(d, 0);
495 if (optDesc_.isRequired() || optDesc_.isZeroOrOne())
496 throw std::string("Only one of (required), (zero_or_one) or "
497 "(one_or_more) properties is allowed!");
498 if (!OptionType::IsList(optDesc_.Type))
Daniel Dunbard4287062009-07-03 00:10:29 +0000499 llvm::errs() << "Warning: specifying the 'one_or_more' property "
Mikhail Glushenkov8139ba32009-01-28 03:47:20 +0000500 "on a non-list option will have no effect.\n";
501 optDesc_.setOneOrMore();
502 }
503
504 void onZeroOrOne (const DagInit* d) {
505 checkNumberOfArguments(d, 0);
506 if (optDesc_.isRequired() || optDesc_.isOneOrMore())
507 throw std::string("Only one of (required), (zero_or_one) or "
508 "(one_or_more) properties is allowed!");
509 if (!OptionType::IsList(optDesc_.Type))
Daniel Dunbard4287062009-07-03 00:10:29 +0000510 llvm::errs() << "Warning: specifying the 'zero_or_one' property"
Mikhail Glushenkov8139ba32009-01-28 03:47:20 +0000511 "on a non-list option will have no effect.\n";
512 optDesc_.setZeroOrOne();
513 }
514
515 void onMultiVal (const DagInit* d) {
516 checkNumberOfArguments(d, 1);
517 int val = InitPtrToInt(d->getArg(0));
518 if (val < 2)
519 throw std::string("Error in the 'multi_val' property: "
520 "the value must be greater than 1!");
521 if (!OptionType::IsList(optDesc_.Type))
522 throw std::string("The multi_val property is valid only "
523 "on list options!");
524 optDesc_.MultiVal = val;
525 }
526
Mikhail Glushenkovbf774352008-05-30 06:27:02 +0000527};
528
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +0000529/// AddOption - A function object that is applied to every option
530/// description. Used by CollectOptionDescriptions.
Mikhail Glushenkove62df252008-05-30 06:27:29 +0000531class AddOption {
532private:
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +0000533 OptionDescriptions& OptDescs_;
Mikhail Glushenkove62df252008-05-30 06:27:29 +0000534
535public:
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +0000536 explicit AddOption(OptionDescriptions& OD) : OptDescs_(OD)
Mikhail Glushenkove62df252008-05-30 06:27:29 +0000537 {}
538
539 void operator()(const Init* i) {
540 const DagInit& d = InitPtrToDag(i);
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +0000541 checkNumberOfArguments(&d, 1);
Mikhail Glushenkove62df252008-05-30 06:27:29 +0000542
543 const OptionType::OptionType Type =
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +0000544 stringToOptionType(d.getOperator()->getAsString());
Mikhail Glushenkove62df252008-05-30 06:27:29 +0000545 const std::string& Name = InitPtrToString(d.getArg(0));
546
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +0000547 OptionDescription OD(Type, Name);
548
549 if (!OD.isExtern())
550 checkNumberOfArguments(&d, 2);
551
552 if (OD.isAlias()) {
553 // Aliases store the aliased option name in the 'Help' field.
Mikhail Glushenkove62df252008-05-30 06:27:29 +0000554 OD.Help = InitPtrToString(d.getArg(1));
555 }
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +0000556 else if (!OD.isExtern()) {
557 processOptionProperties(&d, OD);
558 }
559 OptDescs_.InsertDescription(OD);
Mikhail Glushenkove62df252008-05-30 06:27:29 +0000560 }
561
562private:
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +0000563 /// processOptionProperties - Go through the list of option
564 /// properties and call a corresponding handler for each.
565 static void processOptionProperties (const DagInit* d, OptionDescription& o) {
566 checkNumberOfArguments(d, 2);
567 DagInit::const_arg_iterator B = d->arg_begin();
568 // Skip the first argument: it's always the option name.
569 ++B;
570 std::for_each(B, d->arg_end(), CollectOptionProperties(o));
Mikhail Glushenkove62df252008-05-30 06:27:29 +0000571 }
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +0000572
Mikhail Glushenkove62df252008-05-30 06:27:29 +0000573};
574
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +0000575/// CollectOptionDescriptions - Collects option properties from all
576/// OptionLists.
577void CollectOptionDescriptions (RecordVector::const_iterator B,
578 RecordVector::const_iterator E,
579 OptionDescriptions& OptDescs)
580{
581 // For every OptionList:
582 for (; B!=E; ++B) {
583 RecordVector::value_type T = *B;
584 // Throws an exception if the value does not exist.
585 ListInit* PropList = T->getValueAsListInit("options");
Mikhail Glushenkove62df252008-05-30 06:27:29 +0000586
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +0000587 // For every option description in this list:
588 // collect the information and
589 std::for_each(PropList->begin(), PropList->end(), AddOption(OptDescs));
590 }
591}
592
593// Tool information record
594
595namespace ToolFlags {
596 enum ToolFlags { Join = 0x1, Sink = 0x2 };
597}
598
599struct ToolDescription : public RefCountedBase<ToolDescription> {
600 std::string Name;
601 Init* CmdLine;
602 Init* Actions;
603 StrVector InLanguage;
604 std::string OutLanguage;
605 std::string OutputSuffix;
606 unsigned Flags;
607
608 // Various boolean properties
609 void setSink() { Flags |= ToolFlags::Sink; }
610 bool isSink() const { return Flags & ToolFlags::Sink; }
611 void setJoin() { Flags |= ToolFlags::Join; }
612 bool isJoin() const { return Flags & ToolFlags::Join; }
613
614 // Default ctor here is needed because StringMap can only store
615 // DefaultConstructible objects
616 ToolDescription() : CmdLine(0), Actions(0), Flags(0) {}
617 ToolDescription (const std::string& n)
618 : Name(n), CmdLine(0), Actions(0), Flags(0)
619 {}
620};
621
622/// ToolDescriptions - A list of Tool information records.
623typedef std::vector<IntrusiveRefCntPtr<ToolDescription> > ToolDescriptions;
624
625
626/// CollectToolProperties - Function object for iterating over a list of
Mikhail Glushenkov7adcf1e2008-05-09 08:27:26 +0000627/// tool property records.
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +0000628class CollectToolProperties : public HandlerTable<CollectToolProperties> {
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000629private:
630
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +0000631 /// toolDesc_ - Properties of the current Tool. This is where the
632 /// information is stored.
633 ToolDescription& toolDesc_;
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000634
635public:
636
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +0000637 explicit CollectToolProperties (ToolDescription& d)
638 : HandlerTable<CollectToolProperties>(this) , toolDesc_(d)
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000639 {
640 if (!staticMembersInitialized_) {
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +0000641
642 AddHandler("actions", &CollectToolProperties::onActions);
643 AddHandler("cmd_line", &CollectToolProperties::onCmdLine);
644 AddHandler("in_language", &CollectToolProperties::onInLanguage);
645 AddHandler("join", &CollectToolProperties::onJoin);
646 AddHandler("out_language", &CollectToolProperties::onOutLanguage);
647 AddHandler("output_suffix", &CollectToolProperties::onOutputSuffix);
648 AddHandler("sink", &CollectToolProperties::onSink);
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000649
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000650 staticMembersInitialized_ = true;
651 }
652 }
653
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000654private:
655
656 /// Property handlers --
657 /// Functions that extract information about tool properties from
658 /// DAG representation.
659
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +0000660 void onActions (const DagInit* d) {
661 checkNumberOfArguments(d, 1);
Mikhail Glushenkov8d489a82008-12-07 16:45:12 +0000662 Init* Case = d->getArg(0);
663 if (typeid(*Case) != typeid(DagInit) ||
664 static_cast<DagInit*>(Case)->getOperator()->getAsString() != "case")
665 throw
666 std::string("The argument to (actions) should be a 'case' construct!");
667 toolDesc_.Actions = Case;
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +0000668 }
669
Mikhail Glushenkovdfcad6c2008-05-06 18:18:20 +0000670 void onCmdLine (const DagInit* d) {
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000671 checkNumberOfArguments(d, 1);
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +0000672 toolDesc_.CmdLine = d->getArg(0);
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000673 }
674
Mikhail Glushenkovdfcad6c2008-05-06 18:18:20 +0000675 void onInLanguage (const DagInit* d) {
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000676 checkNumberOfArguments(d, 1);
Mikhail Glushenkov0e92d2f2008-05-30 06:18:16 +0000677 Init* arg = d->getArg(0);
678
679 // Find out the argument's type.
680 if (typeid(*arg) == typeid(StringInit)) {
681 // It's a string.
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +0000682 toolDesc_.InLanguage.push_back(InitPtrToString(arg));
Mikhail Glushenkov0e92d2f2008-05-30 06:18:16 +0000683 }
684 else {
685 // It's a list.
686 const ListInit& lst = InitPtrToList(arg);
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +0000687 StrVector& out = toolDesc_.InLanguage;
Mikhail Glushenkov0e92d2f2008-05-30 06:18:16 +0000688
689 // Copy strings to the output vector.
690 for (ListInit::const_iterator B = lst.begin(), E = lst.end();
691 B != E; ++B) {
692 out.push_back(InitPtrToString(*B));
693 }
694
695 // Remove duplicates.
696 std::sort(out.begin(), out.end());
697 StrVector::iterator newE = std::unique(out.begin(), out.end());
698 out.erase(newE, out.end());
699 }
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000700 }
701
Mikhail Glushenkovdfcad6c2008-05-06 18:18:20 +0000702 void onJoin (const DagInit* d) {
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000703 checkNumberOfArguments(d, 0);
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +0000704 toolDesc_.setJoin();
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000705 }
706
Mikhail Glushenkovdfcad6c2008-05-06 18:18:20 +0000707 void onOutLanguage (const DagInit* d) {
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000708 checkNumberOfArguments(d, 1);
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +0000709 toolDesc_.OutLanguage = InitPtrToString(d->getArg(0));
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000710 }
711
Mikhail Glushenkovdfcad6c2008-05-06 18:18:20 +0000712 void onOutputSuffix (const DagInit* d) {
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000713 checkNumberOfArguments(d, 1);
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +0000714 toolDesc_.OutputSuffix = InitPtrToString(d->getArg(0));
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000715 }
716
Mikhail Glushenkovdfcad6c2008-05-06 18:18:20 +0000717 void onSink (const DagInit* d) {
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000718 checkNumberOfArguments(d, 0);
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +0000719 toolDesc_.setSink();
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000720 }
721
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000722};
723
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +0000724/// CollectToolDescriptions - Gather information about tool properties
Mikhail Glushenkovd638e852008-05-30 06:26:08 +0000725/// from the parsed TableGen data (basically a wrapper for the
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +0000726/// CollectToolProperties function object).
727void CollectToolDescriptions (RecordVector::const_iterator B,
728 RecordVector::const_iterator E,
729 ToolDescriptions& ToolDescs)
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000730{
731 // Iterate over a properties list of every Tool definition
732 for (;B!=E;++B) {
Mikhail Glushenkov973b3a32008-11-17 17:29:42 +0000733 const Record* T = *B;
Mikhail Glushenkovd638e852008-05-30 06:26:08 +0000734 // Throws an exception if the value does not exist.
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000735 ListInit* PropList = T->getValueAsListInit("properties");
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000736
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +0000737 IntrusiveRefCntPtr<ToolDescription>
738 ToolDesc(new ToolDescription(T->getName()));
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000739
740 std::for_each(PropList->begin(), PropList->end(),
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +0000741 CollectToolProperties(*ToolDesc));
742 ToolDescs.push_back(ToolDesc);
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000743 }
744}
745
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +0000746/// FillInEdgeVector - Merge all compilation graph definitions into
747/// one single edge list.
748void FillInEdgeVector(RecordVector::const_iterator B,
749 RecordVector::const_iterator E, RecordVector& Out) {
750 for (; B != E; ++B) {
751 const ListInit* edges = (*B)->getValueAsListInit("edges");
Mikhail Glushenkovbf774352008-05-30 06:27:02 +0000752
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +0000753 for (unsigned i = 0; i < edges->size(); ++i)
754 Out.push_back(edges->getElementAsRecord(i));
755 }
756}
757
758/// CalculatePriority - Calculate the priority of this plugin.
759int CalculatePriority(RecordVector::const_iterator B,
760 RecordVector::const_iterator E) {
761 int total = 0;
Mikhail Glushenkoveb71ecf2008-11-17 17:30:25 +0000762 for (; B!=E; ++B) {
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +0000763 total += static_cast<int>((*B)->getValueAsInt("priority"));
764 }
765 return total;
766}
Mikhail Glushenkovd638e852008-05-30 06:26:08 +0000767
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +0000768/// NotInGraph - Helper function object for FilterNotInGraph.
769struct NotInGraph {
770private:
771 const llvm::StringSet<>& ToolsInGraph_;
772
773public:
774 NotInGraph(const llvm::StringSet<>& ToolsInGraph)
775 : ToolsInGraph_(ToolsInGraph)
776 {}
777
778 bool operator()(const IntrusiveRefCntPtr<ToolDescription>& x) {
779 return (ToolsInGraph_.count(x->Name) == 0);
780 }
781};
782
783/// FilterNotInGraph - Filter out from ToolDescs all Tools not
784/// mentioned in the compilation graph definition.
785void FilterNotInGraph (const RecordVector& EdgeVector,
786 ToolDescriptions& ToolDescs) {
787
788 // List all tools mentioned in the graph.
789 llvm::StringSet<> ToolsInGraph;
790
791 for (RecordVector::const_iterator B = EdgeVector.begin(),
792 E = EdgeVector.end(); B != E; ++B) {
793
794 const Record* Edge = *B;
Mikhail Glushenkov02ec3a52008-12-07 16:44:47 +0000795 const std::string& NodeA = Edge->getValueAsString("a");
796 const std::string& NodeB = Edge->getValueAsString("b");
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +0000797
Mikhail Glushenkov02ec3a52008-12-07 16:44:47 +0000798 if (NodeA != "root")
799 ToolsInGraph.insert(NodeA);
800 ToolsInGraph.insert(NodeB);
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +0000801 }
802
803 // Filter ToolPropertiesList.
804 ToolDescriptions::iterator new_end =
805 std::remove_if(ToolDescs.begin(), ToolDescs.end(),
806 NotInGraph(ToolsInGraph));
807 ToolDescs.erase(new_end, ToolDescs.end());
808}
809
810/// FillInToolToLang - Fills in two tables that map tool names to
811/// (input, output) languages. Helper function used by TypecheckGraph().
812void FillInToolToLang (const ToolDescriptions& ToolDescs,
813 StringMap<StringSet<> >& ToolToInLang,
814 StringMap<std::string>& ToolToOutLang) {
815 for (ToolDescriptions::const_iterator B = ToolDescs.begin(),
816 E = ToolDescs.end(); B != E; ++B) {
817 const ToolDescription& D = *(*B);
818 for (StrVector::const_iterator B = D.InLanguage.begin(),
819 E = D.InLanguage.end(); B != E; ++B)
820 ToolToInLang[D.Name].insert(*B);
821 ToolToOutLang[D.Name] = D.OutLanguage;
Mikhail Glushenkovd638e852008-05-30 06:26:08 +0000822 }
823}
824
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +0000825/// TypecheckGraph - Check that names for output and input languages
826/// on all edges do match. This doesn't do much when the information
827/// about the whole graph is not available (i.e. when compiling most
828/// plugins).
829void TypecheckGraph (const RecordVector& EdgeVector,
830 const ToolDescriptions& ToolDescs) {
831 StringMap<StringSet<> > ToolToInLang;
832 StringMap<std::string> ToolToOutLang;
833
834 FillInToolToLang(ToolDescs, ToolToInLang, ToolToOutLang);
835 StringMap<std::string>::iterator IAE = ToolToOutLang.end();
836 StringMap<StringSet<> >::iterator IBE = ToolToInLang.end();
837
838 for (RecordVector::const_iterator B = EdgeVector.begin(),
839 E = EdgeVector.end(); B != E; ++B) {
840 const Record* Edge = *B;
Mikhail Glushenkov02ec3a52008-12-07 16:44:47 +0000841 const std::string& NodeA = Edge->getValueAsString("a");
842 const std::string& NodeB = Edge->getValueAsString("b");
843 StringMap<std::string>::iterator IA = ToolToOutLang.find(NodeA);
844 StringMap<StringSet<> >::iterator IB = ToolToInLang.find(NodeB);
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +0000845
Mikhail Glushenkov02ec3a52008-12-07 16:44:47 +0000846 if (NodeA != "root") {
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +0000847 if (IA != IAE && IB != IBE && IB->second.count(IA->second) == 0)
Mikhail Glushenkov02ec3a52008-12-07 16:44:47 +0000848 throw "Edge " + NodeA + "->" + NodeB
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +0000849 + ": output->input language mismatch";
850 }
851
Mikhail Glushenkov02ec3a52008-12-07 16:44:47 +0000852 if (NodeB == "root")
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +0000853 throw std::string("Edges back to the root are not allowed!");
854 }
855}
856
857/// WalkCase - Walks the 'case' expression DAG and invokes
858/// TestCallback on every test, and StatementCallback on every
859/// statement. Handles 'case' nesting, but not the 'and' and 'or'
860/// combinators.
861// TODO: Re-implement EmitCaseConstructHandler on top of this function?
862template <typename F1, typename F2>
863void WalkCase(Init* Case, F1 TestCallback, F2 StatementCallback) {
864 const DagInit& d = InitPtrToDag(Case);
865 bool even = false;
866 for (DagInit::const_arg_iterator B = d.arg_begin(), E = d.arg_end();
867 B != E; ++B) {
868 Init* arg = *B;
869 if (even && dynamic_cast<DagInit*>(arg)
870 && static_cast<DagInit*>(arg)->getOperator()->getAsString() == "case")
871 WalkCase(arg, TestCallback, StatementCallback);
872 else if (!even)
873 TestCallback(arg);
874 else
875 StatementCallback(arg);
876 even = !even;
877 }
878}
879
880/// ExtractOptionNames - A helper function object used by
881/// CheckForSuperfluousOptions() to walk the 'case' DAG.
882class ExtractOptionNames {
883 llvm::StringSet<>& OptionNames_;
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +0000884
Mikhail Glushenkovccce1922008-12-07 16:42:22 +0000885 void processDag(const Init* Statement) {
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +0000886 const DagInit& Stmt = InitPtrToDag(Statement);
887 const std::string& ActionName = Stmt.getOperator()->getAsString();
888 if (ActionName == "forward" || ActionName == "forward_as" ||
889 ActionName == "unpack_values" || ActionName == "switch_on" ||
890 ActionName == "parameter_equals" || ActionName == "element_in_list" ||
Mikhail Glushenkov43dc4ca2008-12-17 02:47:01 +0000891 ActionName == "not_empty" || ActionName == "empty") {
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +0000892 checkNumberOfArguments(&Stmt, 1);
893 const std::string& Name = InitPtrToString(Stmt.getArg(0));
894 OptionNames_.insert(Name);
895 }
896 else if (ActionName == "and" || ActionName == "or") {
897 for (unsigned i = 0, NumArgs = Stmt.getNumArgs(); i < NumArgs; ++i) {
Mikhail Glushenkovccce1922008-12-07 16:42:22 +0000898 this->processDag(Stmt.getArg(i));
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +0000899 }
900 }
901 }
Mikhail Glushenkovccce1922008-12-07 16:42:22 +0000902
903public:
904 ExtractOptionNames(llvm::StringSet<>& OptionNames) : OptionNames_(OptionNames)
905 {}
906
907 void operator()(const Init* Statement) {
908 if (typeid(*Statement) == typeid(ListInit)) {
909 const ListInit& DagList = *static_cast<const ListInit*>(Statement);
910 for (ListInit::const_iterator B = DagList.begin(), E = DagList.end();
911 B != E; ++B)
912 this->processDag(*B);
913 }
914 else {
915 this->processDag(Statement);
916 }
917 }
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +0000918};
919
Mikhail Glushenkove5fcb552008-05-30 06:28:37 +0000920/// CheckForSuperfluousOptions - Check that there are no side
921/// effect-free options (specified only in the OptionList). Otherwise,
922/// output a warning.
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +0000923void CheckForSuperfluousOptions (const RecordVector& Edges,
924 const ToolDescriptions& ToolDescs,
925 const OptionDescriptions& OptDescs) {
Mikhail Glushenkove5fcb552008-05-30 06:28:37 +0000926 llvm::StringSet<> nonSuperfluousOptions;
927
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +0000928 // Add all options mentioned in the ToolDesc.Actions to the set of
Mikhail Glushenkove5fcb552008-05-30 06:28:37 +0000929 // non-superfluous options.
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +0000930 for (ToolDescriptions::const_iterator B = ToolDescs.begin(),
931 E = ToolDescs.end(); B != E; ++B) {
932 const ToolDescription& TD = *(*B);
933 ExtractOptionNames Callback(nonSuperfluousOptions);
934 if (TD.Actions)
935 WalkCase(TD.Actions, Callback, Callback);
936 }
937
938 // Add all options mentioned in the 'case' clauses of the
939 // OptionalEdges of the compilation graph to the set of
940 // non-superfluous options.
941 for (RecordVector::const_iterator B = Edges.begin(), E = Edges.end();
942 B != E; ++B) {
943 const Record* Edge = *B;
944 DagInit* Weight = Edge->getValueAsDag("weight");
945
946 if (!isDagEmpty(Weight))
947 WalkCase(Weight, ExtractOptionNames(nonSuperfluousOptions), Id());
Mikhail Glushenkove5fcb552008-05-30 06:28:37 +0000948 }
949
950 // Check that all options in OptDescs belong to the set of
951 // non-superfluous options.
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +0000952 for (OptionDescriptions::const_iterator B = OptDescs.begin(),
Mikhail Glushenkove5fcb552008-05-30 06:28:37 +0000953 E = OptDescs.end(); B != E; ++B) {
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +0000954 const OptionDescription& Val = B->second;
Mikhail Glushenkove5fcb552008-05-30 06:28:37 +0000955 if (!nonSuperfluousOptions.count(Val.Name)
956 && Val.Type != OptionType::Alias)
Daniel Dunbard4287062009-07-03 00:10:29 +0000957 llvm::errs() << "Warning: option '-" << Val.Name << "' has no effect! "
Mikhail Glushenkove5fcb552008-05-30 06:28:37 +0000958 "Probable cause: this option is specified only in the OptionList.\n";
959 }
960}
961
Mikhail Glushenkov35576b02008-05-30 06:10:19 +0000962/// EmitCaseTest1Arg - Helper function used by
963/// EmitCaseConstructHandler.
964bool EmitCaseTest1Arg(const std::string& TestName,
965 const DagInit& d,
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +0000966 const OptionDescriptions& OptDescs,
Daniel Dunbard4287062009-07-03 00:10:29 +0000967 raw_ostream& O) {
Mikhail Glushenkov35576b02008-05-30 06:10:19 +0000968 checkNumberOfArguments(&d, 1);
969 const std::string& OptName = InitPtrToString(d.getArg(0));
Mikhail Glushenkov43dc4ca2008-12-17 02:47:01 +0000970
Mikhail Glushenkov35576b02008-05-30 06:10:19 +0000971 if (TestName == "switch_on") {
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +0000972 const OptionDescription& OptDesc = OptDescs.FindOption(OptName);
Mikhail Glushenkov753e8c52009-07-07 16:08:11 +0000973 if (!OptDesc.isSwitch())
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +0000974 throw OptName + ": incorrect option type - should be a switch!";
Mikhail Glushenkov35576b02008-05-30 06:10:19 +0000975 O << OptDesc.GenVariableName();
976 return true;
977 } else if (TestName == "input_languages_contain") {
978 O << "InLangs.count(\"" << OptName << "\") != 0";
979 return true;
Mikhail Glushenkov242d0e62008-05-30 06:19:52 +0000980 } else if (TestName == "in_language") {
Mikhail Glushenkov56a625a2008-09-22 20:48:22 +0000981 // This works only for single-argument Tool::GenerateAction. Join
982 // tools can process several files in different languages simultaneously.
983
984 // TODO: make this work with Edge::Weight (if possible).
Mikhail Glushenkovcdbfa1a2008-09-22 20:47:46 +0000985 O << "LangMap.GetLanguage(inFile) == \"" << OptName << '\"';
Mikhail Glushenkov242d0e62008-05-30 06:19:52 +0000986 return true;
Mikhail Glushenkov43dc4ca2008-12-17 02:47:01 +0000987 } else if (TestName == "not_empty" || TestName == "empty") {
988 const char* Test = (TestName == "empty") ? "" : "!";
989
Mikhail Glushenkovb4833872008-05-30 06:24:07 +0000990 if (OptName == "o") {
Mikhail Glushenkov43dc4ca2008-12-17 02:47:01 +0000991 O << Test << "OutputFilename.empty()";
Mikhail Glushenkovb4833872008-05-30 06:24:07 +0000992 return true;
993 }
994 else {
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +0000995 const OptionDescription& OptDesc = OptDescs.FindOption(OptName);
Mikhail Glushenkov753e8c52009-07-07 16:08:11 +0000996 if (OptDesc.isSwitch())
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +0000997 throw OptName
998 + ": incorrect option type - should be a list or parameter!";
Mikhail Glushenkov43dc4ca2008-12-17 02:47:01 +0000999 O << Test << OptDesc.GenVariableName() << ".empty()";
Mikhail Glushenkovb4833872008-05-30 06:24:07 +00001000 return true;
1001 }
Mikhail Glushenkov35576b02008-05-30 06:10:19 +00001002 }
1003
1004 return false;
1005}
1006
1007/// EmitCaseTest2Args - Helper function used by
1008/// EmitCaseConstructHandler.
1009bool EmitCaseTest2Args(const std::string& TestName,
1010 const DagInit& d,
1011 const char* IndentLevel,
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +00001012 const OptionDescriptions& OptDescs,
Daniel Dunbard4287062009-07-03 00:10:29 +00001013 raw_ostream& O) {
Mikhail Glushenkov35576b02008-05-30 06:10:19 +00001014 checkNumberOfArguments(&d, 2);
1015 const std::string& OptName = InitPtrToString(d.getArg(0));
1016 const std::string& OptArg = InitPtrToString(d.getArg(1));
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +00001017 const OptionDescription& OptDesc = OptDescs.FindOption(OptName);
Mikhail Glushenkov35576b02008-05-30 06:10:19 +00001018
1019 if (TestName == "parameter_equals") {
Mikhail Glushenkov753e8c52009-07-07 16:08:11 +00001020 if (!OptDesc.isParameter())
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +00001021 throw OptName + ": incorrect option type - should be a parameter!";
Mikhail Glushenkov35576b02008-05-30 06:10:19 +00001022 O << OptDesc.GenVariableName() << " == \"" << OptArg << "\"";
1023 return true;
1024 }
1025 else if (TestName == "element_in_list") {
Mikhail Glushenkov753e8c52009-07-07 16:08:11 +00001026 if (!OptDesc.isList())
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +00001027 throw OptName + ": incorrect option type - should be a list!";
Mikhail Glushenkov35576b02008-05-30 06:10:19 +00001028 const std::string& VarName = OptDesc.GenVariableName();
1029 O << "std::find(" << VarName << ".begin(),\n"
1030 << IndentLevel << Indent1 << VarName << ".end(), \""
1031 << OptArg << "\") != " << VarName << ".end()";
1032 return true;
1033 }
1034
1035 return false;
1036}
1037
1038// Forward declaration.
1039// EmitLogicalOperationTest and EmitCaseTest are mutually recursive.
1040void EmitCaseTest(const DagInit& d, const char* IndentLevel,
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +00001041 const OptionDescriptions& OptDescs,
Daniel Dunbard4287062009-07-03 00:10:29 +00001042 raw_ostream& O);
Mikhail Glushenkov35576b02008-05-30 06:10:19 +00001043
1044/// EmitLogicalOperationTest - Helper function used by
1045/// EmitCaseConstructHandler.
1046void EmitLogicalOperationTest(const DagInit& d, const char* LogicOp,
1047 const char* IndentLevel,
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +00001048 const OptionDescriptions& OptDescs,
Daniel Dunbard4287062009-07-03 00:10:29 +00001049 raw_ostream& O) {
Mikhail Glushenkov35576b02008-05-30 06:10:19 +00001050 O << '(';
1051 for (unsigned j = 0, NumArgs = d.getNumArgs(); j < NumArgs; ++j) {
Mikhail Glushenkov0e92d2f2008-05-30 06:18:16 +00001052 const DagInit& InnerTest = InitPtrToDag(d.getArg(j));
Mikhail Glushenkov35576b02008-05-30 06:10:19 +00001053 EmitCaseTest(InnerTest, IndentLevel, OptDescs, O);
1054 if (j != NumArgs - 1)
1055 O << ")\n" << IndentLevel << Indent1 << ' ' << LogicOp << " (";
1056 else
1057 O << ')';
1058 }
1059}
1060
1061/// EmitCaseTest - Helper function used by EmitCaseConstructHandler.
1062void EmitCaseTest(const DagInit& d, const char* IndentLevel,
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +00001063 const OptionDescriptions& OptDescs,
Daniel Dunbard4287062009-07-03 00:10:29 +00001064 raw_ostream& O) {
Mikhail Glushenkov35576b02008-05-30 06:10:19 +00001065 const std::string& TestName = d.getOperator()->getAsString();
1066
1067 if (TestName == "and")
1068 EmitLogicalOperationTest(d, "&&", IndentLevel, OptDescs, O);
1069 else if (TestName == "or")
1070 EmitLogicalOperationTest(d, "||", IndentLevel, OptDescs, O);
1071 else if (EmitCaseTest1Arg(TestName, d, OptDescs, O))
1072 return;
1073 else if (EmitCaseTest2Args(TestName, d, IndentLevel, OptDescs, O))
1074 return;
1075 else
1076 throw TestName + ": unknown edge property!";
1077}
1078
1079// Emit code that handles the 'case' construct.
1080// Takes a function object that should emit code for every case clause.
1081// Callback's type is
Daniel Dunbard4287062009-07-03 00:10:29 +00001082// void F(Init* Statement, const char* IndentLevel, raw_ostream& O).
Mikhail Glushenkov35576b02008-05-30 06:10:19 +00001083template <typename F>
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +00001084void EmitCaseConstructHandler(const Init* Dag, const char* IndentLevel,
Mikhail Glushenkov1d95e9f2008-05-31 13:43:21 +00001085 F Callback, bool EmitElseIf,
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +00001086 const OptionDescriptions& OptDescs,
Daniel Dunbard4287062009-07-03 00:10:29 +00001087 raw_ostream& O) {
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +00001088 const DagInit* d = &InitPtrToDag(Dag);
1089 if (d->getOperator()->getAsString() != "case")
1090 throw std::string("EmitCaseConstructHandler should be invoked"
1091 " only on 'case' expressions!");
Mikhail Glushenkov35576b02008-05-30 06:10:19 +00001092
Mikhail Glushenkov31681512008-05-30 06:15:47 +00001093 unsigned numArgs = d->getNumArgs();
1094 if (d->getNumArgs() < 2)
1095 throw "There should be at least one clause in the 'case' expression:\n"
1096 + d->getAsString();
1097
1098 for (unsigned i = 0; i != numArgs; ++i) {
Mikhail Glushenkov0e92d2f2008-05-30 06:18:16 +00001099 const DagInit& Test = InitPtrToDag(d->getArg(i));
Mikhail Glushenkov35576b02008-05-30 06:10:19 +00001100
Mikhail Glushenkov31681512008-05-30 06:15:47 +00001101 // Emit the test.
Mikhail Glushenkov35576b02008-05-30 06:10:19 +00001102 if (Test.getOperator()->getAsString() == "default") {
1103 if (i+2 != numArgs)
1104 throw std::string("The 'default' clause should be the last in the"
1105 "'case' construct!");
1106 O << IndentLevel << "else {\n";
1107 }
1108 else {
Mikhail Glushenkovb24c8b22008-05-30 06:22:15 +00001109 O << IndentLevel << ((i != 0 && EmitElseIf) ? "else if (" : "if (");
Mikhail Glushenkov35576b02008-05-30 06:10:19 +00001110 EmitCaseTest(Test, IndentLevel, OptDescs, O);
1111 O << ") {\n";
1112 }
1113
Mikhail Glushenkov31681512008-05-30 06:15:47 +00001114 // Emit the corresponding statement.
Mikhail Glushenkov35576b02008-05-30 06:10:19 +00001115 ++i;
1116 if (i == numArgs)
1117 throw "Case construct handler: no corresponding action "
1118 "found for the test " + Test.getAsString() + '!';
1119
Mikhail Glushenkovb24c8b22008-05-30 06:22:15 +00001120 Init* arg = d->getArg(i);
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +00001121 const DagInit* nd = dynamic_cast<DagInit*>(arg);
1122 if (nd && (nd->getOperator()->getAsString() == "case")) {
1123 // Handle the nested 'case'.
1124 EmitCaseConstructHandler(nd, (std::string(IndentLevel) + Indent1).c_str(),
Mikhail Glushenkovb24c8b22008-05-30 06:22:15 +00001125 Callback, EmitElseIf, OptDescs, O);
1126 }
1127 else {
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +00001128 Callback(arg, (std::string(IndentLevel) + Indent1).c_str(), O);
Mikhail Glushenkovb24c8b22008-05-30 06:22:15 +00001129 }
Mikhail Glushenkov35576b02008-05-30 06:10:19 +00001130 O << IndentLevel << "}\n";
1131 }
1132}
1133
Mikhail Glushenkovab0f3cb2009-01-21 13:04:00 +00001134/// TokenizeCmdline - converts from "$CALL(HookName, 'Arg1', 'Arg2')/path" to
1135/// ["$CALL(", "HookName", "Arg1", "Arg2", ")/path"] .
1136/// Helper function used by EmitCmdLineVecFill and.
1137void TokenizeCmdline(const std::string& CmdLine, StrVector& Out) {
1138 const char* Delimiters = " \t\n\v\f\r";
1139 enum TokenizerState
1140 { Normal, SpecialCommand, InsideSpecialCommand, InsideQuotationMarks }
1141 cur_st = Normal;
Mikhail Glushenkov688fbb62009-06-25 18:21:34 +00001142
1143 if (CmdLine.empty())
1144 return;
Mikhail Glushenkovab0f3cb2009-01-21 13:04:00 +00001145 Out.push_back("");
1146
1147 std::string::size_type B = CmdLine.find_first_not_of(Delimiters),
1148 E = CmdLine.size();
Mikhail Glushenkov688fbb62009-06-25 18:21:34 +00001149
Mikhail Glushenkovab0f3cb2009-01-21 13:04:00 +00001150 for (; B != E; ++B) {
1151 char cur_ch = CmdLine[B];
1152
1153 switch (cur_st) {
1154 case Normal:
1155 if (cur_ch == '$') {
1156 cur_st = SpecialCommand;
1157 break;
1158 }
1159 if (oneOf(Delimiters, cur_ch)) {
1160 // Skip whitespace
1161 B = CmdLine.find_first_not_of(Delimiters, B);
1162 if (B == std::string::npos) {
1163 B = E-1;
1164 continue;
1165 }
1166 --B;
1167 Out.push_back("");
1168 continue;
1169 }
1170 break;
1171
1172
1173 case SpecialCommand:
1174 if (oneOf(Delimiters, cur_ch)) {
1175 cur_st = Normal;
1176 Out.push_back("");
1177 continue;
1178 }
1179 if (cur_ch == '(') {
1180 Out.push_back("");
1181 cur_st = InsideSpecialCommand;
1182 continue;
1183 }
1184 break;
1185
1186 case InsideSpecialCommand:
1187 if (oneOf(Delimiters, cur_ch)) {
1188 continue;
1189 }
1190 if (cur_ch == '\'') {
1191 cur_st = InsideQuotationMarks;
1192 Out.push_back("");
1193 continue;
1194 }
1195 if (cur_ch == ')') {
1196 cur_st = Normal;
1197 Out.push_back("");
1198 }
1199 if (cur_ch == ',') {
1200 continue;
1201 }
1202
1203 break;
1204
1205 case InsideQuotationMarks:
1206 if (cur_ch == '\'') {
1207 cur_st = InsideSpecialCommand;
1208 continue;
1209 }
1210 break;
1211 }
1212
1213 Out.back().push_back(cur_ch);
1214 }
1215}
1216
Mikhail Glushenkov793f63d2008-05-30 06:12:24 +00001217/// SubstituteSpecialCommands - Perform string substitution for $CALL
1218/// and $ENV. Helper function used by EmitCmdLineVecFill().
Mikhail Glushenkovab0f3cb2009-01-21 13:04:00 +00001219StrVector::const_iterator SubstituteSpecialCommands
Daniel Dunbard4287062009-07-03 00:10:29 +00001220(StrVector::const_iterator Pos, StrVector::const_iterator End, raw_ostream& O)
Mikhail Glushenkovab0f3cb2009-01-21 13:04:00 +00001221{
Mikhail Glushenkov1e453b02008-05-30 06:13:29 +00001222
Mikhail Glushenkovab0f3cb2009-01-21 13:04:00 +00001223 const std::string& cmd = *Pos;
1224
1225 if (cmd == "$CALL") {
1226 checkedIncrement(Pos, End, "Syntax error in $CALL invocation!");
1227 const std::string& CmdName = *Pos;
1228
1229 if (CmdName == ")")
Mikhail Glushenkov1e453b02008-05-30 06:13:29 +00001230 throw std::string("$CALL invocation: empty argument list!");
1231
Mikhail Glushenkovab0f3cb2009-01-21 13:04:00 +00001232 O << "hooks::";
1233 O << CmdName << "(";
Mikhail Glushenkov1e453b02008-05-30 06:13:29 +00001234
Mikhail Glushenkovab0f3cb2009-01-21 13:04:00 +00001235
1236 bool firstIteration = true;
1237 while (true) {
1238 checkedIncrement(Pos, End, "Syntax error in $CALL invocation!");
1239 const std::string& Arg = *Pos;
1240 assert(Arg.size() != 0);
1241
1242 if (Arg[0] == ')')
1243 break;
1244
1245 if (firstIteration)
1246 firstIteration = false;
1247 else
1248 O << ", ";
1249
1250 O << '"' << Arg << '"';
1251 }
1252
1253 O << ')';
1254
1255 }
1256 else if (cmd == "$ENV") {
1257 checkedIncrement(Pos, End, "Syntax error in $ENV invocation!");
1258 const std::string& EnvName = *Pos;
1259
1260 if (EnvName == ")")
1261 throw "$ENV invocation: empty argument list!";
1262
1263 O << "checkCString(std::getenv(\"";
1264 O << EnvName;
1265 O << "\"))";
1266
1267 checkedIncrement(Pos, End, "Syntax error in $ENV invocation!");
Mikhail Glushenkov1e453b02008-05-30 06:13:29 +00001268 }
1269 else {
1270 throw "Unknown special command: " + cmd;
1271 }
1272
Mikhail Glushenkovab0f3cb2009-01-21 13:04:00 +00001273 const std::string& Leftover = *Pos;
1274 assert(Leftover.at(0) == ')');
1275 if (Leftover.size() != 1)
1276 O << " + std::string(\"" << (Leftover.c_str() + 1) << "\")";
Mikhail Glushenkov1e453b02008-05-30 06:13:29 +00001277
Mikhail Glushenkovab0f3cb2009-01-21 13:04:00 +00001278 return Pos;
Mikhail Glushenkov793f63d2008-05-30 06:12:24 +00001279}
1280
1281/// EmitCmdLineVecFill - Emit code that fills in the command line
1282/// vector. Helper function used by EmitGenerateActionMethod().
Mikhail Glushenkov35576b02008-05-30 06:10:19 +00001283void EmitCmdLineVecFill(const Init* CmdLine, const std::string& ToolName,
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +00001284 bool IsJoin, const char* IndentLevel,
Daniel Dunbard4287062009-07-03 00:10:29 +00001285 raw_ostream& O) {
Mikhail Glushenkov35576b02008-05-30 06:10:19 +00001286 StrVector StrVec;
Mikhail Glushenkovab0f3cb2009-01-21 13:04:00 +00001287 TokenizeCmdline(InitPtrToString(CmdLine), StrVec);
1288
Mikhail Glushenkov793f63d2008-05-30 06:12:24 +00001289 if (StrVec.empty())
Mikhail Glushenkov688fbb62009-06-25 18:21:34 +00001290 throw "Tool '" + ToolName + "' has empty command line!";
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001291
Mikhail Glushenkovab0f3cb2009-01-21 13:04:00 +00001292 StrVector::const_iterator I = StrVec.begin(), E = StrVec.end();
1293
1294 // If there is a hook invocation on the place of the first command, skip it.
Mikhail Glushenkov72b128f2009-04-19 00:22:35 +00001295 assert(!StrVec[0].empty());
Mikhail Glushenkovab0f3cb2009-01-21 13:04:00 +00001296 if (StrVec[0][0] == '$') {
1297 while (I != E && (*I)[0] != ')' )
1298 ++I;
1299
1300 // Skip the ')' symbol.
1301 ++I;
1302 }
1303 else {
1304 ++I;
1305 }
1306
1307 for (; I != E; ++I) {
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001308 const std::string& cmd = *I;
Mikhail Glushenkov72b128f2009-04-19 00:22:35 +00001309 assert(!cmd.empty());
Mikhail Glushenkov35576b02008-05-30 06:10:19 +00001310 O << IndentLevel;
Mikhail Glushenkov793f63d2008-05-30 06:12:24 +00001311 if (cmd.at(0) == '$') {
1312 if (cmd == "$INFILE") {
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +00001313 if (IsJoin)
Mikhail Glushenkov793f63d2008-05-30 06:12:24 +00001314 O << "for (PathVector::const_iterator B = inFiles.begin()"
1315 << ", E = inFiles.end();\n"
1316 << IndentLevel << "B != E; ++B)\n"
1317 << IndentLevel << Indent1 << "vec.push_back(B->toString());\n";
1318 else
1319 O << "vec.push_back(inFile.toString());\n";
1320 }
1321 else if (cmd == "$OUTFILE") {
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +00001322 O << "vec.push_back(out_file);\n";
Mikhail Glushenkov793f63d2008-05-30 06:12:24 +00001323 }
1324 else {
Mikhail Glushenkovab0f3cb2009-01-21 13:04:00 +00001325 O << "vec.push_back(";
1326 I = SubstituteSpecialCommands(I, E, O);
Mikhail Glushenkov1e453b02008-05-30 06:13:29 +00001327 O << ");\n";
Mikhail Glushenkov793f63d2008-05-30 06:12:24 +00001328 }
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001329 }
1330 else {
1331 O << "vec.push_back(\"" << cmd << "\");\n";
1332 }
1333 }
Mikhail Glushenkovab0f3cb2009-01-21 13:04:00 +00001334 O << IndentLevel << "cmd = ";
1335
1336 if (StrVec[0][0] == '$')
1337 SubstituteSpecialCommands(StrVec.begin(), StrVec.end(), O);
1338 else
1339 O << '"' << StrVec[0] << '"';
1340 O << ";\n";
Mikhail Glushenkov35576b02008-05-30 06:10:19 +00001341}
1342
Mikhail Glushenkov793f63d2008-05-30 06:12:24 +00001343/// EmitCmdLineVecFillCallback - A function object wrapper around
1344/// EmitCmdLineVecFill(). Used by EmitGenerateActionMethod() as an
1345/// argument to EmitCaseConstructHandler().
Mikhail Glushenkov35576b02008-05-30 06:10:19 +00001346class EmitCmdLineVecFillCallback {
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +00001347 bool IsJoin;
Mikhail Glushenkov35576b02008-05-30 06:10:19 +00001348 const std::string& ToolName;
1349 public:
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +00001350 EmitCmdLineVecFillCallback(bool J, const std::string& TN)
1351 : IsJoin(J), ToolName(TN) {}
Mikhail Glushenkov35576b02008-05-30 06:10:19 +00001352
1353 void operator()(const Init* Statement, const char* IndentLevel,
Daniel Dunbard4287062009-07-03 00:10:29 +00001354 raw_ostream& O) const
Mikhail Glushenkov35576b02008-05-30 06:10:19 +00001355 {
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +00001356 EmitCmdLineVecFill(Statement, ToolName, IsJoin,
1357 IndentLevel, O);
1358 }
1359};
1360
1361/// EmitForwardOptionPropertyHandlingCode - Helper function used to
1362/// implement EmitActionHandler. Emits code for
1363/// handling the (forward) and (forward_as) option properties.
1364void EmitForwardOptionPropertyHandlingCode (const OptionDescription& D,
1365 const char* Indent,
1366 const std::string& NewName,
Daniel Dunbard4287062009-07-03 00:10:29 +00001367 raw_ostream& O) {
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +00001368 const std::string& Name = NewName.empty()
1369 ? ("-" + D.Name)
1370 : NewName;
1371
1372 switch (D.Type) {
1373 case OptionType::Switch:
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +00001374 O << Indent << "vec.push_back(\"" << Name << "\");\n";
1375 break;
1376 case OptionType::Parameter:
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +00001377 O << Indent << "vec.push_back(\"" << Name << "\");\n";
1378 O << Indent << "vec.push_back(" << D.GenVariableName() << ");\n";
1379 break;
1380 case OptionType::Prefix:
1381 O << Indent << "vec.push_back(\"" << Name << "\" + "
1382 << D.GenVariableName() << ");\n";
1383 break;
1384 case OptionType::PrefixList:
1385 O << Indent << "for (" << D.GenTypeDeclaration()
1386 << "::iterator B = " << D.GenVariableName() << ".begin(),\n"
Mikhail Glushenkov8139ba32009-01-28 03:47:20 +00001387 << Indent << "E = " << D.GenVariableName() << ".end(); B != E;) {\n"
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +00001388 << Indent << Indent1 << "vec.push_back(\"" << Name << "\" + "
Mikhail Glushenkov8139ba32009-01-28 03:47:20 +00001389 << "*B);\n"
1390 << Indent << Indent1 << "++B;\n";
1391
1392 for (int i = 1, j = D.MultiVal; i < j; ++i) {
1393 O << Indent << Indent1 << "vec.push_back(*B);\n"
1394 << Indent << Indent1 << "++B;\n";
1395 }
1396
1397 O << Indent << "}\n";
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +00001398 break;
1399 case OptionType::ParameterList:
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +00001400 O << Indent << "for (" << D.GenTypeDeclaration()
1401 << "::iterator B = " << D.GenVariableName() << ".begin(),\n"
1402 << Indent << "E = " << D.GenVariableName()
Mikhail Glushenkov8139ba32009-01-28 03:47:20 +00001403 << ".end() ; B != E;) {\n"
1404 << Indent << Indent1 << "vec.push_back(\"" << Name << "\");\n";
1405
1406 for (int i = 0, j = D.MultiVal; i < j; ++i) {
1407 O << Indent << Indent1 << "vec.push_back(*B);\n"
1408 << Indent << Indent1 << "++B;\n";
1409 }
1410
1411 O << Indent << "}\n";
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +00001412 break;
1413 case OptionType::Alias:
1414 default:
1415 throw std::string("Aliases are not allowed in tool option descriptions!");
1416 }
1417}
1418
1419/// EmitActionHandler - Emit code that handles actions. Used by
1420/// EmitGenerateActionMethod() as an argument to
1421/// EmitCaseConstructHandler().
1422class EmitActionHandler {
1423 const OptionDescriptions& OptDescs;
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +00001424
Mikhail Glushenkovccce1922008-12-07 16:42:22 +00001425 void processActionDag(const Init* Statement, const char* IndentLevel,
Daniel Dunbard4287062009-07-03 00:10:29 +00001426 raw_ostream& O) const
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +00001427 {
1428 const DagInit& Dag = InitPtrToDag(Statement);
1429 const std::string& ActionName = Dag.getOperator()->getAsString();
1430
1431 if (ActionName == "append_cmd") {
1432 checkNumberOfArguments(&Dag, 1);
1433 const std::string& Cmd = InitPtrToString(Dag.getArg(0));
Mikhail Glushenkovfa8787d2009-02-27 06:46:55 +00001434 StrVector Out;
1435 llvm::SplitString(Cmd, Out);
1436
1437 for (StrVector::const_iterator B = Out.begin(), E = Out.end();
1438 B != E; ++B)
1439 O << IndentLevel << "vec.push_back(\"" << *B << "\");\n";
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +00001440 }
Mikhail Glushenkov43dc4ca2008-12-17 02:47:01 +00001441 else if (ActionName == "error") {
1442 O << IndentLevel << "throw std::runtime_error(\"" <<
1443 (Dag.getNumArgs() >= 1 ? InitPtrToString(Dag.getArg(0))
1444 : "Unknown error!")
1445 << "\");\n";
1446 }
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +00001447 else if (ActionName == "forward") {
1448 checkNumberOfArguments(&Dag, 1);
1449 const std::string& Name = InitPtrToString(Dag.getArg(0));
1450 EmitForwardOptionPropertyHandlingCode(OptDescs.FindOption(Name),
1451 IndentLevel, "", O);
1452 }
1453 else if (ActionName == "forward_as") {
1454 checkNumberOfArguments(&Dag, 2);
1455 const std::string& Name = InitPtrToString(Dag.getArg(0));
Mikhail Glushenkov09699552009-05-06 01:41:19 +00001456 const std::string& NewName = InitPtrToString(Dag.getArg(1));
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +00001457 EmitForwardOptionPropertyHandlingCode(OptDescs.FindOption(Name),
1458 IndentLevel, NewName, O);
1459 }
1460 else if (ActionName == "output_suffix") {
1461 checkNumberOfArguments(&Dag, 1);
1462 const std::string& OutSuf = InitPtrToString(Dag.getArg(0));
1463 O << IndentLevel << "output_suffix = \"" << OutSuf << "\";\n";
1464 }
1465 else if (ActionName == "stop_compilation") {
1466 O << IndentLevel << "stop_compilation = true;\n";
1467 }
1468 else if (ActionName == "unpack_values") {
1469 checkNumberOfArguments(&Dag, 1);
1470 const std::string& Name = InitPtrToString(Dag.getArg(0));
1471 const OptionDescription& D = OptDescs.FindOption(Name);
1472
Mikhail Glushenkov8139ba32009-01-28 03:47:20 +00001473 if (D.isMultiVal())
1474 throw std::string("Can't use unpack_values with multi-valued options!");
1475
Mikhail Glushenkov753e8c52009-07-07 16:08:11 +00001476 if (D.isList()) {
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +00001477 O << IndentLevel << "for (" << D.GenTypeDeclaration()
1478 << "::iterator B = " << D.GenVariableName() << ".begin(),\n"
1479 << IndentLevel << "E = " << D.GenVariableName()
1480 << ".end(); B != E; ++B)\n"
1481 << IndentLevel << Indent1 << "llvm::SplitString(*B, vec, \",\");\n";
1482 }
Mikhail Glushenkov753e8c52009-07-07 16:08:11 +00001483 else if (D.isParameter()){
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +00001484 O << Indent3 << "llvm::SplitString("
1485 << D.GenVariableName() << ", vec, \",\");\n";
1486 }
1487 else {
1488 throw "Option '" + D.Name +
1489 "': switches can't have the 'unpack_values' property!";
1490 }
1491 }
1492 else {
1493 throw "Unknown action name: " + ActionName + "!";
1494 }
Mikhail Glushenkov35576b02008-05-30 06:10:19 +00001495 }
Mikhail Glushenkovccce1922008-12-07 16:42:22 +00001496 public:
1497 EmitActionHandler(const OptionDescriptions& OD)
1498 : OptDescs(OD) {}
1499
1500 void operator()(const Init* Statement, const char* IndentLevel,
Daniel Dunbard4287062009-07-03 00:10:29 +00001501 raw_ostream& O) const
Mikhail Glushenkovccce1922008-12-07 16:42:22 +00001502 {
1503 if (typeid(*Statement) == typeid(ListInit)) {
1504 const ListInit& DagList = *static_cast<const ListInit*>(Statement);
1505 for (ListInit::const_iterator B = DagList.begin(), E = DagList.end();
1506 B != E; ++B)
1507 this->processActionDag(*B, IndentLevel, O);
1508 }
1509 else {
1510 this->processActionDag(Statement, IndentLevel, O);
1511 }
1512 }
Mikhail Glushenkov35576b02008-05-30 06:10:19 +00001513};
1514
1515// EmitGenerateActionMethod - Emit one of two versions of the
1516// Tool::GenerateAction() method.
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +00001517void EmitGenerateActionMethod (const ToolDescription& D,
1518 const OptionDescriptions& OptDescs,
Daniel Dunbard4287062009-07-03 00:10:29 +00001519 bool IsJoin, raw_ostream& O) {
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +00001520 if (IsJoin)
Mikhail Glushenkov35576b02008-05-30 06:10:19 +00001521 O << Indent1 << "Action GenerateAction(const PathVector& inFiles,\n";
1522 else
1523 O << Indent1 << "Action GenerateAction(const sys::Path& inFile,\n";
1524
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +00001525 O << Indent2 << "bool HasChildren,\n"
1526 << Indent2 << "const llvm::sys::Path& TempDir,\n"
Mikhail Glushenkovcdbfa1a2008-09-22 20:47:46 +00001527 << Indent2 << "const InputLanguagesSet& InLangs,\n"
1528 << Indent2 << "const LanguageMap& LangMap) const\n"
Mikhail Glushenkov35576b02008-05-30 06:10:19 +00001529 << Indent1 << "{\n"
foldre4a81682008-11-08 19:43:32 +00001530 << Indent2 << "std::string cmd;\n"
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +00001531 << Indent2 << "std::vector<std::string> vec;\n"
1532 << Indent2 << "bool stop_compilation = !HasChildren;\n"
1533 << Indent2 << "const char* output_suffix = \"" << D.OutputSuffix << "\";\n"
1534 << Indent2 << "std::string out_file;\n\n";
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001535
Mikhail Glushenkov7adcf1e2008-05-09 08:27:26 +00001536 // For every understood option, emit handling code.
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +00001537 if (D.Actions)
1538 EmitCaseConstructHandler(D.Actions, Indent2, EmitActionHandler(OptDescs),
1539 false, OptDescs, O);
1540
1541 O << '\n' << Indent2
1542 << "out_file = OutFilename(" << (IsJoin ? "sys::Path(),\n" : "inFile,\n")
1543 << Indent3 << "TempDir, stop_compilation, output_suffix).toString();\n\n";
1544
1545 // cmd_line is either a string or a 'case' construct.
1546 if (!D.CmdLine)
1547 throw "Tool " + D.Name + " has no cmd_line property!";
1548 else if (typeid(*D.CmdLine) == typeid(StringInit))
1549 EmitCmdLineVecFill(D.CmdLine, D.Name, IsJoin, Indent2, O);
1550 else
1551 EmitCaseConstructHandler(D.CmdLine, Indent2,
1552 EmitCmdLineVecFillCallback(IsJoin, D.Name),
1553 true, OptDescs, O);
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001554
Mikhail Glushenkov7adcf1e2008-05-09 08:27:26 +00001555 // Handle the Sink property.
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +00001556 if (D.isSink()) {
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001557 O << Indent2 << "if (!" << SinkOptionName << ".empty()) {\n"
1558 << Indent3 << "vec.insert(vec.end(), "
1559 << SinkOptionName << ".begin(), " << SinkOptionName << ".end());\n"
1560 << Indent2 << "}\n";
1561 }
1562
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +00001563 O << Indent2 << "return Action(cmd, vec, stop_compilation, out_file);\n"
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001564 << Indent1 << "}\n\n";
1565}
1566
Mikhail Glushenkov7adcf1e2008-05-09 08:27:26 +00001567/// EmitGenerateActionMethods - Emit two GenerateAction() methods for
1568/// a given Tool class.
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +00001569void EmitGenerateActionMethods (const ToolDescription& ToolDesc,
1570 const OptionDescriptions& OptDescs,
Daniel Dunbard4287062009-07-03 00:10:29 +00001571 raw_ostream& O) {
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +00001572 if (!ToolDesc.isJoin())
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001573 O << Indent1 << "Action GenerateAction(const PathVector& inFiles,\n"
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +00001574 << Indent2 << "bool HasChildren,\n"
1575 << Indent2 << "const llvm::sys::Path& TempDir,\n"
Mikhail Glushenkovcdbfa1a2008-09-22 20:47:46 +00001576 << Indent2 << "const InputLanguagesSet& InLangs,\n"
1577 << Indent2 << "const LanguageMap& LangMap) const\n"
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001578 << Indent1 << "{\n"
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +00001579 << Indent2 << "throw std::runtime_error(\"" << ToolDesc.Name
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001580 << " is not a Join tool!\");\n"
1581 << Indent1 << "}\n\n";
1582 else
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +00001583 EmitGenerateActionMethod(ToolDesc, OptDescs, true, O);
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001584
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +00001585 EmitGenerateActionMethod(ToolDesc, OptDescs, false, O);
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001586}
1587
Mikhail Glushenkovbe46ae12008-05-07 21:50:19 +00001588/// EmitInOutLanguageMethods - Emit the [Input,Output]Language()
1589/// methods for a given Tool class.
Daniel Dunbard4287062009-07-03 00:10:29 +00001590void EmitInOutLanguageMethods (const ToolDescription& D, raw_ostream& O) {
Mikhail Glushenkov61923cb2008-05-30 06:24:49 +00001591 O << Indent1 << "const char** InputLanguages() const {\n"
1592 << Indent2 << "return InputLanguages_;\n"
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001593 << Indent1 << "}\n\n";
1594
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +00001595 if (D.OutLanguage.empty())
1596 throw "Tool " + D.Name + " has no 'out_language' property!";
1597
Mikhail Glushenkovd379d162008-05-06 17:24:26 +00001598 O << Indent1 << "const char* OutputLanguage() const {\n"
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +00001599 << Indent2 << "return \"" << D.OutLanguage << "\";\n"
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001600 << Indent1 << "}\n\n";
1601}
1602
Mikhail Glushenkovbe46ae12008-05-07 21:50:19 +00001603/// EmitNameMethod - Emit the Name() method for a given Tool class.
Daniel Dunbard4287062009-07-03 00:10:29 +00001604void EmitNameMethod (const ToolDescription& D, raw_ostream& O) {
Mikhail Glushenkovd379d162008-05-06 17:24:26 +00001605 O << Indent1 << "const char* Name() const {\n"
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +00001606 << Indent2 << "return \"" << D.Name << "\";\n"
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001607 << Indent1 << "}\n\n";
1608}
1609
Mikhail Glushenkovbe46ae12008-05-07 21:50:19 +00001610/// EmitIsJoinMethod - Emit the IsJoin() method for a given Tool
1611/// class.
Daniel Dunbard4287062009-07-03 00:10:29 +00001612void EmitIsJoinMethod (const ToolDescription& D, raw_ostream& O) {
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001613 O << Indent1 << "bool IsJoin() const {\n";
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +00001614 if (D.isJoin())
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001615 O << Indent2 << "return true;\n";
1616 else
1617 O << Indent2 << "return false;\n";
1618 O << Indent1 << "}\n\n";
1619}
1620
Mikhail Glushenkov61923cb2008-05-30 06:24:49 +00001621/// EmitStaticMemberDefinitions - Emit static member definitions for a
1622/// given Tool class.
Daniel Dunbard4287062009-07-03 00:10:29 +00001623void EmitStaticMemberDefinitions(const ToolDescription& D, raw_ostream& O) {
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +00001624 if (D.InLanguage.empty())
1625 throw "Tool " + D.Name + " has no 'in_language' property!";
1626
1627 O << "const char* " << D.Name << "::InputLanguages_[] = {";
1628 for (StrVector::const_iterator B = D.InLanguage.begin(),
1629 E = D.InLanguage.end(); B != E; ++B)
Mikhail Glushenkov61923cb2008-05-30 06:24:49 +00001630 O << '\"' << *B << "\", ";
1631 O << "0};\n\n";
1632}
1633
Mikhail Glushenkovbe46ae12008-05-07 21:50:19 +00001634/// EmitToolClassDefinition - Emit a Tool class definition.
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +00001635void EmitToolClassDefinition (const ToolDescription& D,
1636 const OptionDescriptions& OptDescs,
Daniel Dunbard4287062009-07-03 00:10:29 +00001637 raw_ostream& O) {
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +00001638 if (D.Name == "root")
Mikhail Glushenkov2cfd2232008-05-06 16:35:25 +00001639 return;
1640
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001641 // Header
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +00001642 O << "class " << D.Name << " : public ";
1643 if (D.isJoin())
Mikhail Glushenkov121889c2008-05-06 17:26:53 +00001644 O << "JoinTool";
1645 else
1646 O << "Tool";
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001647
Mikhail Glushenkov61923cb2008-05-30 06:24:49 +00001648 O << "{\nprivate:\n"
1649 << Indent1 << "static const char* InputLanguages_[];\n\n";
1650
1651 O << "public:\n";
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +00001652 EmitNameMethod(D, O);
1653 EmitInOutLanguageMethods(D, O);
1654 EmitIsJoinMethod(D, O);
1655 EmitGenerateActionMethods(D, OptDescs, O);
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001656
1657 // Close class definition
Mikhail Glushenkov61923cb2008-05-30 06:24:49 +00001658 O << "};\n";
1659
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +00001660 EmitStaticMemberDefinitions(D, O);
Mikhail Glushenkov61923cb2008-05-30 06:24:49 +00001661
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001662}
1663
Mikhail Glushenkov087aebe2009-06-23 20:45:07 +00001664/// EmitOptionDefinitions - Iterate over a list of option descriptions
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +00001665/// and emit registration code.
Mikhail Glushenkov087aebe2009-06-23 20:45:07 +00001666void EmitOptionDefinitions (const OptionDescriptions& descs,
1667 bool HasSink, bool HasExterns,
Daniel Dunbard4287062009-07-03 00:10:29 +00001668 raw_ostream& O)
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001669{
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +00001670 std::vector<OptionDescription> Aliases;
Mikhail Glushenkovb623c322008-05-30 06:22:52 +00001671
Mikhail Glushenkov52a54132008-05-30 06:23:29 +00001672 // Emit static cl::Option variables.
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +00001673 for (OptionDescriptions::const_iterator B = descs.begin(),
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001674 E = descs.end(); B!=E; ++B) {
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +00001675 const OptionDescription& val = B->second;
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001676
Mikhail Glushenkovb623c322008-05-30 06:22:52 +00001677 if (val.Type == OptionType::Alias) {
1678 Aliases.push_back(val);
1679 continue;
1680 }
1681
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +00001682 if (val.isExtern())
1683 O << "extern ";
1684
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001685 O << val.GenTypeDeclaration() << ' '
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +00001686 << val.GenVariableName();
1687
1688 if (val.isExtern()) {
1689 O << ";\n";
1690 continue;
1691 }
1692
Mikhail Glushenkovacaf35f2009-06-23 20:45:31 +00001693 O << "(\"" << val.Name << "\"\n";
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001694
1695 if (val.Type == OptionType::Prefix || val.Type == OptionType::PrefixList)
1696 O << ", cl::Prefix";
1697
1698 if (val.isRequired()) {
Mikhail Glushenkov753e8c52009-07-07 16:08:11 +00001699 if (val.isList() && !val.isMultiVal())
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001700 O << ", cl::OneOrMore";
Mikhail Glushenkov8139ba32009-01-28 03:47:20 +00001701 else
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001702 O << ", cl::Required";
Mikhail Glushenkov8139ba32009-01-28 03:47:20 +00001703 }
Mikhail Glushenkov753e8c52009-07-07 16:08:11 +00001704 else if (val.isOneOrMore() && val.isList()) {
Mikhail Glushenkov8139ba32009-01-28 03:47:20 +00001705 O << ", cl::OneOrMore";
1706 }
Mikhail Glushenkov753e8c52009-07-07 16:08:11 +00001707 else if (val.isZeroOrOne() && val.isList()) {
Mikhail Glushenkov8139ba32009-01-28 03:47:20 +00001708 O << ", cl::ZeroOrOne";
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001709 }
1710
Mikhail Glushenkov8139ba32009-01-28 03:47:20 +00001711 if (val.isReallyHidden()) {
1712 O << ", cl::ReallyHidden";
Mikhail Glushenkovc9b650d2008-11-28 00:13:25 +00001713 }
Mikhail Glushenkov8139ba32009-01-28 03:47:20 +00001714 else if (val.isHidden()) {
1715 O << ", cl::Hidden";
1716 }
1717
1718 if (val.MultiVal > 1)
1719 O << ", cl::multi_val(" << val.MultiVal << ")";
Mikhail Glushenkovc9b650d2008-11-28 00:13:25 +00001720
Mikhail Glushenkovb623c322008-05-30 06:22:52 +00001721 if (!val.Help.empty())
1722 O << ", cl::desc(\"" << val.Help << "\")";
1723
Mikhail Glushenkovacaf35f2009-06-23 20:45:31 +00001724 O << ");\n\n";
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001725 }
1726
Mikhail Glushenkovb623c322008-05-30 06:22:52 +00001727 // Emit the aliases (they should go after all the 'proper' options).
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +00001728 for (std::vector<OptionDescription>::const_iterator
Mikhail Glushenkovb623c322008-05-30 06:22:52 +00001729 B = Aliases.begin(), E = Aliases.end(); B != E; ++B) {
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +00001730 const OptionDescription& val = *B;
Mikhail Glushenkovb623c322008-05-30 06:22:52 +00001731
1732 O << val.GenTypeDeclaration() << ' '
1733 << val.GenVariableName()
1734 << "(\"" << val.Name << '\"';
1735
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +00001736 const OptionDescription& D = descs.FindOption(val.Help);
1737 O << ", cl::aliasopt(" << D.GenVariableName() << ")";
Mikhail Glushenkovb623c322008-05-30 06:22:52 +00001738
1739 O << ", cl::desc(\"" << "An alias for -" + val.Help << "\"));\n";
1740 }
1741
1742 // Emit the sink option.
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +00001743 if (HasSink)
Mikhail Glushenkov9111ba22008-12-07 16:42:47 +00001744 O << (HasExterns ? "extern cl" : "cl")
1745 << "::list<std::string> " << SinkOptionName
1746 << (HasExterns ? ";\n" : "(cl::Sink);\n");
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001747
1748 O << '\n';
1749}
1750
Mikhail Glushenkovbe46ae12008-05-07 21:50:19 +00001751/// EmitPopulateLanguageMap - Emit the PopulateLanguageMap() function.
Daniel Dunbard4287062009-07-03 00:10:29 +00001752void EmitPopulateLanguageMap (const RecordKeeper& Records, raw_ostream& O)
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001753{
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001754 // Generate code
Mikhail Glushenkov945522f2008-09-22 20:49:34 +00001755 O << "void PopulateLanguageMapLocal(LanguageMap& langMap) {\n";
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001756
Mikhail Glushenkovfa990682008-11-17 17:29:18 +00001757 // Get the relevant field out of RecordKeeper
Mikhail Glushenkov973b3a32008-11-17 17:29:42 +00001758 const Record* LangMapRecord = Records.getDef("LanguageMap");
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001759
Mikhail Glushenkovfa990682008-11-17 17:29:18 +00001760 // It is allowed for a plugin to have no language map.
1761 if (LangMapRecord) {
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001762
Mikhail Glushenkovfa990682008-11-17 17:29:18 +00001763 ListInit* LangsToSuffixesList = LangMapRecord->getValueAsListInit("map");
1764 if (!LangsToSuffixesList)
1765 throw std::string("Error in the language map definition!");
1766
1767 for (unsigned i = 0; i < LangsToSuffixesList->size(); ++i) {
Mikhail Glushenkov973b3a32008-11-17 17:29:42 +00001768 const Record* LangToSuffixes = LangsToSuffixesList->getElementAsRecord(i);
Mikhail Glushenkovfa990682008-11-17 17:29:18 +00001769
1770 const std::string& Lang = LangToSuffixes->getValueAsString("lang");
1771 const ListInit* Suffixes = LangToSuffixes->getValueAsListInit("suffixes");
1772
1773 for (unsigned i = 0; i < Suffixes->size(); ++i)
1774 O << Indent1 << "langMap[\""
1775 << InitPtrToString(Suffixes->getElement(i))
1776 << "\"] = \"" << Lang << "\";\n";
1777 }
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001778 }
1779
Mikhail Glushenkov64046a72008-12-11 10:34:18 +00001780 O << "}\n\n";
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001781}
1782
Mikhail Glushenkov793f63d2008-05-30 06:12:24 +00001783/// IncDecWeight - Helper function passed to EmitCaseConstructHandler()
1784/// by EmitEdgeClass().
Mikhail Glushenkov35576b02008-05-30 06:10:19 +00001785void IncDecWeight (const Init* i, const char* IndentLevel,
Daniel Dunbard4287062009-07-03 00:10:29 +00001786 raw_ostream& O) {
Mikhail Glushenkov0e92d2f2008-05-30 06:18:16 +00001787 const DagInit& d = InitPtrToDag(i);
Mikhail Glushenkovdedba642008-05-30 06:08:50 +00001788 const std::string& OpName = d.getOperator()->getAsString();
1789
Mikhail Glushenkov43dc4ca2008-12-17 02:47:01 +00001790 if (OpName == "inc_weight") {
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +00001791 O << IndentLevel << "ret += ";
Mikhail Glushenkov43dc4ca2008-12-17 02:47:01 +00001792 }
1793 else if (OpName == "dec_weight") {
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +00001794 O << IndentLevel << "ret -= ";
Mikhail Glushenkov43dc4ca2008-12-17 02:47:01 +00001795 }
1796 else if (OpName == "error") {
1797 O << IndentLevel << "throw std::runtime_error(\"" <<
1798 (d.getNumArgs() >= 1 ? InitPtrToString(d.getArg(0))
1799 : "Unknown error!")
1800 << "\");\n";
1801 return;
1802 }
1803
Mikhail Glushenkovdedba642008-05-30 06:08:50 +00001804 else
Mikhail Glushenkov43dc4ca2008-12-17 02:47:01 +00001805 throw "Unknown operator in edge properties list: " + OpName + '!' +
Mikhail Glushenkov55c6bdf2008-12-18 04:06:58 +00001806 "\nOnly 'inc_weight', 'dec_weight' and 'error' are allowed.";
Mikhail Glushenkovdedba642008-05-30 06:08:50 +00001807
1808 if (d.getNumArgs() > 0)
1809 O << InitPtrToInt(d.getArg(0)) << ";\n";
1810 else
1811 O << "2;\n";
1812
Mikhail Glushenkovdfcad6c2008-05-06 18:18:20 +00001813}
1814
Mikhail Glushenkovbe46ae12008-05-07 21:50:19 +00001815/// EmitEdgeClass - Emit a single Edge# class.
Mikhail Glushenkov35576b02008-05-30 06:10:19 +00001816void EmitEdgeClass (unsigned N, const std::string& Target,
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +00001817 DagInit* Case, const OptionDescriptions& OptDescs,
Daniel Dunbard4287062009-07-03 00:10:29 +00001818 raw_ostream& O) {
Mikhail Glushenkov8d0d5d22008-05-06 17:23:14 +00001819
1820 // Class constructor.
1821 O << "class Edge" << N << ": public Edge {\n"
1822 << "public:\n"
1823 << Indent1 << "Edge" << N << "() : Edge(\"" << Target
1824 << "\") {}\n\n"
1825
Mikhail Glushenkov7dbc0ab2008-05-06 18:14:24 +00001826 // Function Weight().
Mikhail Glushenkovd6228882008-05-06 18:15:12 +00001827 << Indent1 << "unsigned Weight(const InputLanguagesSet& InLangs) const {\n"
Mikhail Glushenkov7dbc0ab2008-05-06 18:14:24 +00001828 << Indent2 << "unsigned ret = 0;\n";
Mikhail Glushenkov8d0d5d22008-05-06 17:23:14 +00001829
Mikhail Glushenkovdedba642008-05-30 06:08:50 +00001830 // Handle the 'case' construct.
Mikhail Glushenkovb24c8b22008-05-30 06:22:15 +00001831 EmitCaseConstructHandler(Case, Indent2, IncDecWeight, false, OptDescs, O);
Mikhail Glushenkov7dbc0ab2008-05-06 18:14:24 +00001832
1833 O << Indent2 << "return ret;\n"
1834 << Indent1 << "};\n\n};\n\n";
Mikhail Glushenkov8d0d5d22008-05-06 17:23:14 +00001835}
1836
Mikhail Glushenkov793f63d2008-05-30 06:12:24 +00001837/// EmitEdgeClasses - Emit Edge* classes that represent graph edges.
Mikhail Glushenkovd24c1292008-11-28 00:13:47 +00001838void EmitEdgeClasses (const RecordVector& EdgeVector,
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +00001839 const OptionDescriptions& OptDescs,
Daniel Dunbard4287062009-07-03 00:10:29 +00001840 raw_ostream& O) {
Mikhail Glushenkovd24c1292008-11-28 00:13:47 +00001841 int i = 0;
Mikhail Glushenkov02ec3a52008-12-07 16:44:47 +00001842 for (RecordVector::const_iterator B = EdgeVector.begin(),
1843 E = EdgeVector.end(); B != E; ++B) {
1844 const Record* Edge = *B;
1845 const std::string& NodeB = Edge->getValueAsString("b");
Mikhail Glushenkovdedba642008-05-30 06:08:50 +00001846 DagInit* Weight = Edge->getValueAsDag("weight");
Mikhail Glushenkov46d4e972008-05-06 16:36:06 +00001847
Mikhail Glushenkovd24c1292008-11-28 00:13:47 +00001848 if (!isDagEmpty(Weight))
Mikhail Glushenkov02ec3a52008-12-07 16:44:47 +00001849 EmitEdgeClass(i, NodeB, Weight, OptDescs, O);
Mikhail Glushenkovd24c1292008-11-28 00:13:47 +00001850 ++i;
Mikhail Glushenkov46d4e972008-05-06 16:36:06 +00001851 }
1852}
1853
Mikhail Glushenkovbe46ae12008-05-07 21:50:19 +00001854/// EmitPopulateCompilationGraph - Emit the PopulateCompilationGraph()
1855/// function.
Mikhail Glushenkovd24c1292008-11-28 00:13:47 +00001856void EmitPopulateCompilationGraph (const RecordVector& EdgeVector,
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +00001857 const ToolDescriptions& ToolDescs,
Daniel Dunbard4287062009-07-03 00:10:29 +00001858 raw_ostream& O)
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001859{
Mikhail Glushenkov945522f2008-09-22 20:49:34 +00001860 O << "void PopulateCompilationGraphLocal(CompilationGraph& G) {\n";
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001861
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +00001862 for (ToolDescriptions::const_iterator B = ToolDescs.begin(),
1863 E = ToolDescs.end(); B != E; ++B)
Mikhail Glushenkov973b3a32008-11-17 17:29:42 +00001864 O << Indent1 << "G.insertNode(new " << (*B)->Name << "());\n";
Mikhail Glushenkov719c25812008-11-12 00:05:17 +00001865
Mikhail Glushenkov2cfd2232008-05-06 16:35:25 +00001866 O << '\n';
1867
Mikhail Glushenkov719c25812008-11-12 00:05:17 +00001868 // Insert edges.
1869
Mikhail Glushenkovd24c1292008-11-28 00:13:47 +00001870 int i = 0;
Mikhail Glushenkov02ec3a52008-12-07 16:44:47 +00001871 for (RecordVector::const_iterator B = EdgeVector.begin(),
1872 E = EdgeVector.end(); B != E; ++B) {
1873 const Record* Edge = *B;
1874 const std::string& NodeA = Edge->getValueAsString("a");
1875 const std::string& NodeB = Edge->getValueAsString("b");
Mikhail Glushenkovdedba642008-05-30 06:08:50 +00001876 DagInit* Weight = Edge->getValueAsDag("weight");
Mikhail Glushenkov761958d2008-05-06 16:36:50 +00001877
Mikhail Glushenkov02ec3a52008-12-07 16:44:47 +00001878 O << Indent1 << "G.insertEdge(\"" << NodeA << "\", ";
Mikhail Glushenkov761958d2008-05-06 16:36:50 +00001879
Mikhail Glushenkovdedba642008-05-30 06:08:50 +00001880 if (isDagEmpty(Weight))
Mikhail Glushenkov02ec3a52008-12-07 16:44:47 +00001881 O << "new SimpleEdge(\"" << NodeB << "\")";
Mikhail Glushenkov761958d2008-05-06 16:36:50 +00001882 else
1883 O << "new Edge" << i << "()";
1884
1885 O << ");\n";
Mikhail Glushenkovd24c1292008-11-28 00:13:47 +00001886 ++i;
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001887 }
1888
Mikhail Glushenkov64046a72008-12-11 10:34:18 +00001889 O << "}\n\n";
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001890}
1891
Mikhail Glushenkov793f63d2008-05-30 06:12:24 +00001892/// ExtractHookNames - Extract the hook names from all instances of
1893/// $CALL(HookName) in the provided command line string. Helper
1894/// function used by FillInHookNames().
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +00001895class ExtractHookNames {
Mikhail Glushenkovab0f3cb2009-01-21 13:04:00 +00001896 llvm::StringMap<unsigned>& HookNames_;
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +00001897public:
Mikhail Glushenkovab0f3cb2009-01-21 13:04:00 +00001898 ExtractHookNames(llvm::StringMap<unsigned>& HookNames)
1899 : HookNames_(HookNames) {}
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +00001900
1901 void operator()(const Init* CmdLine) {
1902 StrVector cmds;
Mikhail Glushenkovab0f3cb2009-01-21 13:04:00 +00001903 TokenizeCmdline(InitPtrToString(CmdLine), cmds);
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +00001904 for (StrVector::const_iterator B = cmds.begin(), E = cmds.end();
1905 B != E; ++B) {
1906 const std::string& cmd = *B;
Mikhail Glushenkovab0f3cb2009-01-21 13:04:00 +00001907
1908 if (cmd == "$CALL") {
1909 unsigned NumArgs = 0;
1910 checkedIncrement(B, E, "Syntax error in $CALL invocation!");
1911 const std::string& HookName = *B;
1912
1913
1914 if (HookName.at(0) == ')')
1915 throw "$CALL invoked with no arguments!";
1916
1917 while (++B != E && B->at(0) != ')') {
1918 ++NumArgs;
1919 }
1920
1921 StringMap<unsigned>::const_iterator H = HookNames_.find(HookName);
1922
1923 if (H != HookNames_.end() && H->second != NumArgs)
1924 throw "Overloading of hooks is not allowed. Overloaded hook: "
1925 + HookName;
1926 else
1927 HookNames_[HookName] = NumArgs;
1928
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +00001929 }
Mikhail Glushenkov793f63d2008-05-30 06:12:24 +00001930 }
1931 }
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +00001932};
Mikhail Glushenkovb24c8b22008-05-30 06:22:15 +00001933
Mikhail Glushenkov793f63d2008-05-30 06:12:24 +00001934/// FillInHookNames - Actually extract the hook names from all command
1935/// line strings. Helper function used by EmitHookDeclarations().
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +00001936void FillInHookNames(const ToolDescriptions& ToolDescs,
Mikhail Glushenkovab0f3cb2009-01-21 13:04:00 +00001937 llvm::StringMap<unsigned>& HookNames)
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +00001938{
Mikhail Glushenkovb24c8b22008-05-30 06:22:15 +00001939 // For all command lines:
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +00001940 for (ToolDescriptions::const_iterator B = ToolDescs.begin(),
1941 E = ToolDescs.end(); B != E; ++B) {
1942 const ToolDescription& D = *(*B);
1943 if (!D.CmdLine)
Mikhail Glushenkov793f63d2008-05-30 06:12:24 +00001944 continue;
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +00001945 if (dynamic_cast<StringInit*>(D.CmdLine))
Mikhail Glushenkov793f63d2008-05-30 06:12:24 +00001946 // This is a string.
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +00001947 ExtractHookNames(HookNames).operator()(D.CmdLine);
Mikhail Glushenkovb24c8b22008-05-30 06:22:15 +00001948 else
Mikhail Glushenkov793f63d2008-05-30 06:12:24 +00001949 // This is a 'case' construct.
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +00001950 WalkCase(D.CmdLine, Id(), ExtractHookNames(HookNames));
Mikhail Glushenkov793f63d2008-05-30 06:12:24 +00001951 }
1952}
1953
1954/// EmitHookDeclarations - Parse CmdLine fields of all the tool
1955/// property records and emit hook function declaration for each
1956/// instance of $CALL(HookName).
Daniel Dunbard4287062009-07-03 00:10:29 +00001957void EmitHookDeclarations(const ToolDescriptions& ToolDescs, raw_ostream& O) {
Mikhail Glushenkovab0f3cb2009-01-21 13:04:00 +00001958 llvm::StringMap<unsigned> HookNames;
1959
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +00001960 FillInHookNames(ToolDescs, HookNames);
Mikhail Glushenkov793f63d2008-05-30 06:12:24 +00001961 if (HookNames.empty())
1962 return;
Mikhail Glushenkov793f63d2008-05-30 06:12:24 +00001963
1964 O << "namespace hooks {\n";
Mikhail Glushenkovab0f3cb2009-01-21 13:04:00 +00001965 for (StringMap<unsigned>::const_iterator B = HookNames.begin(),
1966 E = HookNames.end(); B != E; ++B) {
Mikhail Glushenkoved765fe2009-01-21 13:04:33 +00001967 O << Indent1 << "std::string " << B->first() << "(";
Mikhail Glushenkov793f63d2008-05-30 06:12:24 +00001968
Mikhail Glushenkovab0f3cb2009-01-21 13:04:00 +00001969 for (unsigned i = 0, j = B->second; i < j; ++i) {
1970 O << "const char* Arg" << i << (i+1 == j ? "" : ", ");
1971 }
1972
1973 O <<");\n";
1974 }
Mikhail Glushenkov793f63d2008-05-30 06:12:24 +00001975 O << "}\n\n";
1976}
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001977
Mikhail Glushenkov945522f2008-09-22 20:49:34 +00001978/// EmitRegisterPlugin - Emit code to register this plugin.
Daniel Dunbard4287062009-07-03 00:10:29 +00001979void EmitRegisterPlugin(int Priority, raw_ostream& O) {
Mikhail Glushenkov64046a72008-12-11 10:34:18 +00001980 O << "struct Plugin : public llvmc::BasePlugin {\n\n"
Mikhail Glushenkoveb71ecf2008-11-17 17:30:25 +00001981 << Indent1 << "int Priority() const { return " << Priority << "; }\n\n"
Mikhail Glushenkov945522f2008-09-22 20:49:34 +00001982 << Indent1 << "void PopulateLanguageMap(LanguageMap& langMap) const\n"
1983 << Indent1 << "{ PopulateLanguageMapLocal(langMap); }\n\n"
1984 << Indent1
1985 << "void PopulateCompilationGraph(CompilationGraph& graph) const\n"
1986 << Indent1 << "{ PopulateCompilationGraphLocal(graph); }\n"
1987 << "};\n\n"
1988
Mikhail Glushenkov64046a72008-12-11 10:34:18 +00001989 << "static llvmc::RegisterPlugin<Plugin> RP;\n\n";
Mikhail Glushenkov945522f2008-09-22 20:49:34 +00001990}
1991
Mikhail Glushenkovb4890702008-11-12 12:41:18 +00001992/// EmitIncludes - Emit necessary #include directives and some
1993/// additional declarations.
Daniel Dunbard4287062009-07-03 00:10:29 +00001994void EmitIncludes(raw_ostream& O) {
Mikhail Glushenkov62ab3112008-09-22 20:50:40 +00001995 O << "#include \"llvm/CompilerDriver/CompilationGraph.h\"\n"
Mikhail Glushenkovd500a272009-06-23 20:46:48 +00001996 << "#include \"llvm/CompilerDriver/ForceLinkageMacros.h\"\n"
Mikhail Glushenkov62ab3112008-09-22 20:50:40 +00001997 << "#include \"llvm/CompilerDriver/Plugin.h\"\n"
1998 << "#include \"llvm/CompilerDriver/Tool.h\"\n\n"
Mikhail Glushenkov945522f2008-09-22 20:49:34 +00001999
2000 << "#include \"llvm/ADT/StringExtras.h\"\n"
2001 << "#include \"llvm/Support/CommandLine.h\"\n\n"
2002
2003 << "#include <cstdlib>\n"
2004 << "#include <stdexcept>\n\n"
2005
2006 << "using namespace llvm;\n"
2007 << "using namespace llvmc;\n\n"
2008
Mikhail Glushenkovb4890702008-11-12 12:41:18 +00002009 << "extern cl::opt<std::string> OutputFilename;\n\n"
2010
2011 << "inline const char* checkCString(const char* s)\n"
2012 << "{ return s == NULL ? \"\" : s; }\n\n";
Mikhail Glushenkov945522f2008-09-22 20:49:34 +00002013}
2014
Mikhail Glushenkov973b3a32008-11-17 17:29:42 +00002015
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +00002016/// PluginData - Holds all information about a plugin.
2017struct PluginData {
2018 OptionDescriptions OptDescs;
2019 bool HasSink;
Mikhail Glushenkov9111ba22008-12-07 16:42:47 +00002020 bool HasExterns;
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +00002021 ToolDescriptions ToolDescs;
2022 RecordVector Edges;
2023 int Priority;
Mikhail Glushenkov973b3a32008-11-17 17:29:42 +00002024};
2025
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +00002026/// HasSink - Go through the list of tool descriptions and check if
Mikhail Glushenkov9111ba22008-12-07 16:42:47 +00002027/// there are any with the 'sink' property set.
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +00002028bool HasSink(const ToolDescriptions& ToolDescs) {
2029 for (ToolDescriptions::const_iterator B = ToolDescs.begin(),
2030 E = ToolDescs.end(); B != E; ++B)
2031 if ((*B)->isSink())
2032 return true;
Mikhail Glushenkov973b3a32008-11-17 17:29:42 +00002033
Mikhail Glushenkov9111ba22008-12-07 16:42:47 +00002034 return false;
2035}
2036
2037/// HasExterns - Go through the list of option descriptions and check
2038/// if there are any external options.
2039bool HasExterns(const OptionDescriptions& OptDescs) {
2040 for (OptionDescriptions::const_iterator B = OptDescs.begin(),
2041 E = OptDescs.end(); B != E; ++B)
2042 if (B->second.isExtern())
2043 return true;
2044
2045 return false;
Mikhail Glushenkov973b3a32008-11-17 17:29:42 +00002046}
2047
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +00002048/// CollectPluginData - Collect tool and option properties,
2049/// compilation graph edges and plugin priority from the parse tree.
2050void CollectPluginData (const RecordKeeper& Records, PluginData& Data) {
2051 // Collect option properties.
2052 const RecordVector& OptionLists =
2053 Records.getAllDerivedDefinitions("OptionList");
2054 CollectOptionDescriptions(OptionLists.begin(), OptionLists.end(),
2055 Data.OptDescs);
2056
2057 // Collect tool properties.
2058 const RecordVector& Tools = Records.getAllDerivedDefinitions("Tool");
2059 CollectToolDescriptions(Tools.begin(), Tools.end(), Data.ToolDescs);
2060 Data.HasSink = HasSink(Data.ToolDescs);
Mikhail Glushenkov9111ba22008-12-07 16:42:47 +00002061 Data.HasExterns = HasExterns(Data.OptDescs);
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +00002062
2063 // Collect compilation graph edges.
2064 const RecordVector& CompilationGraphs =
2065 Records.getAllDerivedDefinitions("CompilationGraph");
2066 FillInEdgeVector(CompilationGraphs.begin(), CompilationGraphs.end(),
2067 Data.Edges);
2068
2069 // Calculate the priority of this plugin.
2070 const RecordVector& Priorities =
2071 Records.getAllDerivedDefinitions("PluginPriority");
2072 Data.Priority = CalculatePriority(Priorities.begin(), Priorities.end());
Mikhail Glushenkoveb71ecf2008-11-17 17:30:25 +00002073}
2074
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +00002075/// CheckPluginData - Perform some sanity checks on the collected data.
2076void CheckPluginData(PluginData& Data) {
2077 // Filter out all tools not mentioned in the compilation graph.
2078 FilterNotInGraph(Data.Edges, Data.ToolDescs);
Mikhail Glushenkovd24c1292008-11-28 00:13:47 +00002079
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +00002080 // Typecheck the compilation graph.
2081 TypecheckGraph(Data.Edges, Data.ToolDescs);
2082
2083 // Check that there are no options without side effects (specified
2084 // only in the OptionList).
2085 CheckForSuperfluousOptions(Data.Edges, Data.ToolDescs, Data.OptDescs);
2086
Mikhail Glushenkovd24c1292008-11-28 00:13:47 +00002087}
2088
Daniel Dunbard4287062009-07-03 00:10:29 +00002089void EmitPluginCode(const PluginData& Data, raw_ostream& O) {
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +00002090 // Emit file header.
2091 EmitIncludes(O);
2092
2093 // Emit global option registration code.
Mikhail Glushenkov087aebe2009-06-23 20:45:07 +00002094 EmitOptionDefinitions(Data.OptDescs, Data.HasSink, Data.HasExterns, O);
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +00002095
2096 // Emit hook declarations.
2097 EmitHookDeclarations(Data.ToolDescs, O);
2098
Mikhail Glushenkov64046a72008-12-11 10:34:18 +00002099 O << "namespace {\n\n";
2100
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +00002101 // Emit PopulateLanguageMap() function
2102 // (a language map maps from file extensions to language names).
2103 EmitPopulateLanguageMap(Records, O);
2104
2105 // Emit Tool classes.
2106 for (ToolDescriptions::const_iterator B = Data.ToolDescs.begin(),
2107 E = Data.ToolDescs.end(); B!=E; ++B)
2108 EmitToolClassDefinition(*(*B), Data.OptDescs, O);
2109
2110 // Emit Edge# classes.
2111 EmitEdgeClasses(Data.Edges, Data.OptDescs, O);
2112
2113 // Emit PopulateCompilationGraph() function.
2114 EmitPopulateCompilationGraph(Data.Edges, Data.ToolDescs, O);
2115
2116 // Emit code for plugin registration.
2117 EmitRegisterPlugin(Data.Priority, O);
2118
Mikhail Glushenkovd500a272009-06-23 20:46:48 +00002119 O << "} // End anonymous namespace.\n\n";
2120
2121 // Force linkage magic.
2122 O << "namespace llvmc {\n";
2123 O << "LLVMC_FORCE_LINKAGE_DECL(LLVMC_PLUGIN_NAME) {}\n";
2124 O << "}\n";
2125
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +00002126 // EOF
2127}
2128
2129
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00002130// End of anonymous namespace
Mikhail Glushenkovc1f738d2008-05-06 18:12:03 +00002131}
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00002132
Mikhail Glushenkovbe46ae12008-05-07 21:50:19 +00002133/// run - The back-end entry point.
Daniel Dunbard4287062009-07-03 00:10:29 +00002134void LLVMCConfigurationEmitter::run (raw_ostream &O) {
Mikhail Glushenkovffe736e2008-05-30 06:21:48 +00002135 try {
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +00002136 PluginData Data;
Mikhail Glushenkovbe46ae12008-05-07 21:50:19 +00002137
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +00002138 CollectPluginData(Records, Data);
2139 CheckPluginData(Data);
2140
Mikhail Glushenkov34307a92008-05-06 18:08:59 +00002141 EmitSourceFileHeader("LLVMC Configuration Library", O);
Mikhail Glushenkov4840b4c2008-12-07 16:41:11 +00002142 EmitPluginCode(Data, O);
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00002143
Mikhail Glushenkovffe736e2008-05-30 06:21:48 +00002144 } catch (std::exception& Error) {
2145 throw Error.what() + std::string(" - usually this means a syntax error.");
2146 }
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00002147}