blob: a3b54a9055994401e3d33c60fcb82623b164c340 [file] [log] [blame]
Mikhail Glushenkovfb37f392008-05-30 06:20:54 +00001//===- LLVMCConfigurationEmitter.cpp - Generate LLVMC config ----*- C++ -*-===//
Anton Korobeynikovac67b7e2008-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 Glushenkovbe9d9a12008-05-06 18:08:59 +000010// This tablegen backend is responsible for emitting LLVMC configuration code.
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +000011//
12//===----------------------------------------------------------------------===//
13
Mikhail Glushenkovecbdcf22008-05-06 18:09:29 +000014#include "LLVMCConfigurationEmitter.h"
Anton Korobeynikovac67b7e2008-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 Glushenkovffcf3a12008-05-30 06:18:16 +000021#include "llvm/ADT/StringSet.h"
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +000022#include <algorithm>
23#include <cassert>
24#include <functional>
Mikhail Glushenkov4fb71ea2008-05-30 06:21:48 +000025#include <stdexcept>
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +000026#include <string>
Chris Lattner32a9e7a2008-06-04 04:46:14 +000027#include <typeinfo>
Mikhail Glushenkovaa4774c2008-11-12 00:04:46 +000028
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +000029using namespace llvm;
30
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +000031
32//===----------------------------------------------------------------------===//
33/// Typedefs
34
35typedef std::vector<Record*> RecordVector;
36typedef std::vector<std::string> StrVector;
37
38//===----------------------------------------------------------------------===//
39/// Constants
40
Mikhail Glushenkovf8349ac2009-09-21 15:53:44 +000041// Indentation.
Chris Lattnerec8e1b72009-11-03 18:30:31 +000042static const unsigned TabWidth = 4;
43static const unsigned Indent1 = TabWidth*1;
44static const unsigned Indent2 = TabWidth*2;
45static const unsigned Indent3 = TabWidth*3;
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +000046
Mikhail Glushenkov4561ab52008-05-07 21:50:19 +000047// Default help string.
Chris Lattnerec8e1b72009-11-03 18:30:31 +000048static const char * const DefaultHelpString = "NO HELP MESSAGE PROVIDED";
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +000049
Mikhail Glushenkov4561ab52008-05-07 21:50:19 +000050// Name for the "sink" option.
Chris Lattnerec8e1b72009-11-03 18:30:31 +000051static const char * const SinkOptionName = "AutoGeneratedSinkOption";
52
53namespace {
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +000054
55//===----------------------------------------------------------------------===//
56/// Helper functions
57
Mikhail Glushenkovf9152532008-12-07 16:41:11 +000058/// Id - An 'identity' function object.
59struct Id {
Mikhail Glushenkov4d21ae72009-10-18 22:51:30 +000060 template<typename T0>
61 void operator()(const T0&) const {
62 }
63 template<typename T0, typename T1>
64 void operator()(const T0&, const T1&) const {
65 }
66 template<typename T0, typename T1, typename T2>
67 void operator()(const T0&, const T1&, const T2&) const {
Mikhail Glushenkovf9152532008-12-07 16:41:11 +000068 }
69};
70
Mikhail Glushenkovb5ccfbf2008-05-30 06:10:19 +000071int InitPtrToInt(const Init* ptr) {
72 const IntInit& val = dynamic_cast<const IntInit&>(*ptr);
Mikhail Glushenkov29063552008-05-06 18:18:20 +000073 return val.getValue();
74}
75
Mikhail Glushenkovffcf3a12008-05-30 06:18:16 +000076const std::string& InitPtrToString(const Init* ptr) {
77 const StringInit& val = dynamic_cast<const StringInit&>(*ptr);
78 return val.getValue();
79}
80
81const ListInit& InitPtrToList(const Init* ptr) {
82 const ListInit& val = dynamic_cast<const ListInit&>(*ptr);
83 return val;
84}
85
86const DagInit& InitPtrToDag(const Init* ptr) {
Mikhail Glushenkovb5ccfbf2008-05-30 06:10:19 +000087 const DagInit& val = dynamic_cast<const DagInit&>(*ptr);
Mikhail Glushenkov29063552008-05-06 18:18:20 +000088 return val;
89}
90
Mikhail Glushenkov4d21ae72009-10-18 22:51:30 +000091const std::string GetOperatorName(const DagInit* D) {
92 return D->getOperator()->getAsString();
93}
94
95const std::string GetOperatorName(const DagInit& D) {
96 return GetOperatorName(&D);
97}
98
Mikhail Glushenkov4561ab52008-05-07 21:50:19 +000099// checkNumberOfArguments - Ensure that the number of args in d is
Mikhail Glushenkovb7970002009-07-07 16:07:36 +0000100// greater than or equal to min_arguments, otherwise throw an exception.
Mikhail Glushenkov581936a2008-05-06 17:22:03 +0000101void checkNumberOfArguments (const DagInit* d, unsigned min_arguments) {
Mikhail Glushenkovb4ced5a2008-12-07 16:47:12 +0000102 if (!d || d->getNumArgs() < min_arguments)
Mikhail Glushenkov4d21ae72009-10-18 22:51:30 +0000103 throw GetOperatorName(d) + ": too few arguments!";
Mikhail Glushenkov581936a2008-05-06 17:22:03 +0000104}
105
Mikhail Glushenkove5557f42008-05-30 06:08:50 +0000106// isDagEmpty - is this DAG marked with an empty marker?
107bool isDagEmpty (const DagInit* d) {
Mikhail Glushenkov4d21ae72009-10-18 22:51:30 +0000108 return GetOperatorName(d) == "empty_dag_marker";
Mikhail Glushenkove5557f42008-05-30 06:08:50 +0000109}
Mikhail Glushenkov581936a2008-05-06 17:22:03 +0000110
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000111// EscapeVariableName - Escape commas and other symbols not allowed
112// in the C++ variable names. Makes it possible to use options named
113// like "Wa," (useful for prefix options).
114std::string EscapeVariableName(const std::string& Var) {
115 std::string ret;
116 for (unsigned i = 0; i != Var.size(); ++i) {
117 char cur_char = Var[i];
118 if (cur_char == ',') {
119 ret += "_comma_";
120 }
121 else if (cur_char == '+') {
122 ret += "_plus_";
123 }
124 else if (cur_char == '-') {
125 ret += "_dash_";
126 }
127 else {
128 ret.push_back(cur_char);
129 }
130 }
131 return ret;
132}
133
Mikhail Glushenkova298bb72009-01-21 13:04:00 +0000134/// oneOf - Does the input string contain this character?
135bool oneOf(const char* lst, char c) {
136 while (*lst) {
137 if (*lst++ == c)
138 return true;
139 }
140 return false;
141}
142
Mikhail Glushenkov19d3e822009-01-28 03:47:20 +0000143template <class I, class S>
144void checkedIncrement(I& P, I E, S ErrorString) {
145 ++P;
146 if (P == E)
147 throw ErrorString;
148}
149
Mikhail Glushenkov4858a1d2009-10-21 02:13:13 +0000150// apply is needed because C++'s syntax doesn't let us construct a function
151// object and call it in the same statement.
152template<typename F, typename T0>
153void apply(F Fun, T0& Arg0) {
154 return Fun(Arg0);
155}
156
157template<typename F, typename T0, typename T1>
158void apply(F Fun, T0& Arg0, T1& Arg1) {
159 return Fun(Arg0, Arg1);
160}
161
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +0000162//===----------------------------------------------------------------------===//
163/// Back-end specific code
164
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +0000165
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000166/// OptionType - One of six different option types. See the
167/// documentation for detailed description of differences.
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +0000168namespace OptionType {
Mikhail Glushenkovcbc360d2009-07-07 16:08:11 +0000169
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000170 enum OptionType { Alias, Switch, Parameter, ParameterList,
Mikhail Glushenkovb4ced5a2008-12-07 16:47:12 +0000171 Prefix, PrefixList};
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000172
Mikhail Glushenkov4858a1d2009-10-21 02:13:13 +0000173 bool IsAlias(OptionType t) {
174 return (t == Alias);
175 }
176
Mikhail Glushenkovcbc360d2009-07-07 16:08:11 +0000177 bool IsList (OptionType t) {
178 return (t == ParameterList || t == PrefixList);
179 }
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +0000180
Mikhail Glushenkovcbc360d2009-07-07 16:08:11 +0000181 bool IsSwitch (OptionType t) {
182 return (t == Switch);
183 }
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +0000184
Mikhail Glushenkovcbc360d2009-07-07 16:08:11 +0000185 bool IsParameter (OptionType t) {
186 return (t == Parameter || t == Prefix);
187 }
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +0000188
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000189}
190
191OptionType::OptionType stringToOptionType(const std::string& T) {
192 if (T == "alias_option")
193 return OptionType::Alias;
194 else if (T == "switch_option")
195 return OptionType::Switch;
196 else if (T == "parameter_option")
197 return OptionType::Parameter;
198 else if (T == "parameter_list_option")
199 return OptionType::ParameterList;
200 else if (T == "prefix_option")
201 return OptionType::Prefix;
202 else if (T == "prefix_list_option")
203 return OptionType::PrefixList;
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000204 else
205 throw "Unknown option type: " + T + '!';
206}
207
208namespace OptionDescriptionFlags {
209 enum OptionDescriptionFlags { Required = 0x1, Hidden = 0x2,
Mikhail Glushenkov19d3e822009-01-28 03:47:20 +0000210 ReallyHidden = 0x4, Extern = 0x8,
211 OneOrMore = 0x10, ZeroOrOne = 0x20 };
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000212}
213
214/// OptionDescription - Represents data contained in a single
215/// OptionList entry.
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +0000216struct OptionDescription {
217 OptionType::OptionType Type;
218 std::string Name;
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000219 unsigned Flags;
220 std::string Help;
Mikhail Glushenkov19d3e822009-01-28 03:47:20 +0000221 unsigned MultiVal;
Mikhail Glushenkov8fe44472009-07-07 16:08:41 +0000222 Init* InitVal;
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +0000223
224 OptionDescription(OptionType::OptionType t = OptionType::Switch,
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000225 const std::string& n = "",
226 const std::string& h = DefaultHelpString)
Mikhail Glushenkov8fe44472009-07-07 16:08:41 +0000227 : Type(t), Name(n), Flags(0x0), Help(h), MultiVal(1), InitVal(0)
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +0000228 {}
229
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000230 /// GenTypeDeclaration - Returns the C++ variable type of this
231 /// option.
232 const char* GenTypeDeclaration() const;
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +0000233
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000234 /// GenVariableName - Returns the variable name used in the
235 /// generated C++ code.
236 std::string GenVariableName() const;
Mikhail Glushenkov739c7202008-11-28 00:13:25 +0000237
Mikhail Glushenkov4561ab52008-05-07 21:50:19 +0000238 /// Merge - Merge two option descriptions.
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000239 void Merge (const OptionDescription& other);
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +0000240
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000241 // Misc convenient getters/setters.
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +0000242
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000243 bool isAlias() const;
Mikhail Glushenkovb4ced5a2008-12-07 16:47:12 +0000244
Mikhail Glushenkov19d3e822009-01-28 03:47:20 +0000245 bool isMultiVal() const;
246
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000247 bool isExtern() const;
Mikhail Glushenkovb4ced5a2008-12-07 16:47:12 +0000248 void setExtern();
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000249
250 bool isRequired() const;
251 void setRequired();
252
Mikhail Glushenkov19d3e822009-01-28 03:47:20 +0000253 bool isOneOrMore() const;
254 void setOneOrMore();
255
256 bool isZeroOrOne() const;
257 void setZeroOrOne();
258
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000259 bool isHidden() const;
260 void setHidden();
261
262 bool isReallyHidden() const;
263 void setReallyHidden();
Mikhail Glushenkov19d3e822009-01-28 03:47:20 +0000264
Mikhail Glushenkovcbc360d2009-07-07 16:08:11 +0000265 bool isSwitch() const
266 { return OptionType::IsSwitch(this->Type); }
267
Mikhail Glushenkov4858a1d2009-10-21 02:13:13 +0000268 bool isParameter() const
269 { return OptionType::IsParameter(this->Type); }
270
Mikhail Glushenkovcbc360d2009-07-07 16:08:11 +0000271 bool isList() const
272 { return OptionType::IsList(this->Type); }
273
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +0000274};
275
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000276void OptionDescription::Merge (const OptionDescription& other)
277{
278 if (other.Type != Type)
279 throw "Conflicting definitions for the option " + Name + "!";
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +0000280
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000281 if (Help == other.Help || Help == DefaultHelpString)
282 Help = other.Help;
283 else if (other.Help != DefaultHelpString) {
Daniel Dunbar1a551802009-07-03 00:10:29 +0000284 llvm::errs() << "Warning: several different help strings"
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000285 " defined for option " + Name + "\n";
286 }
287
288 Flags |= other.Flags;
289}
290
291bool OptionDescription::isAlias() const {
Mikhail Glushenkov4858a1d2009-10-21 02:13:13 +0000292 return OptionType::IsAlias(this->Type);
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000293}
294
Mikhail Glushenkov19d3e822009-01-28 03:47:20 +0000295bool OptionDescription::isMultiVal() const {
Mikhail Glushenkov57cd67f2009-01-28 03:47:58 +0000296 return MultiVal > 1;
Mikhail Glushenkov19d3e822009-01-28 03:47:20 +0000297}
298
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000299bool OptionDescription::isExtern() const {
Mikhail Glushenkovb4ced5a2008-12-07 16:47:12 +0000300 return Flags & OptionDescriptionFlags::Extern;
301}
302void OptionDescription::setExtern() {
303 Flags |= OptionDescriptionFlags::Extern;
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000304}
305
306bool OptionDescription::isRequired() const {
307 return Flags & OptionDescriptionFlags::Required;
308}
309void OptionDescription::setRequired() {
310 Flags |= OptionDescriptionFlags::Required;
311}
312
Mikhail Glushenkov19d3e822009-01-28 03:47:20 +0000313bool OptionDescription::isOneOrMore() const {
314 return Flags & OptionDescriptionFlags::OneOrMore;
315}
316void OptionDescription::setOneOrMore() {
317 Flags |= OptionDescriptionFlags::OneOrMore;
318}
319
320bool OptionDescription::isZeroOrOne() const {
321 return Flags & OptionDescriptionFlags::ZeroOrOne;
322}
323void OptionDescription::setZeroOrOne() {
324 Flags |= OptionDescriptionFlags::ZeroOrOne;
325}
326
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000327bool OptionDescription::isHidden() const {
328 return Flags & OptionDescriptionFlags::Hidden;
329}
330void OptionDescription::setHidden() {
331 Flags |= OptionDescriptionFlags::Hidden;
332}
333
334bool OptionDescription::isReallyHidden() const {
335 return Flags & OptionDescriptionFlags::ReallyHidden;
336}
337void OptionDescription::setReallyHidden() {
338 Flags |= OptionDescriptionFlags::ReallyHidden;
339}
340
341const char* OptionDescription::GenTypeDeclaration() const {
342 switch (Type) {
343 case OptionType::Alias:
344 return "cl::alias";
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000345 case OptionType::PrefixList:
346 case OptionType::ParameterList:
347 return "cl::list<std::string>";
348 case OptionType::Switch:
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000349 return "cl::opt<bool>";
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000350 case OptionType::Parameter:
351 case OptionType::Prefix:
352 default:
353 return "cl::opt<std::string>";
354 }
355}
356
357std::string OptionDescription::GenVariableName() const {
358 const std::string& EscapedName = EscapeVariableName(Name);
359 switch (Type) {
360 case OptionType::Alias:
361 return "AutoGeneratedAlias_" + EscapedName;
362 case OptionType::PrefixList:
363 case OptionType::ParameterList:
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000364 return "AutoGeneratedList_" + EscapedName;
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000365 case OptionType::Switch:
366 return "AutoGeneratedSwitch_" + EscapedName;
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000367 case OptionType::Prefix:
368 case OptionType::Parameter:
369 default:
370 return "AutoGeneratedParameter_" + EscapedName;
371 }
372}
373
374/// OptionDescriptions - An OptionDescription array plus some helper
375/// functions.
376class OptionDescriptions {
377 typedef StringMap<OptionDescription> container_type;
378
379 /// Descriptions - A list of OptionDescriptions.
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +0000380 container_type Descriptions;
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +0000381
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000382public:
Mikhail Glushenkova7d0ae32008-05-30 06:28:37 +0000383 /// FindOption - exception-throwing wrapper for find().
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000384 const OptionDescription& FindOption(const std::string& OptName) const;
Mikhail Glushenkov4858a1d2009-10-21 02:13:13 +0000385
386 // Wrappers for FindOption that throw an exception in case the option has a
387 // wrong type.
Mikhail Glushenkov0a22fb62009-10-17 20:09:29 +0000388 const OptionDescription& FindSwitch(const std::string& OptName) const;
Mikhail Glushenkov4858a1d2009-10-21 02:13:13 +0000389 const OptionDescription& FindParameter(const std::string& OptName) const;
390 const OptionDescription& FindList(const std::string& OptName) const;
391 const OptionDescription&
392 FindListOrParameter(const std::string& OptName) const;
Mikhail Glushenkov581936a2008-05-06 17:22:03 +0000393
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000394 /// insertDescription - Insert new OptionDescription into
395 /// OptionDescriptions list
396 void InsertDescription (const OptionDescription& o);
Mikhail Glushenkov09b51c32008-05-30 06:27:02 +0000397
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +0000398 // Support for STL-style iteration
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000399 typedef container_type::const_iterator const_iterator;
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +0000400 const_iterator begin() const { return Descriptions.begin(); }
401 const_iterator end() const { return Descriptions.end(); }
402};
403
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000404const OptionDescription&
Mikhail Glushenkov4858a1d2009-10-21 02:13:13 +0000405OptionDescriptions::FindOption(const std::string& OptName) const {
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000406 const_iterator I = Descriptions.find(OptName);
407 if (I != Descriptions.end())
408 return I->second;
409 else
410 throw OptName + ": no such option!";
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +0000411}
412
Mikhail Glushenkov0a22fb62009-10-17 20:09:29 +0000413const OptionDescription&
Mikhail Glushenkov4858a1d2009-10-21 02:13:13 +0000414OptionDescriptions::FindSwitch(const std::string& OptName) const {
Mikhail Glushenkov0a22fb62009-10-17 20:09:29 +0000415 const OptionDescription& OptDesc = this->FindOption(OptName);
416 if (!OptDesc.isSwitch())
417 throw OptName + ": incorrect option type - should be a switch!";
418 return OptDesc;
419}
420
Mikhail Glushenkov4858a1d2009-10-21 02:13:13 +0000421const OptionDescription&
422OptionDescriptions::FindList(const std::string& OptName) const {
423 const OptionDescription& OptDesc = this->FindOption(OptName);
424 if (!OptDesc.isList())
425 throw OptName + ": incorrect option type - should be a list!";
426 return OptDesc;
427}
428
429const OptionDescription&
430OptionDescriptions::FindParameter(const std::string& OptName) const {
431 const OptionDescription& OptDesc = this->FindOption(OptName);
432 if (!OptDesc.isParameter())
433 throw OptName + ": incorrect option type - should be a parameter!";
434 return OptDesc;
435}
436
437const OptionDescription&
438OptionDescriptions::FindListOrParameter(const std::string& OptName) const {
439 const OptionDescription& OptDesc = this->FindOption(OptName);
440 if (!OptDesc.isList() && !OptDesc.isParameter())
441 throw OptName
442 + ": incorrect option type - should be a list or parameter!";
443 return OptDesc;
444}
445
446void OptionDescriptions::InsertDescription (const OptionDescription& o) {
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000447 container_type::iterator I = Descriptions.find(o.Name);
448 if (I != Descriptions.end()) {
449 OptionDescription& D = I->second;
450 D.Merge(o);
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +0000451 }
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000452 else {
453 Descriptions[o.Name] = o;
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +0000454 }
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +0000455}
456
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000457/// HandlerTable - A base class for function objects implemented as
458/// 'tables of handlers'.
Mikhail Glushenkov632eb202009-12-07 10:51:55 +0000459template <typename Handler>
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000460class HandlerTable {
461protected:
Mikhail Glushenkov09b51c32008-05-30 06:27:02 +0000462 // Implementation details.
463
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000464 /// HandlerMap - A map from property names to property handlers
465 typedef StringMap<Handler> HandlerMap;
Mikhail Glushenkov09b51c32008-05-30 06:27:02 +0000466
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000467 static HandlerMap Handlers_;
Mikhail Glushenkov09b51c32008-05-30 06:27:02 +0000468 static bool staticMembersInitialized_;
469
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000470public:
Mikhail Glushenkov09b51c32008-05-30 06:27:02 +0000471
Mikhail Glushenkov632eb202009-12-07 10:51:55 +0000472 Handler GetHandler (const std::string& HandlerName) const {
473 typename HandlerMap::iterator method = Handlers_.find(HandlerName);
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000474
475 if (method != Handlers_.end()) {
476 Handler h = method->second;
Mikhail Glushenkov632eb202009-12-07 10:51:55 +0000477 return h;
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000478 }
479 else {
Mikhail Glushenkov632eb202009-12-07 10:51:55 +0000480 throw "No handler found for property " + HandlerName + "!";
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000481 }
482 }
483
Mikhail Glushenkov632eb202009-12-07 10:51:55 +0000484 void AddHandler(const char* Property, Handler H) {
485 Handlers_[Property] = H;
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000486 }
Mikhail Glushenkov632eb202009-12-07 10:51:55 +0000487
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000488};
489
Mikhail Glushenkov632eb202009-12-07 10:51:55 +0000490template <class FunctionObject>
491void InvokeDagInitHandler(FunctionObject* Obj, Init* i) {
492 typedef void (FunctionObject::*Handler) (const DagInit*);
493
494 const DagInit& property = InitPtrToDag(i);
495 const std::string& property_name = GetOperatorName(property);
496 Handler h = Obj->GetHandler(property_name);
497
498 ((Obj)->*(h))(&property);
499}
500
501template <typename H>
502typename HandlerTable<H>::HandlerMap HandlerTable<H>::Handlers_;
503
504template <typename H>
505bool HandlerTable<H>::staticMembersInitialized_ = false;
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000506
507
508/// CollectOptionProperties - Function object for iterating over an
509/// option property list.
Mikhail Glushenkov632eb202009-12-07 10:51:55 +0000510class CollectOptionProperties;
511typedef void (CollectOptionProperties::* CollectOptionPropertiesHandler)
512(const DagInit*);
513
514class CollectOptionProperties
515: public HandlerTable<CollectOptionPropertiesHandler>
516{
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000517private:
518
519 /// optDescs_ - OptionDescriptions table. This is where the
520 /// information is stored.
521 OptionDescription& optDesc_;
Mikhail Glushenkov09b51c32008-05-30 06:27:02 +0000522
523public:
524
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000525 explicit CollectOptionProperties(OptionDescription& OD)
Mikhail Glushenkov632eb202009-12-07 10:51:55 +0000526 : optDesc_(OD)
Mikhail Glushenkov09b51c32008-05-30 06:27:02 +0000527 {
528 if (!staticMembersInitialized_) {
Mikhail Glushenkovb4ced5a2008-12-07 16:47:12 +0000529 AddHandler("extern", &CollectOptionProperties::onExtern);
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000530 AddHandler("help", &CollectOptionProperties::onHelp);
531 AddHandler("hidden", &CollectOptionProperties::onHidden);
Mikhail Glushenkov8fe44472009-07-07 16:08:41 +0000532 AddHandler("init", &CollectOptionProperties::onInit);
Mikhail Glushenkov19d3e822009-01-28 03:47:20 +0000533 AddHandler("multi_val", &CollectOptionProperties::onMultiVal);
534 AddHandler("one_or_more", &CollectOptionProperties::onOneOrMore);
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000535 AddHandler("really_hidden", &CollectOptionProperties::onReallyHidden);
536 AddHandler("required", &CollectOptionProperties::onRequired);
Mikhail Glushenkov19d3e822009-01-28 03:47:20 +0000537 AddHandler("zero_or_one", &CollectOptionProperties::onZeroOrOne);
Mikhail Glushenkov09b51c32008-05-30 06:27:02 +0000538
539 staticMembersInitialized_ = true;
540 }
541 }
542
Mikhail Glushenkov632eb202009-12-07 10:51:55 +0000543 /// operator() - Just forwards to the corresponding property
544 /// handler.
545 void operator() (Init* i) {
546 InvokeDagInitHandler(this, i);
547 }
548
Mikhail Glushenkov09b51c32008-05-30 06:27:02 +0000549private:
550
551 /// Option property handlers --
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000552 /// Methods that handle option properties such as (help) or (hidden).
Mikhail Glushenkovfdee9542008-09-22 20:46:19 +0000553
Mikhail Glushenkovb4ced5a2008-12-07 16:47:12 +0000554 void onExtern (const DagInit* d) {
555 checkNumberOfArguments(d, 0);
556 optDesc_.setExtern();
557 }
558
Mikhail Glushenkov09b51c32008-05-30 06:27:02 +0000559 void onHelp (const DagInit* d) {
560 checkNumberOfArguments(d, 1);
Mikhail Glushenkovb4ced5a2008-12-07 16:47:12 +0000561 optDesc_.Help = InitPtrToString(d->getArg(0));
Mikhail Glushenkov09b51c32008-05-30 06:27:02 +0000562 }
563
Mikhail Glushenkov739c7202008-11-28 00:13:25 +0000564 void onHidden (const DagInit* d) {
565 checkNumberOfArguments(d, 0);
Mikhail Glushenkov739c7202008-11-28 00:13:25 +0000566 optDesc_.setHidden();
567 }
568
569 void onReallyHidden (const DagInit* d) {
570 checkNumberOfArguments(d, 0);
Mikhail Glushenkov739c7202008-11-28 00:13:25 +0000571 optDesc_.setReallyHidden();
572 }
573
Mikhail Glushenkov09b51c32008-05-30 06:27:02 +0000574 void onRequired (const DagInit* d) {
575 checkNumberOfArguments(d, 0);
Mikhail Glushenkov19d3e822009-01-28 03:47:20 +0000576 if (optDesc_.isOneOrMore())
577 throw std::string("An option can't have both (required) "
578 "and (one_or_more) properties!");
Mikhail Glushenkov09b51c32008-05-30 06:27:02 +0000579 optDesc_.setRequired();
580 }
581
Mikhail Glushenkov8fe44472009-07-07 16:08:41 +0000582 void onInit (const DagInit* d) {
583 checkNumberOfArguments(d, 1);
584 Init* i = d->getArg(0);
585 const std::string& str = i->getAsString();
586
587 bool correct = optDesc_.isParameter() && dynamic_cast<StringInit*>(i);
588 correct |= (optDesc_.isSwitch() && (str == "true" || str == "false"));
589
590 if (!correct)
591 throw std::string("Incorrect usage of the 'init' option property!");
592
593 optDesc_.InitVal = i;
594 }
595
Mikhail Glushenkov19d3e822009-01-28 03:47:20 +0000596 void onOneOrMore (const DagInit* d) {
597 checkNumberOfArguments(d, 0);
598 if (optDesc_.isRequired() || optDesc_.isZeroOrOne())
599 throw std::string("Only one of (required), (zero_or_one) or "
600 "(one_or_more) properties is allowed!");
601 if (!OptionType::IsList(optDesc_.Type))
Daniel Dunbar1a551802009-07-03 00:10:29 +0000602 llvm::errs() << "Warning: specifying the 'one_or_more' property "
Mikhail Glushenkov19d3e822009-01-28 03:47:20 +0000603 "on a non-list option will have no effect.\n";
604 optDesc_.setOneOrMore();
605 }
606
607 void onZeroOrOne (const DagInit* d) {
608 checkNumberOfArguments(d, 0);
609 if (optDesc_.isRequired() || optDesc_.isOneOrMore())
610 throw std::string("Only one of (required), (zero_or_one) or "
611 "(one_or_more) properties is allowed!");
612 if (!OptionType::IsList(optDesc_.Type))
Daniel Dunbar1a551802009-07-03 00:10:29 +0000613 llvm::errs() << "Warning: specifying the 'zero_or_one' property"
Mikhail Glushenkov19d3e822009-01-28 03:47:20 +0000614 "on a non-list option will have no effect.\n";
615 optDesc_.setZeroOrOne();
616 }
617
618 void onMultiVal (const DagInit* d) {
619 checkNumberOfArguments(d, 1);
620 int val = InitPtrToInt(d->getArg(0));
621 if (val < 2)
622 throw std::string("Error in the 'multi_val' property: "
623 "the value must be greater than 1!");
624 if (!OptionType::IsList(optDesc_.Type))
625 throw std::string("The multi_val property is valid only "
626 "on list options!");
627 optDesc_.MultiVal = val;
628 }
629
Mikhail Glushenkov09b51c32008-05-30 06:27:02 +0000630};
631
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000632/// AddOption - A function object that is applied to every option
633/// description. Used by CollectOptionDescriptions.
Mikhail Glushenkov2b7bcb42008-05-30 06:27:29 +0000634class AddOption {
635private:
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000636 OptionDescriptions& OptDescs_;
Mikhail Glushenkov2b7bcb42008-05-30 06:27:29 +0000637
638public:
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000639 explicit AddOption(OptionDescriptions& OD) : OptDescs_(OD)
Mikhail Glushenkov2b7bcb42008-05-30 06:27:29 +0000640 {}
641
642 void operator()(const Init* i) {
643 const DagInit& d = InitPtrToDag(i);
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000644 checkNumberOfArguments(&d, 1);
Mikhail Glushenkov2b7bcb42008-05-30 06:27:29 +0000645
646 const OptionType::OptionType Type =
Mikhail Glushenkov4d21ae72009-10-18 22:51:30 +0000647 stringToOptionType(GetOperatorName(d));
Mikhail Glushenkov2b7bcb42008-05-30 06:27:29 +0000648 const std::string& Name = InitPtrToString(d.getArg(0));
649
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000650 OptionDescription OD(Type, Name);
651
652 if (!OD.isExtern())
653 checkNumberOfArguments(&d, 2);
654
655 if (OD.isAlias()) {
656 // Aliases store the aliased option name in the 'Help' field.
Mikhail Glushenkov2b7bcb42008-05-30 06:27:29 +0000657 OD.Help = InitPtrToString(d.getArg(1));
658 }
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000659 else if (!OD.isExtern()) {
660 processOptionProperties(&d, OD);
661 }
662 OptDescs_.InsertDescription(OD);
Mikhail Glushenkov2b7bcb42008-05-30 06:27:29 +0000663 }
664
665private:
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000666 /// processOptionProperties - Go through the list of option
667 /// properties and call a corresponding handler for each.
668 static void processOptionProperties (const DagInit* d, OptionDescription& o) {
669 checkNumberOfArguments(d, 2);
670 DagInit::const_arg_iterator B = d->arg_begin();
671 // Skip the first argument: it's always the option name.
672 ++B;
673 std::for_each(B, d->arg_end(), CollectOptionProperties(o));
Mikhail Glushenkov2b7bcb42008-05-30 06:27:29 +0000674 }
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000675
Mikhail Glushenkov2b7bcb42008-05-30 06:27:29 +0000676};
677
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000678/// CollectOptionDescriptions - Collects option properties from all
679/// OptionLists.
680void CollectOptionDescriptions (RecordVector::const_iterator B,
681 RecordVector::const_iterator E,
682 OptionDescriptions& OptDescs)
683{
684 // For every OptionList:
685 for (; B!=E; ++B) {
686 RecordVector::value_type T = *B;
687 // Throws an exception if the value does not exist.
688 ListInit* PropList = T->getValueAsListInit("options");
Mikhail Glushenkov2b7bcb42008-05-30 06:27:29 +0000689
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000690 // For every option description in this list:
691 // collect the information and
692 std::for_each(PropList->begin(), PropList->end(), AddOption(OptDescs));
693 }
694}
695
696// Tool information record
697
698namespace ToolFlags {
699 enum ToolFlags { Join = 0x1, Sink = 0x2 };
700}
701
702struct ToolDescription : public RefCountedBase<ToolDescription> {
703 std::string Name;
704 Init* CmdLine;
705 Init* Actions;
706 StrVector InLanguage;
707 std::string OutLanguage;
708 std::string OutputSuffix;
709 unsigned Flags;
710
711 // Various boolean properties
712 void setSink() { Flags |= ToolFlags::Sink; }
713 bool isSink() const { return Flags & ToolFlags::Sink; }
714 void setJoin() { Flags |= ToolFlags::Join; }
715 bool isJoin() const { return Flags & ToolFlags::Join; }
716
717 // Default ctor here is needed because StringMap can only store
718 // DefaultConstructible objects
719 ToolDescription() : CmdLine(0), Actions(0), Flags(0) {}
720 ToolDescription (const std::string& n)
721 : Name(n), CmdLine(0), Actions(0), Flags(0)
722 {}
723};
724
725/// ToolDescriptions - A list of Tool information records.
726typedef std::vector<IntrusiveRefCntPtr<ToolDescription> > ToolDescriptions;
727
728
729/// CollectToolProperties - Function object for iterating over a list of
Mikhail Glushenkov8e7254c2008-05-09 08:27:26 +0000730/// tool property records.
Mikhail Glushenkov632eb202009-12-07 10:51:55 +0000731
732class CollectToolProperties;
733typedef void (CollectToolProperties::* CollectToolPropertiesHandler)
734(const DagInit*);
735
736class CollectToolProperties : public HandlerTable<CollectToolPropertiesHandler>
737{
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +0000738private:
739
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000740 /// toolDesc_ - Properties of the current Tool. This is where the
741 /// information is stored.
742 ToolDescription& toolDesc_;
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +0000743
744public:
745
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000746 explicit CollectToolProperties (ToolDescription& d)
Mikhail Glushenkov632eb202009-12-07 10:51:55 +0000747 : toolDesc_(d)
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +0000748 {
749 if (!staticMembersInitialized_) {
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000750
751 AddHandler("actions", &CollectToolProperties::onActions);
752 AddHandler("cmd_line", &CollectToolProperties::onCmdLine);
753 AddHandler("in_language", &CollectToolProperties::onInLanguage);
754 AddHandler("join", &CollectToolProperties::onJoin);
755 AddHandler("out_language", &CollectToolProperties::onOutLanguage);
756 AddHandler("output_suffix", &CollectToolProperties::onOutputSuffix);
757 AddHandler("sink", &CollectToolProperties::onSink);
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +0000758
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +0000759 staticMembersInitialized_ = true;
760 }
761 }
762
Mikhail Glushenkov632eb202009-12-07 10:51:55 +0000763 void operator() (Init* i) {
764 InvokeDagInitHandler(this, i);
765 }
766
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +0000767private:
768
769 /// Property handlers --
770 /// Functions that extract information about tool properties from
771 /// DAG representation.
772
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000773 void onActions (const DagInit* d) {
774 checkNumberOfArguments(d, 1);
Mikhail Glushenkovad889a72008-12-07 16:45:12 +0000775 Init* Case = d->getArg(0);
776 if (typeid(*Case) != typeid(DagInit) ||
Mikhail Glushenkov4d21ae72009-10-18 22:51:30 +0000777 GetOperatorName(static_cast<DagInit*>(Case)) != "case")
Mikhail Glushenkovad889a72008-12-07 16:45:12 +0000778 throw
779 std::string("The argument to (actions) should be a 'case' construct!");
780 toolDesc_.Actions = Case;
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000781 }
782
Mikhail Glushenkov29063552008-05-06 18:18:20 +0000783 void onCmdLine (const DagInit* d) {
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +0000784 checkNumberOfArguments(d, 1);
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000785 toolDesc_.CmdLine = d->getArg(0);
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +0000786 }
787
Mikhail Glushenkov29063552008-05-06 18:18:20 +0000788 void onInLanguage (const DagInit* d) {
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +0000789 checkNumberOfArguments(d, 1);
Mikhail Glushenkovffcf3a12008-05-30 06:18:16 +0000790 Init* arg = d->getArg(0);
791
792 // Find out the argument's type.
793 if (typeid(*arg) == typeid(StringInit)) {
794 // It's a string.
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000795 toolDesc_.InLanguage.push_back(InitPtrToString(arg));
Mikhail Glushenkovffcf3a12008-05-30 06:18:16 +0000796 }
797 else {
798 // It's a list.
799 const ListInit& lst = InitPtrToList(arg);
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000800 StrVector& out = toolDesc_.InLanguage;
Mikhail Glushenkovffcf3a12008-05-30 06:18:16 +0000801
802 // Copy strings to the output vector.
803 for (ListInit::const_iterator B = lst.begin(), E = lst.end();
804 B != E; ++B) {
805 out.push_back(InitPtrToString(*B));
806 }
807
808 // Remove duplicates.
809 std::sort(out.begin(), out.end());
810 StrVector::iterator newE = std::unique(out.begin(), out.end());
811 out.erase(newE, out.end());
812 }
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +0000813 }
814
Mikhail Glushenkov29063552008-05-06 18:18:20 +0000815 void onJoin (const DagInit* d) {
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +0000816 checkNumberOfArguments(d, 0);
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000817 toolDesc_.setJoin();
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +0000818 }
819
Mikhail Glushenkov29063552008-05-06 18:18:20 +0000820 void onOutLanguage (const DagInit* d) {
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +0000821 checkNumberOfArguments(d, 1);
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000822 toolDesc_.OutLanguage = InitPtrToString(d->getArg(0));
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +0000823 }
824
Mikhail Glushenkov29063552008-05-06 18:18:20 +0000825 void onOutputSuffix (const DagInit* d) {
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +0000826 checkNumberOfArguments(d, 1);
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000827 toolDesc_.OutputSuffix = InitPtrToString(d->getArg(0));
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +0000828 }
829
Mikhail Glushenkov29063552008-05-06 18:18:20 +0000830 void onSink (const DagInit* d) {
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +0000831 checkNumberOfArguments(d, 0);
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000832 toolDesc_.setSink();
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +0000833 }
834
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +0000835};
836
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000837/// CollectToolDescriptions - Gather information about tool properties
Mikhail Glushenkove43228952008-05-30 06:26:08 +0000838/// from the parsed TableGen data (basically a wrapper for the
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000839/// CollectToolProperties function object).
840void CollectToolDescriptions (RecordVector::const_iterator B,
841 RecordVector::const_iterator E,
842 ToolDescriptions& ToolDescs)
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +0000843{
844 // Iterate over a properties list of every Tool definition
845 for (;B!=E;++B) {
Mikhail Glushenkovfa270772008-11-17 17:29:42 +0000846 const Record* T = *B;
Mikhail Glushenkove43228952008-05-30 06:26:08 +0000847 // Throws an exception if the value does not exist.
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +0000848 ListInit* PropList = T->getValueAsListInit("properties");
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +0000849
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000850 IntrusiveRefCntPtr<ToolDescription>
851 ToolDesc(new ToolDescription(T->getName()));
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +0000852
853 std::for_each(PropList->begin(), PropList->end(),
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000854 CollectToolProperties(*ToolDesc));
855 ToolDescs.push_back(ToolDesc);
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +0000856 }
857}
858
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000859/// FillInEdgeVector - Merge all compilation graph definitions into
860/// one single edge list.
861void FillInEdgeVector(RecordVector::const_iterator B,
862 RecordVector::const_iterator E, RecordVector& Out) {
863 for (; B != E; ++B) {
864 const ListInit* edges = (*B)->getValueAsListInit("edges");
Mikhail Glushenkov09b51c32008-05-30 06:27:02 +0000865
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000866 for (unsigned i = 0; i < edges->size(); ++i)
867 Out.push_back(edges->getElementAsRecord(i));
868 }
869}
870
871/// CalculatePriority - Calculate the priority of this plugin.
872int CalculatePriority(RecordVector::const_iterator B,
873 RecordVector::const_iterator E) {
Mikhail Glushenkov2cea7bd2009-10-17 20:08:30 +0000874 int priority = 0;
875
876 if (B != E) {
877 priority = static_cast<int>((*B)->getValueAsInt("priority"));
878
879 if (++B != E)
880 throw std::string("More than one 'PluginPriority' instance found: "
881 "most probably an error!");
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000882 }
Mikhail Glushenkov2cea7bd2009-10-17 20:08:30 +0000883
884 return priority;
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000885}
Mikhail Glushenkove43228952008-05-30 06:26:08 +0000886
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000887/// NotInGraph - Helper function object for FilterNotInGraph.
888struct NotInGraph {
889private:
890 const llvm::StringSet<>& ToolsInGraph_;
891
892public:
893 NotInGraph(const llvm::StringSet<>& ToolsInGraph)
894 : ToolsInGraph_(ToolsInGraph)
895 {}
896
897 bool operator()(const IntrusiveRefCntPtr<ToolDescription>& x) {
898 return (ToolsInGraph_.count(x->Name) == 0);
899 }
900};
901
902/// FilterNotInGraph - Filter out from ToolDescs all Tools not
903/// mentioned in the compilation graph definition.
904void FilterNotInGraph (const RecordVector& EdgeVector,
905 ToolDescriptions& ToolDescs) {
906
907 // List all tools mentioned in the graph.
908 llvm::StringSet<> ToolsInGraph;
909
910 for (RecordVector::const_iterator B = EdgeVector.begin(),
911 E = EdgeVector.end(); B != E; ++B) {
912
913 const Record* Edge = *B;
Mikhail Glushenkov15b71ba2008-12-07 16:44:47 +0000914 const std::string& NodeA = Edge->getValueAsString("a");
915 const std::string& NodeB = Edge->getValueAsString("b");
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000916
Mikhail Glushenkov15b71ba2008-12-07 16:44:47 +0000917 if (NodeA != "root")
918 ToolsInGraph.insert(NodeA);
919 ToolsInGraph.insert(NodeB);
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000920 }
921
922 // Filter ToolPropertiesList.
923 ToolDescriptions::iterator new_end =
924 std::remove_if(ToolDescs.begin(), ToolDescs.end(),
925 NotInGraph(ToolsInGraph));
926 ToolDescs.erase(new_end, ToolDescs.end());
927}
928
929/// FillInToolToLang - Fills in two tables that map tool names to
930/// (input, output) languages. Helper function used by TypecheckGraph().
931void FillInToolToLang (const ToolDescriptions& ToolDescs,
932 StringMap<StringSet<> >& ToolToInLang,
933 StringMap<std::string>& ToolToOutLang) {
934 for (ToolDescriptions::const_iterator B = ToolDescs.begin(),
935 E = ToolDescs.end(); B != E; ++B) {
936 const ToolDescription& D = *(*B);
937 for (StrVector::const_iterator B = D.InLanguage.begin(),
938 E = D.InLanguage.end(); B != E; ++B)
939 ToolToInLang[D.Name].insert(*B);
940 ToolToOutLang[D.Name] = D.OutLanguage;
Mikhail Glushenkove43228952008-05-30 06:26:08 +0000941 }
942}
943
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000944/// TypecheckGraph - Check that names for output and input languages
945/// on all edges do match. This doesn't do much when the information
946/// about the whole graph is not available (i.e. when compiling most
947/// plugins).
948void TypecheckGraph (const RecordVector& EdgeVector,
949 const ToolDescriptions& ToolDescs) {
950 StringMap<StringSet<> > ToolToInLang;
951 StringMap<std::string> ToolToOutLang;
952
953 FillInToolToLang(ToolDescs, ToolToInLang, ToolToOutLang);
954 StringMap<std::string>::iterator IAE = ToolToOutLang.end();
955 StringMap<StringSet<> >::iterator IBE = ToolToInLang.end();
956
957 for (RecordVector::const_iterator B = EdgeVector.begin(),
958 E = EdgeVector.end(); B != E; ++B) {
959 const Record* Edge = *B;
Mikhail Glushenkov15b71ba2008-12-07 16:44:47 +0000960 const std::string& NodeA = Edge->getValueAsString("a");
961 const std::string& NodeB = Edge->getValueAsString("b");
962 StringMap<std::string>::iterator IA = ToolToOutLang.find(NodeA);
963 StringMap<StringSet<> >::iterator IB = ToolToInLang.find(NodeB);
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000964
Mikhail Glushenkov15b71ba2008-12-07 16:44:47 +0000965 if (NodeA != "root") {
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000966 if (IA != IAE && IB != IBE && IB->second.count(IA->second) == 0)
Mikhail Glushenkov15b71ba2008-12-07 16:44:47 +0000967 throw "Edge " + NodeA + "->" + NodeB
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000968 + ": output->input language mismatch";
969 }
970
Mikhail Glushenkov15b71ba2008-12-07 16:44:47 +0000971 if (NodeB == "root")
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000972 throw std::string("Edges back to the root are not allowed!");
973 }
974}
975
976/// WalkCase - Walks the 'case' expression DAG and invokes
977/// TestCallback on every test, and StatementCallback on every
978/// statement. Handles 'case' nesting, but not the 'and' and 'or'
Mikhail Glushenkov4d21ae72009-10-18 22:51:30 +0000979/// combinators (that is, they are passed directly to TestCallback).
980/// TestCallback must have type 'void TestCallback(const DagInit*, unsigned
981/// IndentLevel, bool FirstTest)'.
982/// StatementCallback must have type 'void StatementCallback(const Init*,
983/// unsigned IndentLevel)'.
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000984template <typename F1, typename F2>
Mikhail Glushenkov4d21ae72009-10-18 22:51:30 +0000985void WalkCase(const Init* Case, F1 TestCallback, F2 StatementCallback,
986 unsigned IndentLevel = 0)
987{
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000988 const DagInit& d = InitPtrToDag(Case);
Mikhail Glushenkov4d21ae72009-10-18 22:51:30 +0000989
990 // Error checks.
991 if (GetOperatorName(d) != "case")
992 throw std::string("WalkCase should be invoked only on 'case' expressions!");
993
994 if (d.getNumArgs() < 2)
995 throw "There should be at least one clause in the 'case' expression:\n"
996 + d.getAsString();
997
998 // Main loop.
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000999 bool even = false;
Mikhail Glushenkov4d21ae72009-10-18 22:51:30 +00001000 const unsigned numArgs = d.getNumArgs();
1001 unsigned i = 1;
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00001002 for (DagInit::const_arg_iterator B = d.arg_begin(), E = d.arg_end();
1003 B != E; ++B) {
1004 Init* arg = *B;
Mikhail Glushenkov4d21ae72009-10-18 22:51:30 +00001005
1006 if (!even)
1007 {
1008 // Handle test.
1009 const DagInit& Test = InitPtrToDag(arg);
1010
1011 if (GetOperatorName(Test) == "default" && (i+1 != numArgs))
1012 throw std::string("The 'default' clause should be the last in the"
1013 "'case' construct!");
1014 if (i == numArgs)
1015 throw "Case construct handler: no corresponding action "
1016 "found for the test " + Test.getAsString() + '!';
1017
1018 TestCallback(&Test, IndentLevel, (i == 1));
1019 }
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00001020 else
Mikhail Glushenkov4d21ae72009-10-18 22:51:30 +00001021 {
1022 if (dynamic_cast<DagInit*>(arg)
1023 && GetOperatorName(static_cast<DagInit*>(arg)) == "case") {
1024 // Nested 'case'.
1025 WalkCase(arg, TestCallback, StatementCallback, IndentLevel + Indent1);
1026 }
1027
1028 // Handle statement.
1029 StatementCallback(arg, IndentLevel);
1030 }
1031
1032 ++i;
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00001033 even = !even;
1034 }
1035}
1036
1037/// ExtractOptionNames - A helper function object used by
1038/// CheckForSuperfluousOptions() to walk the 'case' DAG.
1039class ExtractOptionNames {
1040 llvm::StringSet<>& OptionNames_;
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00001041
Mikhail Glushenkov08509492008-12-07 16:42:22 +00001042 void processDag(const Init* Statement) {
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00001043 const DagInit& Stmt = InitPtrToDag(Statement);
Mikhail Glushenkov4d21ae72009-10-18 22:51:30 +00001044 const std::string& ActionName = GetOperatorName(Stmt);
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00001045 if (ActionName == "forward" || ActionName == "forward_as" ||
1046 ActionName == "unpack_values" || ActionName == "switch_on" ||
1047 ActionName == "parameter_equals" || ActionName == "element_in_list" ||
Mikhail Glushenkov5c2b6b22008-12-17 02:47:01 +00001048 ActionName == "not_empty" || ActionName == "empty") {
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00001049 checkNumberOfArguments(&Stmt, 1);
1050 const std::string& Name = InitPtrToString(Stmt.getArg(0));
1051 OptionNames_.insert(Name);
1052 }
1053 else if (ActionName == "and" || ActionName == "or") {
1054 for (unsigned i = 0, NumArgs = Stmt.getNumArgs(); i < NumArgs; ++i) {
Mikhail Glushenkov08509492008-12-07 16:42:22 +00001055 this->processDag(Stmt.getArg(i));
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00001056 }
1057 }
1058 }
Mikhail Glushenkov08509492008-12-07 16:42:22 +00001059
1060public:
1061 ExtractOptionNames(llvm::StringSet<>& OptionNames) : OptionNames_(OptionNames)
1062 {}
1063
1064 void operator()(const Init* Statement) {
1065 if (typeid(*Statement) == typeid(ListInit)) {
1066 const ListInit& DagList = *static_cast<const ListInit*>(Statement);
1067 for (ListInit::const_iterator B = DagList.begin(), E = DagList.end();
1068 B != E; ++B)
1069 this->processDag(*B);
1070 }
1071 else {
1072 this->processDag(Statement);
1073 }
1074 }
Mikhail Glushenkov4d21ae72009-10-18 22:51:30 +00001075
1076 void operator()(const DagInit* Test, unsigned, bool) {
1077 this->operator()(Test);
1078 }
1079 void operator()(const Init* Statement, unsigned) {
1080 this->operator()(Statement);
1081 }
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00001082};
1083
Mikhail Glushenkova7d0ae32008-05-30 06:28:37 +00001084/// CheckForSuperfluousOptions - Check that there are no side
1085/// effect-free options (specified only in the OptionList). Otherwise,
1086/// output a warning.
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00001087void CheckForSuperfluousOptions (const RecordVector& Edges,
1088 const ToolDescriptions& ToolDescs,
1089 const OptionDescriptions& OptDescs) {
Mikhail Glushenkova7d0ae32008-05-30 06:28:37 +00001090 llvm::StringSet<> nonSuperfluousOptions;
1091
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00001092 // Add all options mentioned in the ToolDesc.Actions to the set of
Mikhail Glushenkova7d0ae32008-05-30 06:28:37 +00001093 // non-superfluous options.
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00001094 for (ToolDescriptions::const_iterator B = ToolDescs.begin(),
1095 E = ToolDescs.end(); B != E; ++B) {
1096 const ToolDescription& TD = *(*B);
1097 ExtractOptionNames Callback(nonSuperfluousOptions);
1098 if (TD.Actions)
1099 WalkCase(TD.Actions, Callback, Callback);
1100 }
1101
1102 // Add all options mentioned in the 'case' clauses of the
1103 // OptionalEdges of the compilation graph to the set of
1104 // non-superfluous options.
1105 for (RecordVector::const_iterator B = Edges.begin(), E = Edges.end();
1106 B != E; ++B) {
1107 const Record* Edge = *B;
1108 DagInit* Weight = Edge->getValueAsDag("weight");
1109
1110 if (!isDagEmpty(Weight))
1111 WalkCase(Weight, ExtractOptionNames(nonSuperfluousOptions), Id());
Mikhail Glushenkova7d0ae32008-05-30 06:28:37 +00001112 }
1113
1114 // Check that all options in OptDescs belong to the set of
1115 // non-superfluous options.
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00001116 for (OptionDescriptions::const_iterator B = OptDescs.begin(),
Mikhail Glushenkova7d0ae32008-05-30 06:28:37 +00001117 E = OptDescs.end(); B != E; ++B) {
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00001118 const OptionDescription& Val = B->second;
Mikhail Glushenkova7d0ae32008-05-30 06:28:37 +00001119 if (!nonSuperfluousOptions.count(Val.Name)
1120 && Val.Type != OptionType::Alias)
Daniel Dunbar1a551802009-07-03 00:10:29 +00001121 llvm::errs() << "Warning: option '-" << Val.Name << "' has no effect! "
Mikhail Glushenkova7d0ae32008-05-30 06:28:37 +00001122 "Probable cause: this option is specified only in the OptionList.\n";
1123 }
1124}
1125
Mikhail Glushenkovad981bf2009-09-28 01:16:42 +00001126/// EmitCaseTest0Args - Helper function used by EmitCaseConstructHandler().
1127bool EmitCaseTest0Args(const std::string& TestName, raw_ostream& O) {
1128 if (TestName == "single_input_file") {
1129 O << "InputFilenames.size() == 1";
1130 return true;
1131 }
1132 else if (TestName == "multiple_input_files") {
1133 O << "InputFilenames.size() > 1";
1134 return true;
1135 }
1136
1137 return false;
1138}
1139
Mikhail Glushenkov4858a1d2009-10-21 02:13:13 +00001140/// EmitListTest - Helper function used by EmitCaseTest1ArgList().
1141template <typename F>
1142void EmitListTest(const ListInit& L, const char* LogicOp,
1143 F Callback, raw_ostream& O)
1144{
1145 // This is a lot like EmitLogicalOperationTest, but works on ListInits instead
1146 // of Dags...
1147 bool isFirst = true;
1148 for (ListInit::const_iterator B = L.begin(), E = L.end(); B != E; ++B) {
1149 if (isFirst)
1150 isFirst = false;
1151 else
1152 O << " || ";
1153 Callback(InitPtrToString(*B), O);
1154 }
1155}
1156
1157// Callbacks for use with EmitListTest.
1158
1159class EmitSwitchOn {
1160 const OptionDescriptions& OptDescs_;
1161public:
1162 EmitSwitchOn(const OptionDescriptions& OptDescs) : OptDescs_(OptDescs)
1163 {}
1164
1165 void operator()(const std::string& OptName, raw_ostream& O) const {
1166 const OptionDescription& OptDesc = OptDescs_.FindSwitch(OptName);
1167 O << OptDesc.GenVariableName();
1168 }
1169};
1170
1171class EmitEmptyTest {
1172 bool EmitNegate_;
1173 const OptionDescriptions& OptDescs_;
1174public:
1175 EmitEmptyTest(bool EmitNegate, const OptionDescriptions& OptDescs)
1176 : EmitNegate_(EmitNegate), OptDescs_(OptDescs)
1177 {}
1178
1179 void operator()(const std::string& OptName, raw_ostream& O) const {
1180 const char* Neg = (EmitNegate_ ? "!" : "");
1181 if (OptName == "o") {
1182 O << Neg << "OutputFilename.empty()";
1183 }
Mikhail Glushenkov97955002009-12-01 06:51:30 +00001184 else if (OptName == "save-temps") {
1185 O << Neg << "(SaveTemps == SaveTempsEnum::Unset)";
1186 }
Mikhail Glushenkov4858a1d2009-10-21 02:13:13 +00001187 else {
1188 const OptionDescription& OptDesc = OptDescs_.FindListOrParameter(OptName);
1189 O << Neg << OptDesc.GenVariableName() << ".empty()";
1190 }
1191 }
1192};
1193
1194
1195/// EmitCaseTest1ArgList - Helper function used by EmitCaseTest1Arg();
1196bool EmitCaseTest1ArgList(const std::string& TestName,
1197 const DagInit& d,
1198 const OptionDescriptions& OptDescs,
1199 raw_ostream& O) {
1200 const ListInit& L = *static_cast<ListInit*>(d.getArg(0));
1201
1202 if (TestName == "any_switch_on") {
1203 EmitListTest(L, "||", EmitSwitchOn(OptDescs), O);
1204 return true;
1205 }
1206 else if (TestName == "switch_on") {
1207 EmitListTest(L, "&&", EmitSwitchOn(OptDescs), O);
1208 return true;
1209 }
1210 else if (TestName == "any_not_empty") {
1211 EmitListTest(L, "||", EmitEmptyTest(true, OptDescs), O);
1212 return true;
1213 }
1214 else if (TestName == "any_empty") {
1215 EmitListTest(L, "||", EmitEmptyTest(false, OptDescs), O);
1216 return true;
1217 }
1218 else if (TestName == "not_empty") {
1219 EmitListTest(L, "&&", EmitEmptyTest(true, OptDescs), O);
1220 return true;
1221 }
1222 else if (TestName == "empty") {
1223 EmitListTest(L, "&&", EmitEmptyTest(false, OptDescs), O);
1224 return true;
1225 }
1226
1227 return false;
1228}
1229
Mikhail Glushenkov0a22fb62009-10-17 20:09:29 +00001230/// EmitCaseTest1ArgStr - Helper function used by EmitCaseTest1Arg();
1231bool EmitCaseTest1ArgStr(const std::string& TestName,
1232 const DagInit& d,
1233 const OptionDescriptions& OptDescs,
1234 raw_ostream& O) {
Mikhail Glushenkovb5ccfbf2008-05-30 06:10:19 +00001235 const std::string& OptName = InitPtrToString(d.getArg(0));
Mikhail Glushenkov5c2b6b22008-12-17 02:47:01 +00001236
Mikhail Glushenkovb5ccfbf2008-05-30 06:10:19 +00001237 if (TestName == "switch_on") {
Mikhail Glushenkov4858a1d2009-10-21 02:13:13 +00001238 apply(EmitSwitchOn(OptDescs), OptName, O);
Mikhail Glushenkovb5ccfbf2008-05-30 06:10:19 +00001239 return true;
Mikhail Glushenkov0a22fb62009-10-17 20:09:29 +00001240 }
1241 else if (TestName == "input_languages_contain") {
Mikhail Glushenkovb5ccfbf2008-05-30 06:10:19 +00001242 O << "InLangs.count(\"" << OptName << "\") != 0";
1243 return true;
Mikhail Glushenkov0a22fb62009-10-17 20:09:29 +00001244 }
1245 else if (TestName == "in_language") {
Mikhail Glushenkov07376512008-09-22 20:48:22 +00001246 // This works only for single-argument Tool::GenerateAction. Join
1247 // tools can process several files in different languages simultaneously.
1248
1249 // TODO: make this work with Edge::Weight (if possible).
Mikhail Glushenkov11a353a2008-09-22 20:47:46 +00001250 O << "LangMap.GetLanguage(inFile) == \"" << OptName << '\"';
Mikhail Glushenkov2e73e852008-05-30 06:19:52 +00001251 return true;
Mikhail Glushenkov0a22fb62009-10-17 20:09:29 +00001252 }
1253 else if (TestName == "not_empty" || TestName == "empty") {
Mikhail Glushenkov4858a1d2009-10-21 02:13:13 +00001254 bool EmitNegate = (TestName == "not_empty");
1255 apply(EmitEmptyTest(EmitNegate, OptDescs), OptName, O);
Mikhail Glushenkov0a22fb62009-10-17 20:09:29 +00001256 return true;
1257 }
1258
Mikhail Glushenkov0a22fb62009-10-17 20:09:29 +00001259 return false;
1260}
1261
1262/// EmitCaseTest1Arg - Helper function used by EmitCaseConstructHandler();
1263bool EmitCaseTest1Arg(const std::string& TestName,
1264 const DagInit& d,
1265 const OptionDescriptions& OptDescs,
1266 raw_ostream& O) {
1267 checkNumberOfArguments(&d, 1);
1268 if (typeid(*d.getArg(0)) == typeid(ListInit))
1269 return EmitCaseTest1ArgList(TestName, d, OptDescs, O);
1270 else
1271 return EmitCaseTest1ArgStr(TestName, d, OptDescs, O);
1272}
1273
Mikhail Glushenkovad981bf2009-09-28 01:16:42 +00001274/// EmitCaseTest2Args - Helper function used by EmitCaseConstructHandler().
Mikhail Glushenkovb5ccfbf2008-05-30 06:10:19 +00001275bool EmitCaseTest2Args(const std::string& TestName,
1276 const DagInit& d,
Mikhail Glushenkovf8349ac2009-09-21 15:53:44 +00001277 unsigned IndentLevel,
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00001278 const OptionDescriptions& OptDescs,
Daniel Dunbar1a551802009-07-03 00:10:29 +00001279 raw_ostream& O) {
Mikhail Glushenkovb5ccfbf2008-05-30 06:10:19 +00001280 checkNumberOfArguments(&d, 2);
1281 const std::string& OptName = InitPtrToString(d.getArg(0));
1282 const std::string& OptArg = InitPtrToString(d.getArg(1));
Mikhail Glushenkovb5ccfbf2008-05-30 06:10:19 +00001283
1284 if (TestName == "parameter_equals") {
Mikhail Glushenkov4858a1d2009-10-21 02:13:13 +00001285 const OptionDescription& OptDesc = OptDescs.FindParameter(OptName);
Mikhail Glushenkovb5ccfbf2008-05-30 06:10:19 +00001286 O << OptDesc.GenVariableName() << " == \"" << OptArg << "\"";
1287 return true;
1288 }
1289 else if (TestName == "element_in_list") {
Mikhail Glushenkov4858a1d2009-10-21 02:13:13 +00001290 const OptionDescription& OptDesc = OptDescs.FindList(OptName);
Mikhail Glushenkovb5ccfbf2008-05-30 06:10:19 +00001291 const std::string& VarName = OptDesc.GenVariableName();
Mikhail Glushenkovf8349ac2009-09-21 15:53:44 +00001292 O << "std::find(" << VarName << ".begin(),\n";
1293 O.indent(IndentLevel + Indent1)
1294 << VarName << ".end(), \""
Mikhail Glushenkovb5ccfbf2008-05-30 06:10:19 +00001295 << OptArg << "\") != " << VarName << ".end()";
1296 return true;
1297 }
1298
1299 return false;
1300}
1301
1302// Forward declaration.
1303// EmitLogicalOperationTest and EmitCaseTest are mutually recursive.
Mikhail Glushenkovf8349ac2009-09-21 15:53:44 +00001304void EmitCaseTest(const DagInit& d, unsigned IndentLevel,
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00001305 const OptionDescriptions& OptDescs,
Daniel Dunbar1a551802009-07-03 00:10:29 +00001306 raw_ostream& O);
Mikhail Glushenkovb5ccfbf2008-05-30 06:10:19 +00001307
1308/// EmitLogicalOperationTest - Helper function used by
1309/// EmitCaseConstructHandler.
1310void EmitLogicalOperationTest(const DagInit& d, const char* LogicOp,
Mikhail Glushenkovf8349ac2009-09-21 15:53:44 +00001311 unsigned IndentLevel,
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00001312 const OptionDescriptions& OptDescs,
Daniel Dunbar1a551802009-07-03 00:10:29 +00001313 raw_ostream& O) {
Mikhail Glushenkovb5ccfbf2008-05-30 06:10:19 +00001314 O << '(';
1315 for (unsigned j = 0, NumArgs = d.getNumArgs(); j < NumArgs; ++j) {
Mikhail Glushenkovffcf3a12008-05-30 06:18:16 +00001316 const DagInit& InnerTest = InitPtrToDag(d.getArg(j));
Mikhail Glushenkovb5ccfbf2008-05-30 06:10:19 +00001317 EmitCaseTest(InnerTest, IndentLevel, OptDescs, O);
Mikhail Glushenkovf8349ac2009-09-21 15:53:44 +00001318 if (j != NumArgs - 1) {
1319 O << ")\n";
1320 O.indent(IndentLevel + Indent1) << ' ' << LogicOp << " (";
1321 }
1322 else {
Mikhail Glushenkovb5ccfbf2008-05-30 06:10:19 +00001323 O << ')';
Mikhail Glushenkovf8349ac2009-09-21 15:53:44 +00001324 }
Mikhail Glushenkovb5ccfbf2008-05-30 06:10:19 +00001325 }
1326}
1327
Mikhail Glushenkovf8349ac2009-09-21 15:53:44 +00001328void EmitLogicalNot(const DagInit& d, unsigned IndentLevel,
Mikhail Glushenkov684a8b02009-09-10 16:21:38 +00001329 const OptionDescriptions& OptDescs, raw_ostream& O)
1330{
1331 checkNumberOfArguments(&d, 1);
1332 const DagInit& InnerTest = InitPtrToDag(d.getArg(0));
1333 O << "! (";
1334 EmitCaseTest(InnerTest, IndentLevel, OptDescs, O);
1335 O << ")";
1336}
1337
Mikhail Glushenkovb5ccfbf2008-05-30 06:10:19 +00001338/// EmitCaseTest - Helper function used by EmitCaseConstructHandler.
Mikhail Glushenkovf8349ac2009-09-21 15:53:44 +00001339void EmitCaseTest(const DagInit& d, unsigned IndentLevel,
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00001340 const OptionDescriptions& OptDescs,
Daniel Dunbar1a551802009-07-03 00:10:29 +00001341 raw_ostream& O) {
Mikhail Glushenkov4d21ae72009-10-18 22:51:30 +00001342 const std::string& TestName = GetOperatorName(d);
Mikhail Glushenkovb5ccfbf2008-05-30 06:10:19 +00001343
1344 if (TestName == "and")
1345 EmitLogicalOperationTest(d, "&&", IndentLevel, OptDescs, O);
1346 else if (TestName == "or")
1347 EmitLogicalOperationTest(d, "||", IndentLevel, OptDescs, O);
Mikhail Glushenkov684a8b02009-09-10 16:21:38 +00001348 else if (TestName == "not")
1349 EmitLogicalNot(d, IndentLevel, OptDescs, O);
Mikhail Glushenkovad981bf2009-09-28 01:16:42 +00001350 else if (EmitCaseTest0Args(TestName, O))
1351 return;
Mikhail Glushenkovb5ccfbf2008-05-30 06:10:19 +00001352 else if (EmitCaseTest1Arg(TestName, d, OptDescs, O))
1353 return;
1354 else if (EmitCaseTest2Args(TestName, d, IndentLevel, OptDescs, O))
1355 return;
1356 else
1357 throw TestName + ": unknown edge property!";
1358}
1359
Mikhail Glushenkov4d21ae72009-10-18 22:51:30 +00001360
1361/// EmitCaseTestCallback - Callback used by EmitCaseConstructHandler.
1362class EmitCaseTestCallback {
1363 bool EmitElseIf_;
1364 const OptionDescriptions& OptDescs_;
1365 raw_ostream& O_;
1366public:
1367
1368 EmitCaseTestCallback(bool EmitElseIf,
1369 const OptionDescriptions& OptDescs, raw_ostream& O)
1370 : EmitElseIf_(EmitElseIf), OptDescs_(OptDescs), O_(O)
1371 {}
1372
1373 void operator()(const DagInit* Test, unsigned IndentLevel, bool FirstTest)
1374 {
1375 if (GetOperatorName(Test) == "default") {
1376 O_.indent(IndentLevel) << "else {\n";
1377 }
1378 else {
1379 O_.indent(IndentLevel)
1380 << ((!FirstTest && EmitElseIf_) ? "else if (" : "if (");
1381 EmitCaseTest(*Test, IndentLevel, OptDescs_, O_);
1382 O_ << ") {\n";
1383 }
1384 }
1385};
1386
1387/// EmitCaseStatementCallback - Callback used by EmitCaseConstructHandler.
1388template <typename F>
1389class EmitCaseStatementCallback {
1390 F Callback_;
1391 raw_ostream& O_;
1392public:
1393
1394 EmitCaseStatementCallback(F Callback, raw_ostream& O)
1395 : Callback_(Callback), O_(O)
1396 {}
1397
Mikhail Glushenkov4d21ae72009-10-18 22:51:30 +00001398 void operator() (const Init* Statement, unsigned IndentLevel) {
Mikhail Glushenkovccef6de2009-10-19 21:24:28 +00001399
Mikhail Glushenkov4d21ae72009-10-18 22:51:30 +00001400 // Ignore nested 'case' DAG.
1401 if (!(dynamic_cast<const DagInit*>(Statement) &&
Mikhail Glushenkovccef6de2009-10-19 21:24:28 +00001402 GetOperatorName(static_cast<const DagInit*>(Statement)) == "case")) {
1403 if (typeid(*Statement) == typeid(ListInit)) {
1404 const ListInit& DagList = *static_cast<const ListInit*>(Statement);
1405 for (ListInit::const_iterator B = DagList.begin(), E = DagList.end();
1406 B != E; ++B)
1407 Callback_(*B, (IndentLevel + Indent1), O_);
1408 }
1409 else {
1410 Callback_(Statement, (IndentLevel + Indent1), O_);
1411 }
1412 }
Mikhail Glushenkov4d21ae72009-10-18 22:51:30 +00001413 O_.indent(IndentLevel) << "}\n";
1414 }
1415
1416};
1417
Mikhail Glushenkov0a22fb62009-10-17 20:09:29 +00001418/// EmitCaseConstructHandler - Emit code that handles the 'case'
1419/// construct. Takes a function object that should emit code for every case
Mikhail Glushenkov4d21ae72009-10-18 22:51:30 +00001420/// clause. Implemented on top of WalkCase.
Mikhail Glushenkov0a22fb62009-10-17 20:09:29 +00001421/// Callback's type is void F(Init* Statement, unsigned IndentLevel,
1422/// raw_ostream& O).
1423/// EmitElseIf parameter controls the type of condition that is emitted ('if
Mikhail Glushenkov4d21ae72009-10-18 22:51:30 +00001424/// (..) {..} else if (..) {} .. else {..}' vs. 'if (..) {..} if(..) {..}
1425/// .. else {..}').
Mikhail Glushenkovb5ccfbf2008-05-30 06:10:19 +00001426template <typename F>
Mikhail Glushenkov4d21ae72009-10-18 22:51:30 +00001427void EmitCaseConstructHandler(const Init* Case, unsigned IndentLevel,
Mikhail Glushenkov310d2eb2008-05-31 13:43:21 +00001428 F Callback, bool EmitElseIf,
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00001429 const OptionDescriptions& OptDescs,
Daniel Dunbar1a551802009-07-03 00:10:29 +00001430 raw_ostream& O) {
Mikhail Glushenkov4d21ae72009-10-18 22:51:30 +00001431 WalkCase(Case, EmitCaseTestCallback(EmitElseIf, OptDescs, O),
1432 EmitCaseStatementCallback<F>(Callback, O), IndentLevel);
Mikhail Glushenkovb5ccfbf2008-05-30 06:10:19 +00001433}
1434
Mikhail Glushenkova298bb72009-01-21 13:04:00 +00001435/// TokenizeCmdline - converts from "$CALL(HookName, 'Arg1', 'Arg2')/path" to
1436/// ["$CALL(", "HookName", "Arg1", "Arg2", ")/path"] .
1437/// Helper function used by EmitCmdLineVecFill and.
1438void TokenizeCmdline(const std::string& CmdLine, StrVector& Out) {
1439 const char* Delimiters = " \t\n\v\f\r";
1440 enum TokenizerState
1441 { Normal, SpecialCommand, InsideSpecialCommand, InsideQuotationMarks }
1442 cur_st = Normal;
Mikhail Glushenkov7bba2332009-06-25 18:21:34 +00001443
1444 if (CmdLine.empty())
1445 return;
Mikhail Glushenkova298bb72009-01-21 13:04:00 +00001446 Out.push_back("");
1447
1448 std::string::size_type B = CmdLine.find_first_not_of(Delimiters),
1449 E = CmdLine.size();
Mikhail Glushenkov7bba2332009-06-25 18:21:34 +00001450
Mikhail Glushenkova298bb72009-01-21 13:04:00 +00001451 for (; B != E; ++B) {
1452 char cur_ch = CmdLine[B];
1453
1454 switch (cur_st) {
1455 case Normal:
1456 if (cur_ch == '$') {
1457 cur_st = SpecialCommand;
1458 break;
1459 }
1460 if (oneOf(Delimiters, cur_ch)) {
1461 // Skip whitespace
1462 B = CmdLine.find_first_not_of(Delimiters, B);
1463 if (B == std::string::npos) {
1464 B = E-1;
1465 continue;
1466 }
1467 --B;
1468 Out.push_back("");
1469 continue;
1470 }
1471 break;
1472
1473
1474 case SpecialCommand:
1475 if (oneOf(Delimiters, cur_ch)) {
1476 cur_st = Normal;
1477 Out.push_back("");
1478 continue;
1479 }
1480 if (cur_ch == '(') {
1481 Out.push_back("");
1482 cur_st = InsideSpecialCommand;
1483 continue;
1484 }
1485 break;
1486
1487 case InsideSpecialCommand:
1488 if (oneOf(Delimiters, cur_ch)) {
1489 continue;
1490 }
1491 if (cur_ch == '\'') {
1492 cur_st = InsideQuotationMarks;
1493 Out.push_back("");
1494 continue;
1495 }
1496 if (cur_ch == ')') {
1497 cur_st = Normal;
1498 Out.push_back("");
1499 }
1500 if (cur_ch == ',') {
1501 continue;
1502 }
1503
1504 break;
1505
1506 case InsideQuotationMarks:
1507 if (cur_ch == '\'') {
1508 cur_st = InsideSpecialCommand;
1509 continue;
1510 }
1511 break;
1512 }
1513
1514 Out.back().push_back(cur_ch);
1515 }
1516}
1517
Mikhail Glushenkov08bd2e72008-05-30 06:12:24 +00001518/// SubstituteSpecialCommands - Perform string substitution for $CALL
1519/// and $ENV. Helper function used by EmitCmdLineVecFill().
Mikhail Glushenkova298bb72009-01-21 13:04:00 +00001520StrVector::const_iterator SubstituteSpecialCommands
Daniel Dunbar1a551802009-07-03 00:10:29 +00001521(StrVector::const_iterator Pos, StrVector::const_iterator End, raw_ostream& O)
Mikhail Glushenkova298bb72009-01-21 13:04:00 +00001522{
Mikhail Glushenkov22424562008-05-30 06:13:29 +00001523
Mikhail Glushenkova298bb72009-01-21 13:04:00 +00001524 const std::string& cmd = *Pos;
1525
1526 if (cmd == "$CALL") {
1527 checkedIncrement(Pos, End, "Syntax error in $CALL invocation!");
1528 const std::string& CmdName = *Pos;
1529
1530 if (CmdName == ")")
Mikhail Glushenkov22424562008-05-30 06:13:29 +00001531 throw std::string("$CALL invocation: empty argument list!");
1532
Mikhail Glushenkova298bb72009-01-21 13:04:00 +00001533 O << "hooks::";
1534 O << CmdName << "(";
Mikhail Glushenkov22424562008-05-30 06:13:29 +00001535
Mikhail Glushenkova298bb72009-01-21 13:04:00 +00001536
1537 bool firstIteration = true;
1538 while (true) {
1539 checkedIncrement(Pos, End, "Syntax error in $CALL invocation!");
1540 const std::string& Arg = *Pos;
1541 assert(Arg.size() != 0);
1542
1543 if (Arg[0] == ')')
1544 break;
1545
1546 if (firstIteration)
1547 firstIteration = false;
1548 else
1549 O << ", ";
1550
1551 O << '"' << Arg << '"';
1552 }
1553
1554 O << ')';
1555
1556 }
1557 else if (cmd == "$ENV") {
1558 checkedIncrement(Pos, End, "Syntax error in $ENV invocation!");
1559 const std::string& EnvName = *Pos;
1560
1561 if (EnvName == ")")
1562 throw "$ENV invocation: empty argument list!";
1563
1564 O << "checkCString(std::getenv(\"";
1565 O << EnvName;
1566 O << "\"))";
1567
1568 checkedIncrement(Pos, End, "Syntax error in $ENV invocation!");
Mikhail Glushenkov22424562008-05-30 06:13:29 +00001569 }
1570 else {
1571 throw "Unknown special command: " + cmd;
1572 }
1573
Mikhail Glushenkova298bb72009-01-21 13:04:00 +00001574 const std::string& Leftover = *Pos;
1575 assert(Leftover.at(0) == ')');
1576 if (Leftover.size() != 1)
1577 O << " + std::string(\"" << (Leftover.c_str() + 1) << "\")";
Mikhail Glushenkov22424562008-05-30 06:13:29 +00001578
Mikhail Glushenkova298bb72009-01-21 13:04:00 +00001579 return Pos;
Mikhail Glushenkov08bd2e72008-05-30 06:12:24 +00001580}
1581
1582/// EmitCmdLineVecFill - Emit code that fills in the command line
1583/// vector. Helper function used by EmitGenerateActionMethod().
Mikhail Glushenkovb5ccfbf2008-05-30 06:10:19 +00001584void EmitCmdLineVecFill(const Init* CmdLine, const std::string& ToolName,
Mikhail Glushenkovf8349ac2009-09-21 15:53:44 +00001585 bool IsJoin, unsigned IndentLevel,
Daniel Dunbar1a551802009-07-03 00:10:29 +00001586 raw_ostream& O) {
Mikhail Glushenkovb5ccfbf2008-05-30 06:10:19 +00001587 StrVector StrVec;
Mikhail Glushenkova298bb72009-01-21 13:04:00 +00001588 TokenizeCmdline(InitPtrToString(CmdLine), StrVec);
1589
Mikhail Glushenkov08bd2e72008-05-30 06:12:24 +00001590 if (StrVec.empty())
Mikhail Glushenkov7bba2332009-06-25 18:21:34 +00001591 throw "Tool '" + ToolName + "' has empty command line!";
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +00001592
Mikhail Glushenkova298bb72009-01-21 13:04:00 +00001593 StrVector::const_iterator I = StrVec.begin(), E = StrVec.end();
1594
1595 // If there is a hook invocation on the place of the first command, skip it.
Mikhail Glushenkov0941b0f2009-04-19 00:22:35 +00001596 assert(!StrVec[0].empty());
Mikhail Glushenkova298bb72009-01-21 13:04:00 +00001597 if (StrVec[0][0] == '$') {
1598 while (I != E && (*I)[0] != ')' )
1599 ++I;
1600
1601 // Skip the ')' symbol.
1602 ++I;
1603 }
1604 else {
1605 ++I;
1606 }
1607
Mikhail Glushenkov39482dd2009-10-08 04:40:08 +00001608 bool hasINFILE = false;
1609
Mikhail Glushenkova298bb72009-01-21 13:04:00 +00001610 for (; I != E; ++I) {
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +00001611 const std::string& cmd = *I;
Mikhail Glushenkov0941b0f2009-04-19 00:22:35 +00001612 assert(!cmd.empty());
Mikhail Glushenkovf8349ac2009-09-21 15:53:44 +00001613 O.indent(IndentLevel);
Mikhail Glushenkov08bd2e72008-05-30 06:12:24 +00001614 if (cmd.at(0) == '$') {
1615 if (cmd == "$INFILE") {
Mikhail Glushenkov39482dd2009-10-08 04:40:08 +00001616 hasINFILE = true;
Mikhail Glushenkovf8349ac2009-09-21 15:53:44 +00001617 if (IsJoin) {
Mikhail Glushenkov08bd2e72008-05-30 06:12:24 +00001618 O << "for (PathVector::const_iterator B = inFiles.begin()"
Mikhail Glushenkovf8349ac2009-09-21 15:53:44 +00001619 << ", E = inFiles.end();\n";
1620 O.indent(IndentLevel) << "B != E; ++B)\n";
1621 O.indent(IndentLevel + Indent1) << "vec.push_back(B->str());\n";
1622 }
1623 else {
Chris Lattner74382b72009-08-23 22:45:37 +00001624 O << "vec.push_back(inFile.str());\n";
Mikhail Glushenkovf8349ac2009-09-21 15:53:44 +00001625 }
Mikhail Glushenkov08bd2e72008-05-30 06:12:24 +00001626 }
1627 else if (cmd == "$OUTFILE") {
Mikhail Glushenkov39482dd2009-10-08 04:40:08 +00001628 O << "vec.push_back(\"\");\n";
1629 O.indent(IndentLevel) << "out_file_index = vec.size()-1;\n";
Mikhail Glushenkov08bd2e72008-05-30 06:12:24 +00001630 }
1631 else {
Mikhail Glushenkova298bb72009-01-21 13:04:00 +00001632 O << "vec.push_back(";
1633 I = SubstituteSpecialCommands(I, E, O);
Mikhail Glushenkov22424562008-05-30 06:13:29 +00001634 O << ");\n";
Mikhail Glushenkov08bd2e72008-05-30 06:12:24 +00001635 }
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +00001636 }
1637 else {
1638 O << "vec.push_back(\"" << cmd << "\");\n";
1639 }
1640 }
Mikhail Glushenkov39482dd2009-10-08 04:40:08 +00001641 if (!hasINFILE)
1642 throw "Tool '" + ToolName + "' doesn't take any input!";
Mikhail Glushenkova298bb72009-01-21 13:04:00 +00001643
Mikhail Glushenkov39482dd2009-10-08 04:40:08 +00001644 O.indent(IndentLevel) << "cmd = ";
Mikhail Glushenkova298bb72009-01-21 13:04:00 +00001645 if (StrVec[0][0] == '$')
1646 SubstituteSpecialCommands(StrVec.begin(), StrVec.end(), O);
1647 else
1648 O << '"' << StrVec[0] << '"';
1649 O << ";\n";
Mikhail Glushenkovb5ccfbf2008-05-30 06:10:19 +00001650}
1651
Mikhail Glushenkov08bd2e72008-05-30 06:12:24 +00001652/// EmitCmdLineVecFillCallback - A function object wrapper around
1653/// EmitCmdLineVecFill(). Used by EmitGenerateActionMethod() as an
1654/// argument to EmitCaseConstructHandler().
Mikhail Glushenkovb5ccfbf2008-05-30 06:10:19 +00001655class EmitCmdLineVecFillCallback {
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00001656 bool IsJoin;
Mikhail Glushenkovb5ccfbf2008-05-30 06:10:19 +00001657 const std::string& ToolName;
1658 public:
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00001659 EmitCmdLineVecFillCallback(bool J, const std::string& TN)
1660 : IsJoin(J), ToolName(TN) {}
Mikhail Glushenkovb5ccfbf2008-05-30 06:10:19 +00001661
Mikhail Glushenkovf8349ac2009-09-21 15:53:44 +00001662 void operator()(const Init* Statement, unsigned IndentLevel,
Daniel Dunbar1a551802009-07-03 00:10:29 +00001663 raw_ostream& O) const
Mikhail Glushenkovb5ccfbf2008-05-30 06:10:19 +00001664 {
Mikhail Glushenkovf8349ac2009-09-21 15:53:44 +00001665 EmitCmdLineVecFill(Statement, ToolName, IsJoin, IndentLevel, O);
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00001666 }
1667};
1668
1669/// EmitForwardOptionPropertyHandlingCode - Helper function used to
1670/// implement EmitActionHandler. Emits code for
1671/// handling the (forward) and (forward_as) option properties.
1672void EmitForwardOptionPropertyHandlingCode (const OptionDescription& D,
Mikhail Glushenkovf8349ac2009-09-21 15:53:44 +00001673 unsigned IndentLevel,
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00001674 const std::string& NewName,
Daniel Dunbar1a551802009-07-03 00:10:29 +00001675 raw_ostream& O) {
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00001676 const std::string& Name = NewName.empty()
1677 ? ("-" + D.Name)
1678 : NewName;
Mikhail Glushenkovf8349ac2009-09-21 15:53:44 +00001679 unsigned IndentLevel1 = IndentLevel + Indent1;
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00001680
1681 switch (D.Type) {
1682 case OptionType::Switch:
Mikhail Glushenkovf8349ac2009-09-21 15:53:44 +00001683 O.indent(IndentLevel) << "vec.push_back(\"" << Name << "\");\n";
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00001684 break;
1685 case OptionType::Parameter:
Mikhail Glushenkovf8349ac2009-09-21 15:53:44 +00001686 O.indent(IndentLevel) << "vec.push_back(\"" << Name << "\");\n";
1687 O.indent(IndentLevel) << "vec.push_back(" << D.GenVariableName() << ");\n";
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00001688 break;
1689 case OptionType::Prefix:
Mikhail Glushenkovf8349ac2009-09-21 15:53:44 +00001690 O.indent(IndentLevel) << "vec.push_back(\"" << Name << "\" + "
1691 << D.GenVariableName() << ");\n";
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00001692 break;
1693 case OptionType::PrefixList:
Mikhail Glushenkovf8349ac2009-09-21 15:53:44 +00001694 O.indent(IndentLevel)
1695 << "for (" << D.GenTypeDeclaration()
1696 << "::iterator B = " << D.GenVariableName() << ".begin(),\n";
1697 O.indent(IndentLevel)
1698 << "E = " << D.GenVariableName() << ".end(); B != E;) {\n";
1699 O.indent(IndentLevel1) << "vec.push_back(\"" << Name << "\" + " << "*B);\n";
1700 O.indent(IndentLevel1) << "++B;\n";
Mikhail Glushenkov19d3e822009-01-28 03:47:20 +00001701
1702 for (int i = 1, j = D.MultiVal; i < j; ++i) {
Mikhail Glushenkovf8349ac2009-09-21 15:53:44 +00001703 O.indent(IndentLevel1) << "vec.push_back(*B);\n";
1704 O.indent(IndentLevel1) << "++B;\n";
Mikhail Glushenkov19d3e822009-01-28 03:47:20 +00001705 }
1706
Mikhail Glushenkovf8349ac2009-09-21 15:53:44 +00001707 O.indent(IndentLevel) << "}\n";
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00001708 break;
1709 case OptionType::ParameterList:
Mikhail Glushenkovf8349ac2009-09-21 15:53:44 +00001710 O.indent(IndentLevel)
1711 << "for (" << D.GenTypeDeclaration() << "::iterator B = "
1712 << D.GenVariableName() << ".begin(),\n";
1713 O.indent(IndentLevel) << "E = " << D.GenVariableName()
1714 << ".end() ; B != E;) {\n";
1715 O.indent(IndentLevel1) << "vec.push_back(\"" << Name << "\");\n";
Mikhail Glushenkov19d3e822009-01-28 03:47:20 +00001716
1717 for (int i = 0, j = D.MultiVal; i < j; ++i) {
Mikhail Glushenkovf8349ac2009-09-21 15:53:44 +00001718 O.indent(IndentLevel1) << "vec.push_back(*B);\n";
1719 O.indent(IndentLevel1) << "++B;\n";
Mikhail Glushenkov19d3e822009-01-28 03:47:20 +00001720 }
1721
Mikhail Glushenkovf8349ac2009-09-21 15:53:44 +00001722 O.indent(IndentLevel) << "}\n";
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00001723 break;
1724 case OptionType::Alias:
1725 default:
1726 throw std::string("Aliases are not allowed in tool option descriptions!");
1727 }
1728}
1729
Mikhail Glushenkovccef6de2009-10-19 21:24:28 +00001730/// ActionHandlingCallbackBase - Base class of EmitActionHandlersCallback and
1731/// EmitPreprocessOptionsCallback.
1732struct ActionHandlingCallbackBase {
1733
1734 void onErrorDag(const DagInit& d,
1735 unsigned IndentLevel, raw_ostream& O) const
1736 {
1737 O.indent(IndentLevel)
1738 << "throw std::runtime_error(\"" <<
1739 (d.getNumArgs() >= 1 ? InitPtrToString(d.getArg(0))
1740 : "Unknown error!")
1741 << "\");\n";
1742 }
1743
1744 void onWarningDag(const DagInit& d,
1745 unsigned IndentLevel, raw_ostream& O) const
1746 {
1747 checkNumberOfArguments(&d, 1);
1748 O.indent(IndentLevel) << "llvm::errs() << \""
1749 << InitPtrToString(d.getArg(0)) << "\";\n";
1750 }
1751
1752};
1753
1754/// EmitActionHandlersCallback - Emit code that handles actions. Used by
1755/// EmitGenerateActionMethod() as an argument to EmitCaseConstructHandler().
Mikhail Glushenkov632eb202009-12-07 10:51:55 +00001756class EmitActionHandlersCallback;
1757typedef void (EmitActionHandlersCallback::* EmitActionHandlersCallbackHandler)
1758(const DagInit&, unsigned, raw_ostream&) const;
1759
1760class EmitActionHandlersCallback
1761: public ActionHandlingCallbackBase,
1762 public HandlerTable<EmitActionHandlersCallbackHandler>
1763{
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00001764 const OptionDescriptions& OptDescs;
Mikhail Glushenkov632eb202009-12-07 10:51:55 +00001765 typedef EmitActionHandlersCallbackHandler Handler;
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00001766
Mikhail Glushenkov632eb202009-12-07 10:51:55 +00001767 void onAppendCmd (const DagInit& Dag,
1768 unsigned IndentLevel, raw_ostream& O) const
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00001769 {
Mikhail Glushenkov632eb202009-12-07 10:51:55 +00001770 checkNumberOfArguments(&Dag, 1);
1771 const std::string& Cmd = InitPtrToString(Dag.getArg(0));
1772 StrVector Out;
1773 llvm::SplitString(Cmd, Out);
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00001774
Mikhail Glushenkov632eb202009-12-07 10:51:55 +00001775 for (StrVector::const_iterator B = Out.begin(), E = Out.end();
1776 B != E; ++B)
1777 O.indent(IndentLevel) << "vec.push_back(\"" << *B << "\");\n";
1778 }
Mikhail Glushenkovc52551d2009-02-27 06:46:55 +00001779
Mikhail Glushenkov632eb202009-12-07 10:51:55 +00001780 void onForward (const DagInit& Dag,
1781 unsigned IndentLevel, raw_ostream& O) const
1782 {
1783 checkNumberOfArguments(&Dag, 1);
1784 const std::string& Name = InitPtrToString(Dag.getArg(0));
1785 EmitForwardOptionPropertyHandlingCode(OptDescs.FindOption(Name),
1786 IndentLevel, "", O);
1787 }
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00001788
Mikhail Glushenkov632eb202009-12-07 10:51:55 +00001789 void onForwardAs (const DagInit& Dag,
1790 unsigned IndentLevel, raw_ostream& O) const
1791 {
1792 checkNumberOfArguments(&Dag, 2);
1793 const std::string& Name = InitPtrToString(Dag.getArg(0));
1794 const std::string& NewName = InitPtrToString(Dag.getArg(1));
1795 EmitForwardOptionPropertyHandlingCode(OptDescs.FindOption(Name),
1796 IndentLevel, NewName, O);
1797 }
Mikhail Glushenkov19d3e822009-01-28 03:47:20 +00001798
Mikhail Glushenkov632eb202009-12-07 10:51:55 +00001799 void onOutputSuffix (const DagInit& Dag,
1800 unsigned IndentLevel, raw_ostream& O) const
1801 {
1802 checkNumberOfArguments(&Dag, 1);
1803 const std::string& OutSuf = InitPtrToString(Dag.getArg(0));
1804 O.indent(IndentLevel) << "output_suffix = \"" << OutSuf << "\";\n";
1805 }
1806
1807 void onStopCompilation (const DagInit& Dag,
1808 unsigned IndentLevel, raw_ostream& O) const
1809 {
1810 O.indent(IndentLevel) << "stop_compilation = true;\n";
1811 }
1812
1813
1814 void onUnpackValues (const DagInit& Dag,
1815 unsigned IndentLevel, raw_ostream& O) const
1816 {
1817 checkNumberOfArguments(&Dag, 1);
1818 const std::string& Name = InitPtrToString(Dag.getArg(0));
1819 const OptionDescription& D = OptDescs.FindOption(Name);
1820
1821 if (D.isMultiVal())
1822 throw std::string("Can't use unpack_values with multi-valued options!");
1823
1824 if (D.isList()) {
1825 O.indent(IndentLevel)
1826 << "for (" << D.GenTypeDeclaration()
1827 << "::iterator B = " << D.GenVariableName() << ".begin(),\n";
1828 O.indent(IndentLevel)
1829 << "E = " << D.GenVariableName() << ".end(); B != E; ++B)\n";
1830 O.indent(IndentLevel + Indent1)
1831 << "llvm::SplitString(*B, vec, \",\");\n";
1832 }
1833 else if (D.isParameter()){
1834 O.indent(IndentLevel) << "llvm::SplitString("
1835 << D.GenVariableName() << ", vec, \",\");\n";
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00001836 }
1837 else {
Mikhail Glushenkov632eb202009-12-07 10:51:55 +00001838 throw "Option '" + D.Name +
1839 "': switches can't have the 'unpack_values' property!";
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00001840 }
Mikhail Glushenkovb5ccfbf2008-05-30 06:10:19 +00001841 }
Mikhail Glushenkov632eb202009-12-07 10:51:55 +00001842
Mikhail Glushenkov08509492008-12-07 16:42:22 +00001843 public:
Mikhail Glushenkov632eb202009-12-07 10:51:55 +00001844
1845 explicit EmitActionHandlersCallback(const OptionDescriptions& OD)
1846 : OptDescs(OD)
1847 {
1848 if (!staticMembersInitialized_) {
1849 AddHandler("error", &EmitActionHandlersCallback::onErrorDag);
1850 AddHandler("warning", &EmitActionHandlersCallback::onWarningDag);
1851 AddHandler("append_cmd", &EmitActionHandlersCallback::onAppendCmd);
1852 AddHandler("forward", &EmitActionHandlersCallback::onForward);
1853 AddHandler("forward_as", &EmitActionHandlersCallback::onForwardAs);
1854 AddHandler("output_suffix", &EmitActionHandlersCallback::onOutputSuffix);
1855 AddHandler("stop_compilation",
1856 &EmitActionHandlersCallback::onStopCompilation);
1857 AddHandler("unpack_values",
1858 &EmitActionHandlersCallback::onUnpackValues);
1859
1860 staticMembersInitialized_ = true;
1861 }
1862 }
Mikhail Glushenkov08509492008-12-07 16:42:22 +00001863
Mikhail Glushenkovccef6de2009-10-19 21:24:28 +00001864 void operator()(const Init* Statement,
1865 unsigned IndentLevel, raw_ostream& O) const
Mikhail Glushenkov08509492008-12-07 16:42:22 +00001866 {
Mikhail Glushenkov632eb202009-12-07 10:51:55 +00001867 const DagInit& Dag = InitPtrToDag(Statement);
1868 const std::string& ActionName = GetOperatorName(Dag);
1869 Handler h = GetHandler(ActionName);
1870
1871 ((this)->*(h))(Dag, IndentLevel, O);
Mikhail Glushenkov08509492008-12-07 16:42:22 +00001872 }
Mikhail Glushenkovb5ccfbf2008-05-30 06:10:19 +00001873};
1874
Mikhail Glushenkov0b599392009-10-09 05:45:21 +00001875bool IsOutFileIndexCheckRequiredStr (const Init* CmdLine) {
1876 StrVector StrVec;
1877 TokenizeCmdline(InitPtrToString(CmdLine), StrVec);
1878
1879 for (StrVector::const_iterator I = StrVec.begin(), E = StrVec.end();
1880 I != E; ++I) {
1881 if (*I == "$OUTFILE")
1882 return false;
1883 }
1884
1885 return true;
1886}
1887
1888class IsOutFileIndexCheckRequiredStrCallback {
1889 bool* ret_;
1890
1891public:
1892 IsOutFileIndexCheckRequiredStrCallback(bool* ret) : ret_(ret)
1893 {}
1894
1895 void operator()(const Init* CmdLine) {
Mikhail Glushenkov4d21ae72009-10-18 22:51:30 +00001896 // Ignore nested 'case' DAG.
1897 if (typeid(*CmdLine) == typeid(DagInit))
1898 return;
1899
Mikhail Glushenkov0b599392009-10-09 05:45:21 +00001900 if (IsOutFileIndexCheckRequiredStr(CmdLine))
1901 *ret_ = true;
1902 }
Mikhail Glushenkov4d21ae72009-10-18 22:51:30 +00001903
1904 void operator()(const DagInit* Test, unsigned, bool) {
1905 this->operator()(Test);
1906 }
1907 void operator()(const Init* Statement, unsigned) {
1908 this->operator()(Statement);
1909 }
Mikhail Glushenkov0b599392009-10-09 05:45:21 +00001910};
1911
1912bool IsOutFileIndexCheckRequiredCase (Init* CmdLine) {
1913 bool ret = false;
1914 WalkCase(CmdLine, Id(), IsOutFileIndexCheckRequiredStrCallback(&ret));
1915 return ret;
1916}
1917
1918/// IsOutFileIndexCheckRequired - Should we emit an "out_file_index != -1" check
1919/// in EmitGenerateActionMethod() ?
1920bool IsOutFileIndexCheckRequired (Init* CmdLine) {
1921 if (typeid(*CmdLine) == typeid(StringInit))
1922 return IsOutFileIndexCheckRequiredStr(CmdLine);
1923 else
1924 return IsOutFileIndexCheckRequiredCase(CmdLine);
1925}
1926
Mikhail Glushenkov632eb202009-12-07 10:51:55 +00001927void EmitGenerateActionMethodHeader(const ToolDescription& D,
1928 bool IsJoin, raw_ostream& O)
1929{
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00001930 if (IsJoin)
Mikhail Glushenkovf8349ac2009-09-21 15:53:44 +00001931 O.indent(Indent1) << "Action GenerateAction(const PathVector& inFiles,\n";
Mikhail Glushenkovb5ccfbf2008-05-30 06:10:19 +00001932 else
Mikhail Glushenkovf8349ac2009-09-21 15:53:44 +00001933 O.indent(Indent1) << "Action GenerateAction(const sys::Path& inFile,\n";
Mikhail Glushenkovb5ccfbf2008-05-30 06:10:19 +00001934
Mikhail Glushenkovf8349ac2009-09-21 15:53:44 +00001935 O.indent(Indent2) << "bool HasChildren,\n";
1936 O.indent(Indent2) << "const llvm::sys::Path& TempDir,\n";
1937 O.indent(Indent2) << "const InputLanguagesSet& InLangs,\n";
1938 O.indent(Indent2) << "const LanguageMap& LangMap) const\n";
1939 O.indent(Indent1) << "{\n";
1940 O.indent(Indent2) << "std::string cmd;\n";
1941 O.indent(Indent2) << "std::vector<std::string> vec;\n";
1942 O.indent(Indent2) << "bool stop_compilation = !HasChildren;\n";
1943 O.indent(Indent2) << "const char* output_suffix = \""
1944 << D.OutputSuffix << "\";\n";
Mikhail Glushenkov632eb202009-12-07 10:51:55 +00001945}
1946
1947// EmitGenerateActionMethod - Emit either a normal or a "join" version of the
1948// Tool::GenerateAction() method.
1949void EmitGenerateActionMethod (const ToolDescription& D,
1950 const OptionDescriptions& OptDescs,
1951 bool IsJoin, raw_ostream& O) {
1952
1953 EmitGenerateActionMethodHeader(D, IsJoin, O);
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00001954
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00001955 if (!D.CmdLine)
1956 throw "Tool " + D.Name + " has no cmd_line property!";
Mikhail Glushenkov0b599392009-10-09 05:45:21 +00001957
1958 bool IndexCheckRequired = IsOutFileIndexCheckRequired(D.CmdLine);
1959 O.indent(Indent2) << "int out_file_index"
1960 << (IndexCheckRequired ? " = -1" : "")
1961 << ";\n\n";
1962
1963 // Process the cmd_line property.
1964 if (typeid(*D.CmdLine) == typeid(StringInit))
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00001965 EmitCmdLineVecFill(D.CmdLine, D.Name, IsJoin, Indent2, O);
1966 else
1967 EmitCaseConstructHandler(D.CmdLine, Indent2,
1968 EmitCmdLineVecFillCallback(IsJoin, D.Name),
1969 true, OptDescs, O);
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +00001970
Mikhail Glushenkov39482dd2009-10-08 04:40:08 +00001971 // For every understood option, emit handling code.
1972 if (D.Actions)
Mikhail Glushenkovd5a72d92009-10-27 09:02:49 +00001973 EmitCaseConstructHandler(D.Actions, Indent2,
1974 EmitActionHandlersCallback(OptDescs),
Mikhail Glushenkov39482dd2009-10-08 04:40:08 +00001975 false, OptDescs, O);
1976
1977 O << '\n';
1978 O.indent(Indent2)
1979 << "std::string out_file = OutFilename("
1980 << (IsJoin ? "sys::Path(),\n" : "inFile,\n");
1981 O.indent(Indent3) << "TempDir, stop_compilation, output_suffix).str();\n\n";
Mikhail Glushenkov0b599392009-10-09 05:45:21 +00001982
1983 if (IndexCheckRequired)
1984 O.indent(Indent2) << "if (out_file_index != -1)\n";
1985 O.indent(IndexCheckRequired ? Indent3 : Indent2)
1986 << "vec[out_file_index] = out_file;\n";
Mikhail Glushenkov39482dd2009-10-08 04:40:08 +00001987
Mikhail Glushenkov8e7254c2008-05-09 08:27:26 +00001988 // Handle the Sink property.
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00001989 if (D.isSink()) {
Mikhail Glushenkovf8349ac2009-09-21 15:53:44 +00001990 O.indent(Indent2) << "if (!" << SinkOptionName << ".empty()) {\n";
1991 O.indent(Indent3) << "vec.insert(vec.end(), "
1992 << SinkOptionName << ".begin(), " << SinkOptionName
1993 << ".end());\n";
1994 O.indent(Indent2) << "}\n";
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +00001995 }
1996
Mikhail Glushenkovf8349ac2009-09-21 15:53:44 +00001997 O.indent(Indent2) << "return Action(cmd, vec, stop_compilation, out_file);\n";
1998 O.indent(Indent1) << "}\n\n";
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +00001999}
2000
Mikhail Glushenkov8e7254c2008-05-09 08:27:26 +00002001/// EmitGenerateActionMethods - Emit two GenerateAction() methods for
2002/// a given Tool class.
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002003void EmitGenerateActionMethods (const ToolDescription& ToolDesc,
2004 const OptionDescriptions& OptDescs,
Daniel Dunbar1a551802009-07-03 00:10:29 +00002005 raw_ostream& O) {
Mikhail Glushenkovf8349ac2009-09-21 15:53:44 +00002006 if (!ToolDesc.isJoin()) {
2007 O.indent(Indent1) << "Action GenerateAction(const PathVector& inFiles,\n";
2008 O.indent(Indent2) << "bool HasChildren,\n";
2009 O.indent(Indent2) << "const llvm::sys::Path& TempDir,\n";
2010 O.indent(Indent2) << "const InputLanguagesSet& InLangs,\n";
2011 O.indent(Indent2) << "const LanguageMap& LangMap) const\n";
2012 O.indent(Indent1) << "{\n";
2013 O.indent(Indent2) << "throw std::runtime_error(\"" << ToolDesc.Name
2014 << " is not a Join tool!\");\n";
2015 O.indent(Indent1) << "}\n\n";
2016 }
2017 else {
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002018 EmitGenerateActionMethod(ToolDesc, OptDescs, true, O);
Mikhail Glushenkovf8349ac2009-09-21 15:53:44 +00002019 }
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +00002020
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002021 EmitGenerateActionMethod(ToolDesc, OptDescs, false, O);
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +00002022}
2023
Mikhail Glushenkov4561ab52008-05-07 21:50:19 +00002024/// EmitInOutLanguageMethods - Emit the [Input,Output]Language()
2025/// methods for a given Tool class.
Daniel Dunbar1a551802009-07-03 00:10:29 +00002026void EmitInOutLanguageMethods (const ToolDescription& D, raw_ostream& O) {
Mikhail Glushenkovf8349ac2009-09-21 15:53:44 +00002027 O.indent(Indent1) << "const char** InputLanguages() const {\n";
2028 O.indent(Indent2) << "return InputLanguages_;\n";
2029 O.indent(Indent1) << "}\n\n";
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +00002030
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002031 if (D.OutLanguage.empty())
2032 throw "Tool " + D.Name + " has no 'out_language' property!";
2033
Mikhail Glushenkovf8349ac2009-09-21 15:53:44 +00002034 O.indent(Indent1) << "const char* OutputLanguage() const {\n";
2035 O.indent(Indent2) << "return \"" << D.OutLanguage << "\";\n";
2036 O.indent(Indent1) << "}\n\n";
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +00002037}
2038
Mikhail Glushenkov4561ab52008-05-07 21:50:19 +00002039/// EmitNameMethod - Emit the Name() method for a given Tool class.
Daniel Dunbar1a551802009-07-03 00:10:29 +00002040void EmitNameMethod (const ToolDescription& D, raw_ostream& O) {
Mikhail Glushenkovf8349ac2009-09-21 15:53:44 +00002041 O.indent(Indent1) << "const char* Name() const {\n";
2042 O.indent(Indent2) << "return \"" << D.Name << "\";\n";
2043 O.indent(Indent1) << "}\n\n";
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +00002044}
2045
Mikhail Glushenkov4561ab52008-05-07 21:50:19 +00002046/// EmitIsJoinMethod - Emit the IsJoin() method for a given Tool
2047/// class.
Daniel Dunbar1a551802009-07-03 00:10:29 +00002048void EmitIsJoinMethod (const ToolDescription& D, raw_ostream& O) {
Mikhail Glushenkovf8349ac2009-09-21 15:53:44 +00002049 O.indent(Indent1) << "bool IsJoin() const {\n";
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002050 if (D.isJoin())
Mikhail Glushenkovf8349ac2009-09-21 15:53:44 +00002051 O.indent(Indent2) << "return true;\n";
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +00002052 else
Mikhail Glushenkovf8349ac2009-09-21 15:53:44 +00002053 O.indent(Indent2) << "return false;\n";
2054 O.indent(Indent1) << "}\n\n";
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +00002055}
2056
Mikhail Glushenkov5fe84752008-05-30 06:24:49 +00002057/// EmitStaticMemberDefinitions - Emit static member definitions for a
2058/// given Tool class.
Daniel Dunbar1a551802009-07-03 00:10:29 +00002059void EmitStaticMemberDefinitions(const ToolDescription& D, raw_ostream& O) {
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002060 if (D.InLanguage.empty())
2061 throw "Tool " + D.Name + " has no 'in_language' property!";
2062
2063 O << "const char* " << D.Name << "::InputLanguages_[] = {";
2064 for (StrVector::const_iterator B = D.InLanguage.begin(),
2065 E = D.InLanguage.end(); B != E; ++B)
Mikhail Glushenkov5fe84752008-05-30 06:24:49 +00002066 O << '\"' << *B << "\", ";
2067 O << "0};\n\n";
2068}
2069
Mikhail Glushenkov4561ab52008-05-07 21:50:19 +00002070/// EmitToolClassDefinition - Emit a Tool class definition.
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002071void EmitToolClassDefinition (const ToolDescription& D,
2072 const OptionDescriptions& OptDescs,
Daniel Dunbar1a551802009-07-03 00:10:29 +00002073 raw_ostream& O) {
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002074 if (D.Name == "root")
Mikhail Glushenkov0d08db02008-05-06 16:35:25 +00002075 return;
2076
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +00002077 // Header
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002078 O << "class " << D.Name << " : public ";
2079 if (D.isJoin())
Mikhail Glushenkovc74bfc92008-05-06 17:26:53 +00002080 O << "JoinTool";
2081 else
2082 O << "Tool";
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +00002083
Mikhail Glushenkovf8349ac2009-09-21 15:53:44 +00002084 O << "{\nprivate:\n";
2085 O.indent(Indent1) << "static const char* InputLanguages_[];\n\n";
Mikhail Glushenkov5fe84752008-05-30 06:24:49 +00002086
2087 O << "public:\n";
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002088 EmitNameMethod(D, O);
2089 EmitInOutLanguageMethods(D, O);
2090 EmitIsJoinMethod(D, O);
2091 EmitGenerateActionMethods(D, OptDescs, O);
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +00002092
2093 // Close class definition
Mikhail Glushenkov5fe84752008-05-30 06:24:49 +00002094 O << "};\n";
2095
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002096 EmitStaticMemberDefinitions(D, O);
Mikhail Glushenkov5fe84752008-05-30 06:24:49 +00002097
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +00002098}
2099
Mikhail Glushenkov7c8deb32009-06-23 20:45:07 +00002100/// EmitOptionDefinitions - Iterate over a list of option descriptions
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002101/// and emit registration code.
Mikhail Glushenkov7c8deb32009-06-23 20:45:07 +00002102void EmitOptionDefinitions (const OptionDescriptions& descs,
2103 bool HasSink, bool HasExterns,
Daniel Dunbar1a551802009-07-03 00:10:29 +00002104 raw_ostream& O)
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +00002105{
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002106 std::vector<OptionDescription> Aliases;
Mikhail Glushenkov6be4ffc2008-05-30 06:22:52 +00002107
Mikhail Glushenkov34f37622008-05-30 06:23:29 +00002108 // Emit static cl::Option variables.
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002109 for (OptionDescriptions::const_iterator B = descs.begin(),
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +00002110 E = descs.end(); B!=E; ++B) {
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002111 const OptionDescription& val = B->second;
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +00002112
Mikhail Glushenkov6be4ffc2008-05-30 06:22:52 +00002113 if (val.Type == OptionType::Alias) {
2114 Aliases.push_back(val);
2115 continue;
2116 }
2117
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002118 if (val.isExtern())
2119 O << "extern ";
2120
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +00002121 O << val.GenTypeDeclaration() << ' '
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002122 << val.GenVariableName();
2123
2124 if (val.isExtern()) {
2125 O << ";\n";
2126 continue;
2127 }
2128
Mikhail Glushenkov0cbb5902009-06-23 20:45:31 +00002129 O << "(\"" << val.Name << "\"\n";
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +00002130
2131 if (val.Type == OptionType::Prefix || val.Type == OptionType::PrefixList)
2132 O << ", cl::Prefix";
2133
2134 if (val.isRequired()) {
Mikhail Glushenkovcbc360d2009-07-07 16:08:11 +00002135 if (val.isList() && !val.isMultiVal())
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +00002136 O << ", cl::OneOrMore";
Mikhail Glushenkov19d3e822009-01-28 03:47:20 +00002137 else
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +00002138 O << ", cl::Required";
Mikhail Glushenkov19d3e822009-01-28 03:47:20 +00002139 }
Mikhail Glushenkovcbc360d2009-07-07 16:08:11 +00002140 else if (val.isOneOrMore() && val.isList()) {
Mikhail Glushenkov19d3e822009-01-28 03:47:20 +00002141 O << ", cl::OneOrMore";
2142 }
Mikhail Glushenkovcbc360d2009-07-07 16:08:11 +00002143 else if (val.isZeroOrOne() && val.isList()) {
Mikhail Glushenkov19d3e822009-01-28 03:47:20 +00002144 O << ", cl::ZeroOrOne";
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +00002145 }
2146
Mikhail Glushenkov19d3e822009-01-28 03:47:20 +00002147 if (val.isReallyHidden()) {
2148 O << ", cl::ReallyHidden";
Mikhail Glushenkov739c7202008-11-28 00:13:25 +00002149 }
Mikhail Glushenkov19d3e822009-01-28 03:47:20 +00002150 else if (val.isHidden()) {
2151 O << ", cl::Hidden";
2152 }
2153
2154 if (val.MultiVal > 1)
Mikhail Glushenkov8fe44472009-07-07 16:08:41 +00002155 O << ", cl::multi_val(" << val.MultiVal << ')';
2156
2157 if (val.InitVal) {
2158 const std::string& str = val.InitVal->getAsString();
2159 O << ", cl::init(" << str << ')';
2160 }
Mikhail Glushenkov739c7202008-11-28 00:13:25 +00002161
Mikhail Glushenkov6be4ffc2008-05-30 06:22:52 +00002162 if (!val.Help.empty())
2163 O << ", cl::desc(\"" << val.Help << "\")";
2164
Mikhail Glushenkov0cbb5902009-06-23 20:45:31 +00002165 O << ");\n\n";
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +00002166 }
2167
Mikhail Glushenkov6be4ffc2008-05-30 06:22:52 +00002168 // Emit the aliases (they should go after all the 'proper' options).
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002169 for (std::vector<OptionDescription>::const_iterator
Mikhail Glushenkov6be4ffc2008-05-30 06:22:52 +00002170 B = Aliases.begin(), E = Aliases.end(); B != E; ++B) {
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002171 const OptionDescription& val = *B;
Mikhail Glushenkov6be4ffc2008-05-30 06:22:52 +00002172
2173 O << val.GenTypeDeclaration() << ' '
2174 << val.GenVariableName()
2175 << "(\"" << val.Name << '\"';
2176
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002177 const OptionDescription& D = descs.FindOption(val.Help);
2178 O << ", cl::aliasopt(" << D.GenVariableName() << ")";
Mikhail Glushenkov6be4ffc2008-05-30 06:22:52 +00002179
2180 O << ", cl::desc(\"" << "An alias for -" + val.Help << "\"));\n";
2181 }
2182
2183 // Emit the sink option.
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002184 if (HasSink)
Mikhail Glushenkovb59dbad2008-12-07 16:42:47 +00002185 O << (HasExterns ? "extern cl" : "cl")
2186 << "::list<std::string> " << SinkOptionName
2187 << (HasExterns ? ";\n" : "(cl::Sink);\n");
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +00002188
2189 O << '\n';
2190}
2191
Mikhail Glushenkovccef6de2009-10-19 21:24:28 +00002192/// EmitPreprocessOptionsCallback - Helper function passed to
Mikhail Glushenkov0a22fb62009-10-17 20:09:29 +00002193/// EmitCaseConstructHandler() by EmitPreprocessOptions().
Mikhail Glushenkovccef6de2009-10-19 21:24:28 +00002194class EmitPreprocessOptionsCallback : ActionHandlingCallbackBase {
Mikhail Glushenkov0a22fb62009-10-17 20:09:29 +00002195 const OptionDescriptions& OptDescs_;
2196
2197 void onUnsetOption(Init* i, unsigned IndentLevel, raw_ostream& O) {
2198 const std::string& OptName = InitPtrToString(i);
2199 const OptionDescription& OptDesc = OptDescs_.FindOption(OptName);
Mikhail Glushenkov0a22fb62009-10-17 20:09:29 +00002200
Mikhail Glushenkovb6c34832009-10-22 04:15:07 +00002201 if (OptDesc.isSwitch()) {
Mikhail Glushenkov0a22fb62009-10-17 20:09:29 +00002202 O.indent(IndentLevel) << OptDesc.GenVariableName() << " = false;\n";
2203 }
Mikhail Glushenkovb6c34832009-10-22 04:15:07 +00002204 else if (OptDesc.isParameter()) {
Mikhail Glushenkov0a22fb62009-10-17 20:09:29 +00002205 O.indent(IndentLevel) << OptDesc.GenVariableName() << " = \"\";\n";
2206 }
Mikhail Glushenkovb6c34832009-10-22 04:15:07 +00002207 else if (OptDesc.isList()) {
2208 O.indent(IndentLevel) << OptDesc.GenVariableName() << ".clear();\n";
2209 }
Mikhail Glushenkov0a22fb62009-10-17 20:09:29 +00002210 else {
Mikhail Glushenkovb6c34832009-10-22 04:15:07 +00002211 throw "Can't apply 'unset_option' to alias option '" + OptName + "'";
Mikhail Glushenkov0a22fb62009-10-17 20:09:29 +00002212 }
2213 }
2214
2215 void processDag(const Init* I, unsigned IndentLevel, raw_ostream& O)
2216 {
2217 const DagInit& d = InitPtrToDag(I);
Mikhail Glushenkov4d21ae72009-10-18 22:51:30 +00002218 const std::string& OpName = GetOperatorName(d);
Mikhail Glushenkov0a22fb62009-10-17 20:09:29 +00002219
Mikhail Glushenkov0a22fb62009-10-17 20:09:29 +00002220 if (OpName == "warning") {
Mikhail Glushenkovccef6de2009-10-19 21:24:28 +00002221 this->onWarningDag(d, IndentLevel, O);
Mikhail Glushenkov0a22fb62009-10-17 20:09:29 +00002222 }
2223 else if (OpName == "error") {
Mikhail Glushenkovccef6de2009-10-19 21:24:28 +00002224 this->onWarningDag(d, IndentLevel, O);
Mikhail Glushenkov0a22fb62009-10-17 20:09:29 +00002225 }
2226 else if (OpName == "unset_option") {
2227 checkNumberOfArguments(&d, 1);
2228 Init* I = d.getArg(0);
2229 if (typeid(*I) == typeid(ListInit)) {
2230 const ListInit& DagList = *static_cast<const ListInit*>(I);
2231 for (ListInit::const_iterator B = DagList.begin(), E = DagList.end();
2232 B != E; ++B)
2233 this->onUnsetOption(*B, IndentLevel, O);
2234 }
2235 else {
2236 this->onUnsetOption(I, IndentLevel, O);
2237 }
2238 }
2239 else {
2240 throw "Unknown operator in the option preprocessor: '" + OpName + "'!"
2241 "\nOnly 'warning', 'error' and 'unset_option' are allowed.";
2242 }
2243 }
2244
2245public:
2246
Mikhail Glushenkov0a22fb62009-10-17 20:09:29 +00002247 void operator()(const Init* I, unsigned IndentLevel, raw_ostream& O) {
Mikhail Glushenkov0a22fb62009-10-17 20:09:29 +00002248 this->processDag(I, IndentLevel, O);
Mikhail Glushenkov0a22fb62009-10-17 20:09:29 +00002249 }
2250
Mikhail Glushenkovccef6de2009-10-19 21:24:28 +00002251 EmitPreprocessOptionsCallback(const OptionDescriptions& OptDescs)
Mikhail Glushenkov0a22fb62009-10-17 20:09:29 +00002252 : OptDescs_(OptDescs)
2253 {}
2254};
2255
2256/// EmitPreprocessOptions - Emit the PreprocessOptionsLocal() function.
2257void EmitPreprocessOptions (const RecordKeeper& Records,
2258 const OptionDescriptions& OptDecs, raw_ostream& O)
2259{
2260 O << "void PreprocessOptionsLocal() {\n";
2261
2262 const RecordVector& OptionPreprocessors =
2263 Records.getAllDerivedDefinitions("OptionPreprocessor");
2264
2265 for (RecordVector::const_iterator B = OptionPreprocessors.begin(),
2266 E = OptionPreprocessors.end(); B!=E; ++B) {
2267 DagInit* Case = (*B)->getValueAsDag("preprocessor");
Mikhail Glushenkovccef6de2009-10-19 21:24:28 +00002268 EmitCaseConstructHandler(Case, Indent1,
2269 EmitPreprocessOptionsCallback(OptDecs),
Mikhail Glushenkov0a22fb62009-10-17 20:09:29 +00002270 false, OptDecs, O);
2271 }
2272
2273 O << "}\n\n";
2274}
2275
2276/// EmitPopulateLanguageMap - Emit the PopulateLanguageMapLocal() function.
Daniel Dunbar1a551802009-07-03 00:10:29 +00002277void EmitPopulateLanguageMap (const RecordKeeper& Records, raw_ostream& O)
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +00002278{
Mikhail Glushenkovc82ce4a2008-09-22 20:49:34 +00002279 O << "void PopulateLanguageMapLocal(LanguageMap& langMap) {\n";
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +00002280
Mikhail Glushenkov01088772008-11-17 17:29:18 +00002281 // Get the relevant field out of RecordKeeper
Mikhail Glushenkovfa270772008-11-17 17:29:42 +00002282 const Record* LangMapRecord = Records.getDef("LanguageMap");
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +00002283
Mikhail Glushenkov01088772008-11-17 17:29:18 +00002284 // It is allowed for a plugin to have no language map.
2285 if (LangMapRecord) {
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +00002286
Mikhail Glushenkov01088772008-11-17 17:29:18 +00002287 ListInit* LangsToSuffixesList = LangMapRecord->getValueAsListInit("map");
2288 if (!LangsToSuffixesList)
2289 throw std::string("Error in the language map definition!");
2290
2291 for (unsigned i = 0; i < LangsToSuffixesList->size(); ++i) {
Mikhail Glushenkovfa270772008-11-17 17:29:42 +00002292 const Record* LangToSuffixes = LangsToSuffixesList->getElementAsRecord(i);
Mikhail Glushenkov01088772008-11-17 17:29:18 +00002293
2294 const std::string& Lang = LangToSuffixes->getValueAsString("lang");
2295 const ListInit* Suffixes = LangToSuffixes->getValueAsListInit("suffixes");
2296
2297 for (unsigned i = 0; i < Suffixes->size(); ++i)
Mikhail Glushenkovf8349ac2009-09-21 15:53:44 +00002298 O.indent(Indent1) << "langMap[\""
2299 << InitPtrToString(Suffixes->getElement(i))
2300 << "\"] = \"" << Lang << "\";\n";
Mikhail Glushenkov01088772008-11-17 17:29:18 +00002301 }
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +00002302 }
2303
Mikhail Glushenkove1d44b52008-12-11 10:34:18 +00002304 O << "}\n\n";
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +00002305}
2306
Mikhail Glushenkov08bd2e72008-05-30 06:12:24 +00002307/// IncDecWeight - Helper function passed to EmitCaseConstructHandler()
2308/// by EmitEdgeClass().
Mikhail Glushenkovf8349ac2009-09-21 15:53:44 +00002309void IncDecWeight (const Init* i, unsigned IndentLevel,
Daniel Dunbar1a551802009-07-03 00:10:29 +00002310 raw_ostream& O) {
Mikhail Glushenkovffcf3a12008-05-30 06:18:16 +00002311 const DagInit& d = InitPtrToDag(i);
Mikhail Glushenkov4d21ae72009-10-18 22:51:30 +00002312 const std::string& OpName = GetOperatorName(d);
Mikhail Glushenkove5557f42008-05-30 06:08:50 +00002313
Mikhail Glushenkov5c2b6b22008-12-17 02:47:01 +00002314 if (OpName == "inc_weight") {
Mikhail Glushenkovf8349ac2009-09-21 15:53:44 +00002315 O.indent(IndentLevel) << "ret += ";
Mikhail Glushenkov5c2b6b22008-12-17 02:47:01 +00002316 }
2317 else if (OpName == "dec_weight") {
Mikhail Glushenkovf8349ac2009-09-21 15:53:44 +00002318 O.indent(IndentLevel) << "ret -= ";
Mikhail Glushenkov5c2b6b22008-12-17 02:47:01 +00002319 }
2320 else if (OpName == "error") {
Mikhail Glushenkov0a22fb62009-10-17 20:09:29 +00002321 checkNumberOfArguments(&d, 1);
2322 O.indent(IndentLevel) << "throw std::runtime_error(\""
2323 << InitPtrToString(d.getArg(0))
2324 << "\");\n";
Mikhail Glushenkov5c2b6b22008-12-17 02:47:01 +00002325 return;
2326 }
Mikhail Glushenkov0a22fb62009-10-17 20:09:29 +00002327 else {
2328 throw "Unknown operator in edge properties list: '" + OpName + "'!"
Mikhail Glushenkov65ee1e62008-12-18 04:06:58 +00002329 "\nOnly 'inc_weight', 'dec_weight' and 'error' are allowed.";
Mikhail Glushenkov0a22fb62009-10-17 20:09:29 +00002330 }
Mikhail Glushenkove5557f42008-05-30 06:08:50 +00002331
2332 if (d.getNumArgs() > 0)
2333 O << InitPtrToInt(d.getArg(0)) << ";\n";
2334 else
2335 O << "2;\n";
2336
Mikhail Glushenkov29063552008-05-06 18:18:20 +00002337}
2338
Mikhail Glushenkov4561ab52008-05-07 21:50:19 +00002339/// EmitEdgeClass - Emit a single Edge# class.
Mikhail Glushenkovb5ccfbf2008-05-30 06:10:19 +00002340void EmitEdgeClass (unsigned N, const std::string& Target,
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002341 DagInit* Case, const OptionDescriptions& OptDescs,
Daniel Dunbar1a551802009-07-03 00:10:29 +00002342 raw_ostream& O) {
Mikhail Glushenkov9ef501b2008-05-06 17:23:14 +00002343
2344 // Class constructor.
2345 O << "class Edge" << N << ": public Edge {\n"
Mikhail Glushenkovf8349ac2009-09-21 15:53:44 +00002346 << "public:\n";
2347 O.indent(Indent1) << "Edge" << N << "() : Edge(\"" << Target
2348 << "\") {}\n\n";
Mikhail Glushenkov9ef501b2008-05-06 17:23:14 +00002349
Mikhail Glushenkovbb8b58d2008-05-06 18:14:24 +00002350 // Function Weight().
Mikhail Glushenkovf8349ac2009-09-21 15:53:44 +00002351 O.indent(Indent1)
2352 << "unsigned Weight(const InputLanguagesSet& InLangs) const {\n";
2353 O.indent(Indent2) << "unsigned ret = 0;\n";
Mikhail Glushenkov9ef501b2008-05-06 17:23:14 +00002354
Mikhail Glushenkove5557f42008-05-30 06:08:50 +00002355 // Handle the 'case' construct.
Mikhail Glushenkov2d0dc9a2008-05-30 06:22:15 +00002356 EmitCaseConstructHandler(Case, Indent2, IncDecWeight, false, OptDescs, O);
Mikhail Glushenkovbb8b58d2008-05-06 18:14:24 +00002357
Mikhail Glushenkovf8349ac2009-09-21 15:53:44 +00002358 O.indent(Indent2) << "return ret;\n";
2359 O.indent(Indent1) << "};\n\n};\n\n";
Mikhail Glushenkov9ef501b2008-05-06 17:23:14 +00002360}
2361
Mikhail Glushenkov08bd2e72008-05-30 06:12:24 +00002362/// EmitEdgeClasses - Emit Edge* classes that represent graph edges.
Mikhail Glushenkovad746be2008-11-28 00:13:47 +00002363void EmitEdgeClasses (const RecordVector& EdgeVector,
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002364 const OptionDescriptions& OptDescs,
Daniel Dunbar1a551802009-07-03 00:10:29 +00002365 raw_ostream& O) {
Mikhail Glushenkovad746be2008-11-28 00:13:47 +00002366 int i = 0;
Mikhail Glushenkov15b71ba2008-12-07 16:44:47 +00002367 for (RecordVector::const_iterator B = EdgeVector.begin(),
2368 E = EdgeVector.end(); B != E; ++B) {
2369 const Record* Edge = *B;
2370 const std::string& NodeB = Edge->getValueAsString("b");
Mikhail Glushenkove5557f42008-05-30 06:08:50 +00002371 DagInit* Weight = Edge->getValueAsDag("weight");
Mikhail Glushenkov0a174932008-05-06 16:36:06 +00002372
Mikhail Glushenkovad746be2008-11-28 00:13:47 +00002373 if (!isDagEmpty(Weight))
Mikhail Glushenkov15b71ba2008-12-07 16:44:47 +00002374 EmitEdgeClass(i, NodeB, Weight, OptDescs, O);
Mikhail Glushenkovad746be2008-11-28 00:13:47 +00002375 ++i;
Mikhail Glushenkov0a174932008-05-06 16:36:06 +00002376 }
2377}
2378
Mikhail Glushenkov0a22fb62009-10-17 20:09:29 +00002379/// EmitPopulateCompilationGraph - Emit the PopulateCompilationGraphLocal()
Mikhail Glushenkov4561ab52008-05-07 21:50:19 +00002380/// function.
Mikhail Glushenkovad746be2008-11-28 00:13:47 +00002381void EmitPopulateCompilationGraph (const RecordVector& EdgeVector,
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002382 const ToolDescriptions& ToolDescs,
Daniel Dunbar1a551802009-07-03 00:10:29 +00002383 raw_ostream& O)
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +00002384{
Mikhail Glushenkovc82ce4a2008-09-22 20:49:34 +00002385 O << "void PopulateCompilationGraphLocal(CompilationGraph& G) {\n";
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +00002386
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002387 for (ToolDescriptions::const_iterator B = ToolDescs.begin(),
2388 E = ToolDescs.end(); B != E; ++B)
Mikhail Glushenkovf8349ac2009-09-21 15:53:44 +00002389 O.indent(Indent1) << "G.insertNode(new " << (*B)->Name << "());\n";
Mikhail Glushenkov262d2482008-11-12 00:05:17 +00002390
Mikhail Glushenkov0d08db02008-05-06 16:35:25 +00002391 O << '\n';
2392
Mikhail Glushenkov262d2482008-11-12 00:05:17 +00002393 // Insert edges.
2394
Mikhail Glushenkovad746be2008-11-28 00:13:47 +00002395 int i = 0;
Mikhail Glushenkov15b71ba2008-12-07 16:44:47 +00002396 for (RecordVector::const_iterator B = EdgeVector.begin(),
2397 E = EdgeVector.end(); B != E; ++B) {
2398 const Record* Edge = *B;
2399 const std::string& NodeA = Edge->getValueAsString("a");
2400 const std::string& NodeB = Edge->getValueAsString("b");
Mikhail Glushenkove5557f42008-05-30 06:08:50 +00002401 DagInit* Weight = Edge->getValueAsDag("weight");
Mikhail Glushenkovd752c3f2008-05-06 16:36:50 +00002402
Mikhail Glushenkovf8349ac2009-09-21 15:53:44 +00002403 O.indent(Indent1) << "G.insertEdge(\"" << NodeA << "\", ";
Mikhail Glushenkovd752c3f2008-05-06 16:36:50 +00002404
Mikhail Glushenkove5557f42008-05-30 06:08:50 +00002405 if (isDagEmpty(Weight))
Mikhail Glushenkov15b71ba2008-12-07 16:44:47 +00002406 O << "new SimpleEdge(\"" << NodeB << "\")";
Mikhail Glushenkovd752c3f2008-05-06 16:36:50 +00002407 else
2408 O << "new Edge" << i << "()";
2409
2410 O << ");\n";
Mikhail Glushenkovad746be2008-11-28 00:13:47 +00002411 ++i;
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +00002412 }
2413
Mikhail Glushenkove1d44b52008-12-11 10:34:18 +00002414 O << "}\n\n";
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +00002415}
2416
Mikhail Glushenkov08bd2e72008-05-30 06:12:24 +00002417/// ExtractHookNames - Extract the hook names from all instances of
2418/// $CALL(HookName) in the provided command line string. Helper
2419/// function used by FillInHookNames().
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002420class ExtractHookNames {
Mikhail Glushenkova298bb72009-01-21 13:04:00 +00002421 llvm::StringMap<unsigned>& HookNames_;
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002422public:
Mikhail Glushenkova298bb72009-01-21 13:04:00 +00002423 ExtractHookNames(llvm::StringMap<unsigned>& HookNames)
2424 : HookNames_(HookNames) {}
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002425
2426 void operator()(const Init* CmdLine) {
2427 StrVector cmds;
Mikhail Glushenkov4d21ae72009-10-18 22:51:30 +00002428
2429 // Ignore nested 'case' DAG.
2430 if (typeid(*CmdLine) == typeid(DagInit))
2431 return;
2432
Mikhail Glushenkova298bb72009-01-21 13:04:00 +00002433 TokenizeCmdline(InitPtrToString(CmdLine), cmds);
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002434 for (StrVector::const_iterator B = cmds.begin(), E = cmds.end();
2435 B != E; ++B) {
2436 const std::string& cmd = *B;
Mikhail Glushenkova298bb72009-01-21 13:04:00 +00002437
2438 if (cmd == "$CALL") {
2439 unsigned NumArgs = 0;
2440 checkedIncrement(B, E, "Syntax error in $CALL invocation!");
2441 const std::string& HookName = *B;
2442
2443
2444 if (HookName.at(0) == ')')
2445 throw "$CALL invoked with no arguments!";
2446
2447 while (++B != E && B->at(0) != ')') {
2448 ++NumArgs;
2449 }
2450
2451 StringMap<unsigned>::const_iterator H = HookNames_.find(HookName);
2452
2453 if (H != HookNames_.end() && H->second != NumArgs)
2454 throw "Overloading of hooks is not allowed. Overloaded hook: "
2455 + HookName;
2456 else
2457 HookNames_[HookName] = NumArgs;
2458
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002459 }
Mikhail Glushenkov08bd2e72008-05-30 06:12:24 +00002460 }
2461 }
Mikhail Glushenkov4d21ae72009-10-18 22:51:30 +00002462
2463 void operator()(const DagInit* Test, unsigned, bool) {
2464 this->operator()(Test);
2465 }
2466 void operator()(const Init* Statement, unsigned) {
2467 this->operator()(Statement);
2468 }
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002469};
Mikhail Glushenkov2d0dc9a2008-05-30 06:22:15 +00002470
Mikhail Glushenkov08bd2e72008-05-30 06:12:24 +00002471/// FillInHookNames - Actually extract the hook names from all command
2472/// line strings. Helper function used by EmitHookDeclarations().
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002473void FillInHookNames(const ToolDescriptions& ToolDescs,
Mikhail Glushenkova298bb72009-01-21 13:04:00 +00002474 llvm::StringMap<unsigned>& HookNames)
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002475{
Mikhail Glushenkov2d0dc9a2008-05-30 06:22:15 +00002476 // For all command lines:
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002477 for (ToolDescriptions::const_iterator B = ToolDescs.begin(),
2478 E = ToolDescs.end(); B != E; ++B) {
2479 const ToolDescription& D = *(*B);
2480 if (!D.CmdLine)
Mikhail Glushenkov08bd2e72008-05-30 06:12:24 +00002481 continue;
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002482 if (dynamic_cast<StringInit*>(D.CmdLine))
Mikhail Glushenkov08bd2e72008-05-30 06:12:24 +00002483 // This is a string.
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002484 ExtractHookNames(HookNames).operator()(D.CmdLine);
Mikhail Glushenkov2d0dc9a2008-05-30 06:22:15 +00002485 else
Mikhail Glushenkov08bd2e72008-05-30 06:12:24 +00002486 // This is a 'case' construct.
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002487 WalkCase(D.CmdLine, Id(), ExtractHookNames(HookNames));
Mikhail Glushenkov08bd2e72008-05-30 06:12:24 +00002488 }
2489}
2490
2491/// EmitHookDeclarations - Parse CmdLine fields of all the tool
2492/// property records and emit hook function declaration for each
2493/// instance of $CALL(HookName).
Daniel Dunbar1a551802009-07-03 00:10:29 +00002494void EmitHookDeclarations(const ToolDescriptions& ToolDescs, raw_ostream& O) {
Mikhail Glushenkova298bb72009-01-21 13:04:00 +00002495 llvm::StringMap<unsigned> HookNames;
2496
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002497 FillInHookNames(ToolDescs, HookNames);
Mikhail Glushenkov08bd2e72008-05-30 06:12:24 +00002498 if (HookNames.empty())
2499 return;
Mikhail Glushenkov08bd2e72008-05-30 06:12:24 +00002500
2501 O << "namespace hooks {\n";
Mikhail Glushenkova298bb72009-01-21 13:04:00 +00002502 for (StringMap<unsigned>::const_iterator B = HookNames.begin(),
2503 E = HookNames.end(); B != E; ++B) {
Mikhail Glushenkovf8349ac2009-09-21 15:53:44 +00002504 O.indent(Indent1) << "std::string " << B->first() << "(";
Mikhail Glushenkov08bd2e72008-05-30 06:12:24 +00002505
Mikhail Glushenkova298bb72009-01-21 13:04:00 +00002506 for (unsigned i = 0, j = B->second; i < j; ++i) {
2507 O << "const char* Arg" << i << (i+1 == j ? "" : ", ");
2508 }
2509
2510 O <<");\n";
2511 }
Mikhail Glushenkov08bd2e72008-05-30 06:12:24 +00002512 O << "}\n\n";
2513}
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +00002514
Mikhail Glushenkovc82ce4a2008-09-22 20:49:34 +00002515/// EmitRegisterPlugin - Emit code to register this plugin.
Daniel Dunbar1a551802009-07-03 00:10:29 +00002516void EmitRegisterPlugin(int Priority, raw_ostream& O) {
Mikhail Glushenkovf8349ac2009-09-21 15:53:44 +00002517 O << "struct Plugin : public llvmc::BasePlugin {\n\n";
2518 O.indent(Indent1) << "int Priority() const { return "
2519 << Priority << "; }\n\n";
Mikhail Glushenkov0a22fb62009-10-17 20:09:29 +00002520 O.indent(Indent1) << "void PreprocessOptions() const\n";
2521 O.indent(Indent1) << "{ PreprocessOptionsLocal(); }\n\n";
Mikhail Glushenkovf8349ac2009-09-21 15:53:44 +00002522 O.indent(Indent1) << "void PopulateLanguageMap(LanguageMap& langMap) const\n";
2523 O.indent(Indent1) << "{ PopulateLanguageMapLocal(langMap); }\n\n";
2524 O.indent(Indent1)
2525 << "void PopulateCompilationGraph(CompilationGraph& graph) const\n";
2526 O.indent(Indent1) << "{ PopulateCompilationGraphLocal(graph); }\n"
2527 << "};\n\n"
2528 << "static llvmc::RegisterPlugin<Plugin> RP;\n\n";
Mikhail Glushenkovc82ce4a2008-09-22 20:49:34 +00002529}
2530
Mikhail Glushenkov67665722008-11-12 12:41:18 +00002531/// EmitIncludes - Emit necessary #include directives and some
2532/// additional declarations.
Daniel Dunbar1a551802009-07-03 00:10:29 +00002533void EmitIncludes(raw_ostream& O) {
Mikhail Glushenkovad981bf2009-09-28 01:16:42 +00002534 O << "#include \"llvm/CompilerDriver/BuiltinOptions.h\"\n"
2535 << "#include \"llvm/CompilerDriver/CompilationGraph.h\"\n"
Mikhail Glushenkovd80d8692009-06-23 20:46:48 +00002536 << "#include \"llvm/CompilerDriver/ForceLinkageMacros.h\"\n"
Mikhail Glushenkov4a1a77c2008-09-22 20:50:40 +00002537 << "#include \"llvm/CompilerDriver/Plugin.h\"\n"
2538 << "#include \"llvm/CompilerDriver/Tool.h\"\n\n"
Mikhail Glushenkovc82ce4a2008-09-22 20:49:34 +00002539
2540 << "#include \"llvm/ADT/StringExtras.h\"\n"
Mikhail Glushenkov0a22fb62009-10-17 20:09:29 +00002541 << "#include \"llvm/Support/CommandLine.h\"\n"
2542 << "#include \"llvm/Support/raw_ostream.h\"\n\n"
Mikhail Glushenkovc82ce4a2008-09-22 20:49:34 +00002543
2544 << "#include <cstdlib>\n"
2545 << "#include <stdexcept>\n\n"
2546
2547 << "using namespace llvm;\n"
2548 << "using namespace llvmc;\n\n"
2549
Mikhail Glushenkov67665722008-11-12 12:41:18 +00002550 << "extern cl::opt<std::string> OutputFilename;\n\n"
2551
2552 << "inline const char* checkCString(const char* s)\n"
2553 << "{ return s == NULL ? \"\" : s; }\n\n";
Mikhail Glushenkovc82ce4a2008-09-22 20:49:34 +00002554}
2555
Mikhail Glushenkovfa270772008-11-17 17:29:42 +00002556
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002557/// PluginData - Holds all information about a plugin.
2558struct PluginData {
2559 OptionDescriptions OptDescs;
2560 bool HasSink;
Mikhail Glushenkovb59dbad2008-12-07 16:42:47 +00002561 bool HasExterns;
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002562 ToolDescriptions ToolDescs;
2563 RecordVector Edges;
2564 int Priority;
Mikhail Glushenkovfa270772008-11-17 17:29:42 +00002565};
2566
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002567/// HasSink - Go through the list of tool descriptions and check if
Mikhail Glushenkovb59dbad2008-12-07 16:42:47 +00002568/// there are any with the 'sink' property set.
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002569bool HasSink(const ToolDescriptions& ToolDescs) {
2570 for (ToolDescriptions::const_iterator B = ToolDescs.begin(),
2571 E = ToolDescs.end(); B != E; ++B)
2572 if ((*B)->isSink())
2573 return true;
Mikhail Glushenkovfa270772008-11-17 17:29:42 +00002574
Mikhail Glushenkovb59dbad2008-12-07 16:42:47 +00002575 return false;
2576}
2577
2578/// HasExterns - Go through the list of option descriptions and check
2579/// if there are any external options.
2580bool HasExterns(const OptionDescriptions& OptDescs) {
2581 for (OptionDescriptions::const_iterator B = OptDescs.begin(),
2582 E = OptDescs.end(); B != E; ++B)
2583 if (B->second.isExtern())
2584 return true;
2585
2586 return false;
Mikhail Glushenkovfa270772008-11-17 17:29:42 +00002587}
2588
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002589/// CollectPluginData - Collect tool and option properties,
2590/// compilation graph edges and plugin priority from the parse tree.
2591void CollectPluginData (const RecordKeeper& Records, PluginData& Data) {
2592 // Collect option properties.
2593 const RecordVector& OptionLists =
2594 Records.getAllDerivedDefinitions("OptionList");
2595 CollectOptionDescriptions(OptionLists.begin(), OptionLists.end(),
2596 Data.OptDescs);
2597
2598 // Collect tool properties.
2599 const RecordVector& Tools = Records.getAllDerivedDefinitions("Tool");
2600 CollectToolDescriptions(Tools.begin(), Tools.end(), Data.ToolDescs);
2601 Data.HasSink = HasSink(Data.ToolDescs);
Mikhail Glushenkovb59dbad2008-12-07 16:42:47 +00002602 Data.HasExterns = HasExterns(Data.OptDescs);
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002603
2604 // Collect compilation graph edges.
2605 const RecordVector& CompilationGraphs =
2606 Records.getAllDerivedDefinitions("CompilationGraph");
2607 FillInEdgeVector(CompilationGraphs.begin(), CompilationGraphs.end(),
2608 Data.Edges);
2609
2610 // Calculate the priority of this plugin.
2611 const RecordVector& Priorities =
2612 Records.getAllDerivedDefinitions("PluginPriority");
2613 Data.Priority = CalculatePriority(Priorities.begin(), Priorities.end());
Mikhail Glushenkov35fde152008-11-17 17:30:25 +00002614}
2615
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002616/// CheckPluginData - Perform some sanity checks on the collected data.
2617void CheckPluginData(PluginData& Data) {
2618 // Filter out all tools not mentioned in the compilation graph.
2619 FilterNotInGraph(Data.Edges, Data.ToolDescs);
Mikhail Glushenkovad746be2008-11-28 00:13:47 +00002620
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002621 // Typecheck the compilation graph.
2622 TypecheckGraph(Data.Edges, Data.ToolDescs);
2623
2624 // Check that there are no options without side effects (specified
2625 // only in the OptionList).
2626 CheckForSuperfluousOptions(Data.Edges, Data.ToolDescs, Data.OptDescs);
2627
Mikhail Glushenkovad746be2008-11-28 00:13:47 +00002628}
2629
Daniel Dunbar1a551802009-07-03 00:10:29 +00002630void EmitPluginCode(const PluginData& Data, raw_ostream& O) {
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002631 // Emit file header.
2632 EmitIncludes(O);
2633
2634 // Emit global option registration code.
Mikhail Glushenkov7c8deb32009-06-23 20:45:07 +00002635 EmitOptionDefinitions(Data.OptDescs, Data.HasSink, Data.HasExterns, O);
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002636
2637 // Emit hook declarations.
2638 EmitHookDeclarations(Data.ToolDescs, O);
2639
Mikhail Glushenkove1d44b52008-12-11 10:34:18 +00002640 O << "namespace {\n\n";
2641
Mikhail Glushenkov0a22fb62009-10-17 20:09:29 +00002642 // Emit PreprocessOptionsLocal() function.
2643 EmitPreprocessOptions(Records, Data.OptDescs, O);
2644
2645 // Emit PopulateLanguageMapLocal() function
2646 // (language map maps from file extensions to language names).
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002647 EmitPopulateLanguageMap(Records, O);
2648
2649 // Emit Tool classes.
2650 for (ToolDescriptions::const_iterator B = Data.ToolDescs.begin(),
2651 E = Data.ToolDescs.end(); B!=E; ++B)
2652 EmitToolClassDefinition(*(*B), Data.OptDescs, O);
2653
2654 // Emit Edge# classes.
2655 EmitEdgeClasses(Data.Edges, Data.OptDescs, O);
2656
Mikhail Glushenkov0a22fb62009-10-17 20:09:29 +00002657 // Emit PopulateCompilationGraphLocal() function.
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002658 EmitPopulateCompilationGraph(Data.Edges, Data.ToolDescs, O);
2659
2660 // Emit code for plugin registration.
2661 EmitRegisterPlugin(Data.Priority, O);
2662
Mikhail Glushenkovd80d8692009-06-23 20:46:48 +00002663 O << "} // End anonymous namespace.\n\n";
2664
2665 // Force linkage magic.
2666 O << "namespace llvmc {\n";
2667 O << "LLVMC_FORCE_LINKAGE_DECL(LLVMC_PLUGIN_NAME) {}\n";
2668 O << "}\n";
2669
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002670 // EOF
2671}
2672
2673
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +00002674// End of anonymous namespace
Mikhail Glushenkov895820d2008-05-06 18:12:03 +00002675}
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +00002676
Mikhail Glushenkov4561ab52008-05-07 21:50:19 +00002677/// run - The back-end entry point.
Daniel Dunbar1a551802009-07-03 00:10:29 +00002678void LLVMCConfigurationEmitter::run (raw_ostream &O) {
Mikhail Glushenkov4fb71ea2008-05-30 06:21:48 +00002679 try {
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002680 PluginData Data;
Mikhail Glushenkov4561ab52008-05-07 21:50:19 +00002681
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002682 CollectPluginData(Records, Data);
2683 CheckPluginData(Data);
2684
Mikhail Glushenkovbe9d9a12008-05-06 18:08:59 +00002685 EmitSourceFileHeader("LLVMC Configuration Library", O);
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002686 EmitPluginCode(Data, O);
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +00002687
Mikhail Glushenkov4fb71ea2008-05-30 06:21:48 +00002688 } catch (std::exception& Error) {
2689 throw Error.what() + std::string(" - usually this means a syntax error.");
2690 }
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +00002691}