blob: 2abc94bbcdad2f4495b73ecc75ad27fb2ed26489 [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"
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +000018#include "llvm/ADT/StringMap.h"
Mikhail Glushenkovffcf3a12008-05-30 06:18:16 +000019#include "llvm/ADT/StringSet.h"
Mikhail Glushenkove0b65702009-12-23 12:49:30 +000020
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +000021#include <algorithm>
22#include <cassert>
23#include <functional>
Mikhail Glushenkov4fb71ea2008-05-30 06:21:48 +000024#include <stdexcept>
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +000025#include <string>
Chris Lattner32a9e7a2008-06-04 04:46:14 +000026#include <typeinfo>
Mikhail Glushenkovaa4774c2008-11-12 00:04:46 +000027
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +000028using namespace llvm;
29
Mikhail Glushenkov2d366a22009-12-17 07:48:34 +000030namespace {
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.
Mikhail Glushenkov2d366a22009-12-17 07:48:34 +000042const unsigned TabWidth = 4;
43const unsigned Indent1 = TabWidth*1;
44const unsigned Indent2 = TabWidth*2;
45const unsigned Indent3 = TabWidth*3;
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +000046
Mikhail Glushenkov4561ab52008-05-07 21:50:19 +000047// Default help string.
Mikhail Glushenkov2d366a22009-12-17 07:48:34 +000048const 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.
Mikhail Glushenkov2d366a22009-12-17 07:48:34 +000051const char * const SinkOptionName = "AutoGeneratedSinkOption";
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +000052
53//===----------------------------------------------------------------------===//
54/// Helper functions
55
Mikhail Glushenkovf9152532008-12-07 16:41:11 +000056/// Id - An 'identity' function object.
57struct Id {
Mikhail Glushenkov4d21ae72009-10-18 22:51:30 +000058 template<typename T0>
59 void operator()(const T0&) const {
60 }
61 template<typename T0, typename T1>
62 void operator()(const T0&, const T1&) const {
63 }
64 template<typename T0, typename T1, typename T2>
65 void operator()(const T0&, const T1&, const T2&) const {
Mikhail Glushenkovf9152532008-12-07 16:41:11 +000066 }
67};
68
Mikhail Glushenkovb5ccfbf2008-05-30 06:10:19 +000069int InitPtrToInt(const Init* ptr) {
70 const IntInit& val = dynamic_cast<const IntInit&>(*ptr);
Mikhail Glushenkov29063552008-05-06 18:18:20 +000071 return val.getValue();
72}
73
Mikhail Glushenkovffcf3a12008-05-30 06:18:16 +000074const std::string& InitPtrToString(const Init* ptr) {
75 const StringInit& val = dynamic_cast<const StringInit&>(*ptr);
76 return val.getValue();
77}
78
79const ListInit& InitPtrToList(const Init* ptr) {
80 const ListInit& val = dynamic_cast<const ListInit&>(*ptr);
81 return val;
82}
83
84const DagInit& InitPtrToDag(const Init* ptr) {
Mikhail Glushenkovb5ccfbf2008-05-30 06:10:19 +000085 const DagInit& val = dynamic_cast<const DagInit&>(*ptr);
Mikhail Glushenkov29063552008-05-06 18:18:20 +000086 return val;
87}
88
Mikhail Glushenkov4d21ae72009-10-18 22:51:30 +000089const std::string GetOperatorName(const DagInit& D) {
Mikhail Glushenkov24723282009-12-17 07:48:49 +000090 return D.getOperator()->getAsString();
Mikhail Glushenkov4d21ae72009-10-18 22:51:30 +000091}
92
Mikhail Glushenkove0b65702009-12-23 12:49:30 +000093/// CheckBooleanConstant - Check that the provided value is a boolean constant.
94void CheckBooleanConstant(const Init* I) {
95 const DefInit& val = dynamic_cast<const DefInit&>(*I);
96 const std::string& str = val.getAsString();
97
98 if (str != "true" && str != "false") {
99 throw "Incorrect boolean value: '" + str +
100 "': must be either 'true' or 'false'";
101 }
102}
103
Mikhail Glushenkov9bef1bd2009-12-23 12:49:41 +0000104// CheckNumberOfArguments - Ensure that the number of args in d is
Mikhail Glushenkovb7970002009-07-07 16:07:36 +0000105// greater than or equal to min_arguments, otherwise throw an exception.
Mikhail Glushenkov9bef1bd2009-12-23 12:49:41 +0000106void CheckNumberOfArguments (const DagInit& d, unsigned minArgs) {
Mikhail Glushenkov24723282009-12-17 07:48:49 +0000107 if (d.getNumArgs() < minArgs)
108 throw GetOperatorName(d) + ": too few arguments!";
Mikhail Glushenkov8245a1d2009-12-07 17:03:05 +0000109}
Mikhail Glushenkov581936a2008-05-06 17:22:03 +0000110
Mikhail Glushenkov9bef1bd2009-12-23 12:49:41 +0000111// IsDagEmpty - is this DAG marked with an empty marker?
112bool IsDagEmpty (const DagInit& d) {
Mikhail Glushenkov4d21ae72009-10-18 22:51:30 +0000113 return GetOperatorName(d) == "empty_dag_marker";
Mikhail Glushenkove5557f42008-05-30 06:08:50 +0000114}
Mikhail Glushenkov581936a2008-05-06 17:22:03 +0000115
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000116// EscapeVariableName - Escape commas and other symbols not allowed
117// in the C++ variable names. Makes it possible to use options named
118// like "Wa," (useful for prefix options).
Mikhail Glushenkovae779382010-01-26 14:55:04 +0000119std::string EscapeVariableName (const std::string& Var) {
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000120 std::string ret;
121 for (unsigned i = 0; i != Var.size(); ++i) {
122 char cur_char = Var[i];
123 if (cur_char == ',') {
124 ret += "_comma_";
125 }
126 else if (cur_char == '+') {
127 ret += "_plus_";
128 }
129 else if (cur_char == '-') {
130 ret += "_dash_";
131 }
132 else {
133 ret.push_back(cur_char);
134 }
135 }
136 return ret;
137}
138
Mikhail Glushenkovae779382010-01-26 14:55:04 +0000139/// EscapeQuotes - Replace '"' with '\"'.
140std::string EscapeQuotes (const std::string& Var) {
141 std::string ret;
142 for (unsigned i = 0; i != Var.size(); ++i) {
143 char cur_char = Var[i];
144 if (cur_char == '"') {
145 ret += "\\\"";
146 }
147 else {
148 ret.push_back(cur_char);
149 }
150 }
151 return ret;
152}
153
Mikhail Glushenkov9bef1bd2009-12-23 12:49:41 +0000154/// OneOf - Does the input string contain this character?
155bool OneOf(const char* lst, char c) {
Mikhail Glushenkova298bb72009-01-21 13:04:00 +0000156 while (*lst) {
157 if (*lst++ == c)
158 return true;
159 }
160 return false;
161}
162
Mikhail Glushenkov19d3e822009-01-28 03:47:20 +0000163template <class I, class S>
Mikhail Glushenkov9bef1bd2009-12-23 12:49:41 +0000164void CheckedIncrement(I& P, I E, S ErrorString) {
Mikhail Glushenkov19d3e822009-01-28 03:47:20 +0000165 ++P;
166 if (P == E)
167 throw ErrorString;
168}
169
Mikhail Glushenkov4858a1d2009-10-21 02:13:13 +0000170// apply is needed because C++'s syntax doesn't let us construct a function
171// object and call it in the same statement.
172template<typename F, typename T0>
173void apply(F Fun, T0& Arg0) {
174 return Fun(Arg0);
175}
176
177template<typename F, typename T0, typename T1>
178void apply(F Fun, T0& Arg0, T1& Arg1) {
179 return Fun(Arg0, Arg1);
180}
181
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +0000182//===----------------------------------------------------------------------===//
183/// Back-end specific code
184
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +0000185
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000186/// OptionType - One of six different option types. See the
187/// documentation for detailed description of differences.
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +0000188namespace OptionType {
Mikhail Glushenkovcbc360d2009-07-07 16:08:11 +0000189
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000190 enum OptionType { Alias, Switch, Parameter, ParameterList,
Mikhail Glushenkovb4ced5a2008-12-07 16:47:12 +0000191 Prefix, PrefixList};
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000192
Mikhail Glushenkov4858a1d2009-10-21 02:13:13 +0000193 bool IsAlias(OptionType t) {
194 return (t == Alias);
195 }
196
Mikhail Glushenkovcbc360d2009-07-07 16:08:11 +0000197 bool IsList (OptionType t) {
198 return (t == ParameterList || t == PrefixList);
199 }
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +0000200
Mikhail Glushenkovcbc360d2009-07-07 16:08:11 +0000201 bool IsSwitch (OptionType t) {
202 return (t == Switch);
203 }
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +0000204
Mikhail Glushenkovcbc360d2009-07-07 16:08:11 +0000205 bool IsParameter (OptionType t) {
206 return (t == Parameter || t == Prefix);
207 }
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +0000208
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000209}
210
211OptionType::OptionType stringToOptionType(const std::string& T) {
212 if (T == "alias_option")
213 return OptionType::Alias;
214 else if (T == "switch_option")
215 return OptionType::Switch;
216 else if (T == "parameter_option")
217 return OptionType::Parameter;
218 else if (T == "parameter_list_option")
219 return OptionType::ParameterList;
220 else if (T == "prefix_option")
221 return OptionType::Prefix;
222 else if (T == "prefix_list_option")
223 return OptionType::PrefixList;
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000224 else
225 throw "Unknown option type: " + T + '!';
226}
227
228namespace OptionDescriptionFlags {
229 enum OptionDescriptionFlags { Required = 0x1, Hidden = 0x2,
Mikhail Glushenkov19d3e822009-01-28 03:47:20 +0000230 ReallyHidden = 0x4, Extern = 0x8,
Mikhail Glushenkove4ac23a2009-12-15 03:04:52 +0000231 OneOrMore = 0x10, Optional = 0x20,
Mikhail Glushenkov5b9b3ba2009-12-07 18:25:54 +0000232 CommaSeparated = 0x40 };
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000233}
234
235/// OptionDescription - Represents data contained in a single
236/// OptionList entry.
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +0000237struct OptionDescription {
238 OptionType::OptionType Type;
239 std::string Name;
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000240 unsigned Flags;
241 std::string Help;
Mikhail Glushenkov19d3e822009-01-28 03:47:20 +0000242 unsigned MultiVal;
Mikhail Glushenkov8fe44472009-07-07 16:08:41 +0000243 Init* InitVal;
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +0000244
245 OptionDescription(OptionType::OptionType t = OptionType::Switch,
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000246 const std::string& n = "",
247 const std::string& h = DefaultHelpString)
Mikhail Glushenkov8fe44472009-07-07 16:08:41 +0000248 : Type(t), Name(n), Flags(0x0), Help(h), MultiVal(1), InitVal(0)
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +0000249 {}
250
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000251 /// GenTypeDeclaration - Returns the C++ variable type of this
252 /// option.
253 const char* GenTypeDeclaration() const;
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +0000254
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000255 /// GenVariableName - Returns the variable name used in the
256 /// generated C++ code.
257 std::string GenVariableName() const;
Mikhail Glushenkov739c7202008-11-28 00:13:25 +0000258
Mikhail Glushenkov4561ab52008-05-07 21:50:19 +0000259 /// Merge - Merge two option descriptions.
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000260 void Merge (const OptionDescription& other);
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +0000261
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000262 // Misc convenient getters/setters.
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +0000263
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000264 bool isAlias() const;
Mikhail Glushenkovb4ced5a2008-12-07 16:47:12 +0000265
Mikhail Glushenkov19d3e822009-01-28 03:47:20 +0000266 bool isMultiVal() const;
267
Mikhail Glushenkov5b9b3ba2009-12-07 18:25:54 +0000268 bool isCommaSeparated() const;
269 void setCommaSeparated();
270
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000271 bool isExtern() const;
Mikhail Glushenkovb4ced5a2008-12-07 16:47:12 +0000272 void setExtern();
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000273
274 bool isRequired() const;
275 void setRequired();
276
Mikhail Glushenkov19d3e822009-01-28 03:47:20 +0000277 bool isOneOrMore() const;
278 void setOneOrMore();
279
Mikhail Glushenkove4ac23a2009-12-15 03:04:52 +0000280 bool isOptional() const;
281 void setOptional();
Mikhail Glushenkov19d3e822009-01-28 03:47:20 +0000282
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000283 bool isHidden() const;
284 void setHidden();
285
286 bool isReallyHidden() const;
287 void setReallyHidden();
Mikhail Glushenkov19d3e822009-01-28 03:47:20 +0000288
Mikhail Glushenkovcbc360d2009-07-07 16:08:11 +0000289 bool isSwitch() const
290 { return OptionType::IsSwitch(this->Type); }
291
Mikhail Glushenkov4858a1d2009-10-21 02:13:13 +0000292 bool isParameter() const
293 { return OptionType::IsParameter(this->Type); }
294
Mikhail Glushenkovcbc360d2009-07-07 16:08:11 +0000295 bool isList() const
296 { return OptionType::IsList(this->Type); }
297
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +0000298};
299
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000300void OptionDescription::Merge (const OptionDescription& other)
301{
302 if (other.Type != Type)
303 throw "Conflicting definitions for the option " + Name + "!";
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +0000304
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000305 if (Help == other.Help || Help == DefaultHelpString)
306 Help = other.Help;
307 else if (other.Help != DefaultHelpString) {
Daniel Dunbar1a551802009-07-03 00:10:29 +0000308 llvm::errs() << "Warning: several different help strings"
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000309 " defined for option " + Name + "\n";
310 }
311
312 Flags |= other.Flags;
313}
314
315bool OptionDescription::isAlias() const {
Mikhail Glushenkov4858a1d2009-10-21 02:13:13 +0000316 return OptionType::IsAlias(this->Type);
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000317}
318
Mikhail Glushenkov19d3e822009-01-28 03:47:20 +0000319bool OptionDescription::isMultiVal() const {
Mikhail Glushenkov57cd67f2009-01-28 03:47:58 +0000320 return MultiVal > 1;
Mikhail Glushenkov19d3e822009-01-28 03:47:20 +0000321}
322
Mikhail Glushenkov5b9b3ba2009-12-07 18:25:54 +0000323bool OptionDescription::isCommaSeparated() const {
324 return Flags & OptionDescriptionFlags::CommaSeparated;
325}
326void OptionDescription::setCommaSeparated() {
327 Flags |= OptionDescriptionFlags::CommaSeparated;
328}
329
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000330bool OptionDescription::isExtern() const {
Mikhail Glushenkovb4ced5a2008-12-07 16:47:12 +0000331 return Flags & OptionDescriptionFlags::Extern;
332}
333void OptionDescription::setExtern() {
334 Flags |= OptionDescriptionFlags::Extern;
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000335}
336
337bool OptionDescription::isRequired() const {
338 return Flags & OptionDescriptionFlags::Required;
339}
340void OptionDescription::setRequired() {
341 Flags |= OptionDescriptionFlags::Required;
342}
343
Mikhail Glushenkov19d3e822009-01-28 03:47:20 +0000344bool OptionDescription::isOneOrMore() const {
345 return Flags & OptionDescriptionFlags::OneOrMore;
346}
347void OptionDescription::setOneOrMore() {
348 Flags |= OptionDescriptionFlags::OneOrMore;
349}
350
Mikhail Glushenkove4ac23a2009-12-15 03:04:52 +0000351bool OptionDescription::isOptional() const {
352 return Flags & OptionDescriptionFlags::Optional;
Mikhail Glushenkov19d3e822009-01-28 03:47:20 +0000353}
Mikhail Glushenkove4ac23a2009-12-15 03:04:52 +0000354void OptionDescription::setOptional() {
355 Flags |= OptionDescriptionFlags::Optional;
Mikhail Glushenkov19d3e822009-01-28 03:47:20 +0000356}
357
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000358bool OptionDescription::isHidden() const {
359 return Flags & OptionDescriptionFlags::Hidden;
360}
361void OptionDescription::setHidden() {
362 Flags |= OptionDescriptionFlags::Hidden;
363}
364
365bool OptionDescription::isReallyHidden() const {
366 return Flags & OptionDescriptionFlags::ReallyHidden;
367}
368void OptionDescription::setReallyHidden() {
369 Flags |= OptionDescriptionFlags::ReallyHidden;
370}
371
372const char* OptionDescription::GenTypeDeclaration() const {
373 switch (Type) {
374 case OptionType::Alias:
375 return "cl::alias";
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000376 case OptionType::PrefixList:
377 case OptionType::ParameterList:
378 return "cl::list<std::string>";
379 case OptionType::Switch:
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000380 return "cl::opt<bool>";
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000381 case OptionType::Parameter:
382 case OptionType::Prefix:
383 default:
384 return "cl::opt<std::string>";
385 }
386}
387
388std::string OptionDescription::GenVariableName() const {
389 const std::string& EscapedName = EscapeVariableName(Name);
390 switch (Type) {
391 case OptionType::Alias:
392 return "AutoGeneratedAlias_" + EscapedName;
393 case OptionType::PrefixList:
394 case OptionType::ParameterList:
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000395 return "AutoGeneratedList_" + EscapedName;
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000396 case OptionType::Switch:
397 return "AutoGeneratedSwitch_" + EscapedName;
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000398 case OptionType::Prefix:
399 case OptionType::Parameter:
400 default:
401 return "AutoGeneratedParameter_" + EscapedName;
402 }
403}
404
405/// OptionDescriptions - An OptionDescription array plus some helper
406/// functions.
407class OptionDescriptions {
408 typedef StringMap<OptionDescription> container_type;
409
410 /// Descriptions - A list of OptionDescriptions.
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +0000411 container_type Descriptions;
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +0000412
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000413public:
Mikhail Glushenkova7d0ae32008-05-30 06:28:37 +0000414 /// FindOption - exception-throwing wrapper for find().
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000415 const OptionDescription& FindOption(const std::string& OptName) const;
Mikhail Glushenkov4858a1d2009-10-21 02:13:13 +0000416
417 // Wrappers for FindOption that throw an exception in case the option has a
418 // wrong type.
Mikhail Glushenkov0a22fb62009-10-17 20:09:29 +0000419 const OptionDescription& FindSwitch(const std::string& OptName) const;
Mikhail Glushenkov4858a1d2009-10-21 02:13:13 +0000420 const OptionDescription& FindParameter(const std::string& OptName) const;
421 const OptionDescription& FindList(const std::string& OptName) const;
422 const OptionDescription&
423 FindListOrParameter(const std::string& OptName) const;
Mikhail Glushenkov581936a2008-05-06 17:22:03 +0000424
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000425 /// insertDescription - Insert new OptionDescription into
426 /// OptionDescriptions list
427 void InsertDescription (const OptionDescription& o);
Mikhail Glushenkov09b51c32008-05-30 06:27:02 +0000428
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +0000429 // Support for STL-style iteration
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000430 typedef container_type::const_iterator const_iterator;
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +0000431 const_iterator begin() const { return Descriptions.begin(); }
432 const_iterator end() const { return Descriptions.end(); }
433};
434
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000435const OptionDescription&
Mikhail Glushenkov4858a1d2009-10-21 02:13:13 +0000436OptionDescriptions::FindOption(const std::string& OptName) const {
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000437 const_iterator I = Descriptions.find(OptName);
438 if (I != Descriptions.end())
439 return I->second;
440 else
441 throw OptName + ": no such option!";
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +0000442}
443
Mikhail Glushenkov0a22fb62009-10-17 20:09:29 +0000444const OptionDescription&
Mikhail Glushenkov4858a1d2009-10-21 02:13:13 +0000445OptionDescriptions::FindSwitch(const std::string& OptName) const {
Mikhail Glushenkov0a22fb62009-10-17 20:09:29 +0000446 const OptionDescription& OptDesc = this->FindOption(OptName);
447 if (!OptDesc.isSwitch())
448 throw OptName + ": incorrect option type - should be a switch!";
449 return OptDesc;
450}
451
Mikhail Glushenkov4858a1d2009-10-21 02:13:13 +0000452const OptionDescription&
453OptionDescriptions::FindList(const std::string& OptName) const {
454 const OptionDescription& OptDesc = this->FindOption(OptName);
455 if (!OptDesc.isList())
456 throw OptName + ": incorrect option type - should be a list!";
457 return OptDesc;
458}
459
460const OptionDescription&
461OptionDescriptions::FindParameter(const std::string& OptName) const {
462 const OptionDescription& OptDesc = this->FindOption(OptName);
463 if (!OptDesc.isParameter())
464 throw OptName + ": incorrect option type - should be a parameter!";
465 return OptDesc;
466}
467
468const OptionDescription&
469OptionDescriptions::FindListOrParameter(const std::string& OptName) const {
470 const OptionDescription& OptDesc = this->FindOption(OptName);
471 if (!OptDesc.isList() && !OptDesc.isParameter())
472 throw OptName
473 + ": incorrect option type - should be a list or parameter!";
474 return OptDesc;
475}
476
477void OptionDescriptions::InsertDescription (const OptionDescription& o) {
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000478 container_type::iterator I = Descriptions.find(o.Name);
479 if (I != Descriptions.end()) {
480 OptionDescription& D = I->second;
481 D.Merge(o);
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +0000482 }
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000483 else {
484 Descriptions[o.Name] = o;
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +0000485 }
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +0000486}
487
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000488/// HandlerTable - A base class for function objects implemented as
489/// 'tables of handlers'.
Mikhail Glushenkov632eb202009-12-07 10:51:55 +0000490template <typename Handler>
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000491class HandlerTable {
492protected:
Mikhail Glushenkov09b51c32008-05-30 06:27:02 +0000493 // Implementation details.
494
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000495 /// HandlerMap - A map from property names to property handlers
496 typedef StringMap<Handler> HandlerMap;
Mikhail Glushenkov09b51c32008-05-30 06:27:02 +0000497
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000498 static HandlerMap Handlers_;
Mikhail Glushenkov09b51c32008-05-30 06:27:02 +0000499 static bool staticMembersInitialized_;
500
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000501public:
Mikhail Glushenkov09b51c32008-05-30 06:27:02 +0000502
Mikhail Glushenkov632eb202009-12-07 10:51:55 +0000503 Handler GetHandler (const std::string& HandlerName) const {
504 typename HandlerMap::iterator method = Handlers_.find(HandlerName);
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000505
506 if (method != Handlers_.end()) {
507 Handler h = method->second;
Mikhail Glushenkov632eb202009-12-07 10:51:55 +0000508 return h;
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000509 }
510 else {
Mikhail Glushenkov632eb202009-12-07 10:51:55 +0000511 throw "No handler found for property " + HandlerName + "!";
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000512 }
513 }
514
Mikhail Glushenkov632eb202009-12-07 10:51:55 +0000515 void AddHandler(const char* Property, Handler H) {
516 Handlers_[Property] = H;
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000517 }
Mikhail Glushenkov632eb202009-12-07 10:51:55 +0000518
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000519};
520
Mikhail Glushenkov24723282009-12-17 07:48:49 +0000521template <class Handler, class FunctionObject>
522Handler GetHandler(FunctionObject* Obj, const DagInit& Dag) {
523 const std::string& HandlerName = GetOperatorName(Dag);
524 return Obj->GetHandler(HandlerName);
Mikhail Glushenkov632eb202009-12-07 10:51:55 +0000525}
526
Mikhail Glushenkov24723282009-12-17 07:48:49 +0000527template <class FunctionObject>
528void InvokeDagInitHandler(FunctionObject* Obj, Init* I) {
529 typedef void (FunctionObject::*Handler) (const DagInit&);
530
531 const DagInit& Dag = InitPtrToDag(I);
532 Handler h = GetHandler<Handler>(Obj, Dag);
533
534 ((Obj)->*(h))(Dag);
535}
536
537template <class FunctionObject>
538void InvokeDagInitHandler(const FunctionObject* const Obj,
539 const Init* I, unsigned IndentLevel, raw_ostream& O)
540{
541 typedef void (FunctionObject::*Handler)
542 (const DagInit&, unsigned IndentLevel, raw_ostream& O) const;
543
544 const DagInit& Dag = InitPtrToDag(I);
545 Handler h = GetHandler<Handler>(Obj, Dag);
546
547 ((Obj)->*(h))(Dag, IndentLevel, O);
548}
549
550
Mikhail Glushenkov632eb202009-12-07 10:51:55 +0000551template <typename H>
552typename HandlerTable<H>::HandlerMap HandlerTable<H>::Handlers_;
553
554template <typename H>
555bool HandlerTable<H>::staticMembersInitialized_ = false;
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000556
557
558/// CollectOptionProperties - Function object for iterating over an
559/// option property list.
Mikhail Glushenkov632eb202009-12-07 10:51:55 +0000560class CollectOptionProperties;
561typedef void (CollectOptionProperties::* CollectOptionPropertiesHandler)
Mikhail Glushenkov24723282009-12-17 07:48:49 +0000562(const DagInit&);
Mikhail Glushenkov632eb202009-12-07 10:51:55 +0000563
564class CollectOptionProperties
565: public HandlerTable<CollectOptionPropertiesHandler>
566{
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000567private:
568
569 /// optDescs_ - OptionDescriptions table. This is where the
570 /// information is stored.
571 OptionDescription& optDesc_;
Mikhail Glushenkov09b51c32008-05-30 06:27:02 +0000572
573public:
574
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000575 explicit CollectOptionProperties(OptionDescription& OD)
Mikhail Glushenkov632eb202009-12-07 10:51:55 +0000576 : optDesc_(OD)
Mikhail Glushenkov09b51c32008-05-30 06:27:02 +0000577 {
578 if (!staticMembersInitialized_) {
Mikhail Glushenkovb4ced5a2008-12-07 16:47:12 +0000579 AddHandler("extern", &CollectOptionProperties::onExtern);
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000580 AddHandler("help", &CollectOptionProperties::onHelp);
581 AddHandler("hidden", &CollectOptionProperties::onHidden);
Mikhail Glushenkov8fe44472009-07-07 16:08:41 +0000582 AddHandler("init", &CollectOptionProperties::onInit);
Mikhail Glushenkov19d3e822009-01-28 03:47:20 +0000583 AddHandler("multi_val", &CollectOptionProperties::onMultiVal);
584 AddHandler("one_or_more", &CollectOptionProperties::onOneOrMore);
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000585 AddHandler("really_hidden", &CollectOptionProperties::onReallyHidden);
586 AddHandler("required", &CollectOptionProperties::onRequired);
Mikhail Glushenkove4ac23a2009-12-15 03:04:52 +0000587 AddHandler("optional", &CollectOptionProperties::onOptional);
Mikhail Glushenkov5b9b3ba2009-12-07 18:25:54 +0000588 AddHandler("comma_separated", &CollectOptionProperties::onCommaSeparated);
Mikhail Glushenkov09b51c32008-05-30 06:27:02 +0000589
590 staticMembersInitialized_ = true;
591 }
592 }
593
Mikhail Glushenkov632eb202009-12-07 10:51:55 +0000594 /// operator() - Just forwards to the corresponding property
595 /// handler.
Mikhail Glushenkov24723282009-12-17 07:48:49 +0000596 void operator() (Init* I) {
597 InvokeDagInitHandler(this, I);
Mikhail Glushenkov632eb202009-12-07 10:51:55 +0000598 }
599
Mikhail Glushenkov09b51c32008-05-30 06:27:02 +0000600private:
601
602 /// Option property handlers --
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000603 /// Methods that handle option properties such as (help) or (hidden).
Mikhail Glushenkovfdee9542008-09-22 20:46:19 +0000604
Mikhail Glushenkov24723282009-12-17 07:48:49 +0000605 void onExtern (const DagInit& d) {
Mikhail Glushenkov9bef1bd2009-12-23 12:49:41 +0000606 CheckNumberOfArguments(d, 0);
Mikhail Glushenkovb4ced5a2008-12-07 16:47:12 +0000607 optDesc_.setExtern();
608 }
609
Mikhail Glushenkov24723282009-12-17 07:48:49 +0000610 void onHelp (const DagInit& d) {
Mikhail Glushenkov9bef1bd2009-12-23 12:49:41 +0000611 CheckNumberOfArguments(d, 1);
Mikhail Glushenkovae779382010-01-26 14:55:04 +0000612 optDesc_.Help = EscapeQuotes(InitPtrToString(d.getArg(0)));
Mikhail Glushenkov09b51c32008-05-30 06:27:02 +0000613 }
614
Mikhail Glushenkov24723282009-12-17 07:48:49 +0000615 void onHidden (const DagInit& d) {
Mikhail Glushenkov9bef1bd2009-12-23 12:49:41 +0000616 CheckNumberOfArguments(d, 0);
Mikhail Glushenkov739c7202008-11-28 00:13:25 +0000617 optDesc_.setHidden();
618 }
619
Mikhail Glushenkov24723282009-12-17 07:48:49 +0000620 void onReallyHidden (const DagInit& d) {
Mikhail Glushenkov9bef1bd2009-12-23 12:49:41 +0000621 CheckNumberOfArguments(d, 0);
Mikhail Glushenkov739c7202008-11-28 00:13:25 +0000622 optDesc_.setReallyHidden();
623 }
624
Mikhail Glushenkov24723282009-12-17 07:48:49 +0000625 void onCommaSeparated (const DagInit& d) {
Mikhail Glushenkov9bef1bd2009-12-23 12:49:41 +0000626 CheckNumberOfArguments(d, 0);
Mikhail Glushenkov5b9b3ba2009-12-07 18:25:54 +0000627 if (!optDesc_.isList())
628 throw "'comma_separated' is valid only on list options!";
629 optDesc_.setCommaSeparated();
630 }
631
Mikhail Glushenkov24723282009-12-17 07:48:49 +0000632 void onRequired (const DagInit& d) {
Mikhail Glushenkov9bef1bd2009-12-23 12:49:41 +0000633 CheckNumberOfArguments(d, 0);
Mikhail Glushenkove4ac23a2009-12-15 03:04:52 +0000634 if (optDesc_.isOneOrMore() || optDesc_.isOptional())
635 throw "Only one of (required), (optional) or "
Mikhail Glushenkov5b9b3ba2009-12-07 18:25:54 +0000636 "(one_or_more) properties is allowed!";
Mikhail Glushenkov09b51c32008-05-30 06:27:02 +0000637 optDesc_.setRequired();
638 }
639
Mikhail Glushenkov24723282009-12-17 07:48:49 +0000640 void onInit (const DagInit& d) {
Mikhail Glushenkov9bef1bd2009-12-23 12:49:41 +0000641 CheckNumberOfArguments(d, 1);
Mikhail Glushenkov24723282009-12-17 07:48:49 +0000642 Init* i = d.getArg(0);
Mikhail Glushenkov8fe44472009-07-07 16:08:41 +0000643 const std::string& str = i->getAsString();
644
645 bool correct = optDesc_.isParameter() && dynamic_cast<StringInit*>(i);
646 correct |= (optDesc_.isSwitch() && (str == "true" || str == "false"));
647
648 if (!correct)
Mikhail Glushenkov5b9b3ba2009-12-07 18:25:54 +0000649 throw "Incorrect usage of the 'init' option property!";
Mikhail Glushenkov8fe44472009-07-07 16:08:41 +0000650
651 optDesc_.InitVal = i;
652 }
653
Mikhail Glushenkov24723282009-12-17 07:48:49 +0000654 void onOneOrMore (const DagInit& d) {
Mikhail Glushenkov9bef1bd2009-12-23 12:49:41 +0000655 CheckNumberOfArguments(d, 0);
Mikhail Glushenkove4ac23a2009-12-15 03:04:52 +0000656 if (optDesc_.isRequired() || optDesc_.isOptional())
657 throw "Only one of (required), (optional) or "
Mikhail Glushenkov5b9b3ba2009-12-07 18:25:54 +0000658 "(one_or_more) properties is allowed!";
Mikhail Glushenkov19d3e822009-01-28 03:47:20 +0000659 if (!OptionType::IsList(optDesc_.Type))
Daniel Dunbar1a551802009-07-03 00:10:29 +0000660 llvm::errs() << "Warning: specifying the 'one_or_more' property "
Mikhail Glushenkov19d3e822009-01-28 03:47:20 +0000661 "on a non-list option will have no effect.\n";
662 optDesc_.setOneOrMore();
663 }
664
Mikhail Glushenkov24723282009-12-17 07:48:49 +0000665 void onOptional (const DagInit& d) {
Mikhail Glushenkov9bef1bd2009-12-23 12:49:41 +0000666 CheckNumberOfArguments(d, 0);
Mikhail Glushenkov19d3e822009-01-28 03:47:20 +0000667 if (optDesc_.isRequired() || optDesc_.isOneOrMore())
Mikhail Glushenkove4ac23a2009-12-15 03:04:52 +0000668 throw "Only one of (required), (optional) or "
Mikhail Glushenkov5b9b3ba2009-12-07 18:25:54 +0000669 "(one_or_more) properties is allowed!";
Mikhail Glushenkov19d3e822009-01-28 03:47:20 +0000670 if (!OptionType::IsList(optDesc_.Type))
Mikhail Glushenkove4ac23a2009-12-15 03:04:52 +0000671 llvm::errs() << "Warning: specifying the 'optional' property"
Mikhail Glushenkov19d3e822009-01-28 03:47:20 +0000672 "on a non-list option will have no effect.\n";
Mikhail Glushenkove4ac23a2009-12-15 03:04:52 +0000673 optDesc_.setOptional();
Mikhail Glushenkov19d3e822009-01-28 03:47:20 +0000674 }
675
Mikhail Glushenkov24723282009-12-17 07:48:49 +0000676 void onMultiVal (const DagInit& d) {
Mikhail Glushenkov9bef1bd2009-12-23 12:49:41 +0000677 CheckNumberOfArguments(d, 1);
Mikhail Glushenkov24723282009-12-17 07:48:49 +0000678 int val = InitPtrToInt(d.getArg(0));
Mikhail Glushenkov19d3e822009-01-28 03:47:20 +0000679 if (val < 2)
Mikhail Glushenkov5b9b3ba2009-12-07 18:25:54 +0000680 throw "Error in the 'multi_val' property: "
681 "the value must be greater than 1!";
Mikhail Glushenkov19d3e822009-01-28 03:47:20 +0000682 if (!OptionType::IsList(optDesc_.Type))
Mikhail Glushenkov5b9b3ba2009-12-07 18:25:54 +0000683 throw "The multi_val property is valid only on list options!";
Mikhail Glushenkov19d3e822009-01-28 03:47:20 +0000684 optDesc_.MultiVal = val;
685 }
686
Mikhail Glushenkov09b51c32008-05-30 06:27:02 +0000687};
688
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000689/// AddOption - A function object that is applied to every option
690/// description. Used by CollectOptionDescriptions.
Mikhail Glushenkov2b7bcb42008-05-30 06:27:29 +0000691class AddOption {
692private:
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000693 OptionDescriptions& OptDescs_;
Mikhail Glushenkov2b7bcb42008-05-30 06:27:29 +0000694
695public:
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000696 explicit AddOption(OptionDescriptions& OD) : OptDescs_(OD)
Mikhail Glushenkov2b7bcb42008-05-30 06:27:29 +0000697 {}
698
699 void operator()(const Init* i) {
700 const DagInit& d = InitPtrToDag(i);
Mikhail Glushenkov9bef1bd2009-12-23 12:49:41 +0000701 CheckNumberOfArguments(d, 1);
Mikhail Glushenkov2b7bcb42008-05-30 06:27:29 +0000702
703 const OptionType::OptionType Type =
Mikhail Glushenkov4d21ae72009-10-18 22:51:30 +0000704 stringToOptionType(GetOperatorName(d));
Mikhail Glushenkov2b7bcb42008-05-30 06:27:29 +0000705 const std::string& Name = InitPtrToString(d.getArg(0));
706
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000707 OptionDescription OD(Type, Name);
708
709 if (!OD.isExtern())
Mikhail Glushenkov9bef1bd2009-12-23 12:49:41 +0000710 CheckNumberOfArguments(d, 2);
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000711
712 if (OD.isAlias()) {
713 // Aliases store the aliased option name in the 'Help' field.
Mikhail Glushenkov2b7bcb42008-05-30 06:27:29 +0000714 OD.Help = InitPtrToString(d.getArg(1));
715 }
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000716 else if (!OD.isExtern()) {
Mikhail Glushenkov24723282009-12-17 07:48:49 +0000717 processOptionProperties(d, OD);
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000718 }
719 OptDescs_.InsertDescription(OD);
Mikhail Glushenkov2b7bcb42008-05-30 06:27:29 +0000720 }
721
722private:
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000723 /// processOptionProperties - Go through the list of option
724 /// properties and call a corresponding handler for each.
Mikhail Glushenkov24723282009-12-17 07:48:49 +0000725 static void processOptionProperties (const DagInit& d, OptionDescription& o) {
Mikhail Glushenkov9bef1bd2009-12-23 12:49:41 +0000726 CheckNumberOfArguments(d, 2);
Mikhail Glushenkov24723282009-12-17 07:48:49 +0000727 DagInit::const_arg_iterator B = d.arg_begin();
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000728 // Skip the first argument: it's always the option name.
729 ++B;
Mikhail Glushenkov24723282009-12-17 07:48:49 +0000730 std::for_each(B, d.arg_end(), CollectOptionProperties(o));
Mikhail Glushenkov2b7bcb42008-05-30 06:27:29 +0000731 }
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000732
Mikhail Glushenkov2b7bcb42008-05-30 06:27:29 +0000733};
734
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000735/// CollectOptionDescriptions - Collects option properties from all
736/// OptionLists.
737void CollectOptionDescriptions (RecordVector::const_iterator B,
738 RecordVector::const_iterator E,
739 OptionDescriptions& OptDescs)
740{
741 // For every OptionList:
742 for (; B!=E; ++B) {
743 RecordVector::value_type T = *B;
744 // Throws an exception if the value does not exist.
745 ListInit* PropList = T->getValueAsListInit("options");
Mikhail Glushenkov2b7bcb42008-05-30 06:27:29 +0000746
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000747 // For every option description in this list:
748 // collect the information and
749 std::for_each(PropList->begin(), PropList->end(), AddOption(OptDescs));
750 }
751}
752
753// Tool information record
754
755namespace ToolFlags {
756 enum ToolFlags { Join = 0x1, Sink = 0x2 };
757}
758
759struct ToolDescription : public RefCountedBase<ToolDescription> {
760 std::string Name;
761 Init* CmdLine;
762 Init* Actions;
763 StrVector InLanguage;
764 std::string OutLanguage;
765 std::string OutputSuffix;
766 unsigned Flags;
767
768 // Various boolean properties
769 void setSink() { Flags |= ToolFlags::Sink; }
770 bool isSink() const { return Flags & ToolFlags::Sink; }
771 void setJoin() { Flags |= ToolFlags::Join; }
772 bool isJoin() const { return Flags & ToolFlags::Join; }
773
774 // Default ctor here is needed because StringMap can only store
775 // DefaultConstructible objects
776 ToolDescription() : CmdLine(0), Actions(0), Flags(0) {}
777 ToolDescription (const std::string& n)
778 : Name(n), CmdLine(0), Actions(0), Flags(0)
779 {}
780};
781
782/// ToolDescriptions - A list of Tool information records.
783typedef std::vector<IntrusiveRefCntPtr<ToolDescription> > ToolDescriptions;
784
785
786/// CollectToolProperties - Function object for iterating over a list of
Mikhail Glushenkov8e7254c2008-05-09 08:27:26 +0000787/// tool property records.
Mikhail Glushenkov632eb202009-12-07 10:51:55 +0000788
789class CollectToolProperties;
790typedef void (CollectToolProperties::* CollectToolPropertiesHandler)
Mikhail Glushenkov24723282009-12-17 07:48:49 +0000791(const DagInit&);
Mikhail Glushenkov632eb202009-12-07 10:51:55 +0000792
793class CollectToolProperties : public HandlerTable<CollectToolPropertiesHandler>
794{
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +0000795private:
796
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000797 /// toolDesc_ - Properties of the current Tool. This is where the
798 /// information is stored.
799 ToolDescription& toolDesc_;
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +0000800
801public:
802
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000803 explicit CollectToolProperties (ToolDescription& d)
Mikhail Glushenkov632eb202009-12-07 10:51:55 +0000804 : toolDesc_(d)
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +0000805 {
806 if (!staticMembersInitialized_) {
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000807
808 AddHandler("actions", &CollectToolProperties::onActions);
809 AddHandler("cmd_line", &CollectToolProperties::onCmdLine);
810 AddHandler("in_language", &CollectToolProperties::onInLanguage);
811 AddHandler("join", &CollectToolProperties::onJoin);
812 AddHandler("out_language", &CollectToolProperties::onOutLanguage);
813 AddHandler("output_suffix", &CollectToolProperties::onOutputSuffix);
814 AddHandler("sink", &CollectToolProperties::onSink);
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +0000815
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +0000816 staticMembersInitialized_ = true;
817 }
818 }
819
Mikhail Glushenkov24723282009-12-17 07:48:49 +0000820 void operator() (Init* I) {
821 InvokeDagInitHandler(this, I);
Mikhail Glushenkov632eb202009-12-07 10:51:55 +0000822 }
823
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +0000824private:
825
826 /// Property handlers --
827 /// Functions that extract information about tool properties from
828 /// DAG representation.
829
Mikhail Glushenkov24723282009-12-17 07:48:49 +0000830 void onActions (const DagInit& d) {
Mikhail Glushenkov9bef1bd2009-12-23 12:49:41 +0000831 CheckNumberOfArguments(d, 1);
Mikhail Glushenkov24723282009-12-17 07:48:49 +0000832 Init* Case = d.getArg(0);
Mikhail Glushenkovad889a72008-12-07 16:45:12 +0000833 if (typeid(*Case) != typeid(DagInit) ||
Mikhail Glushenkov24723282009-12-17 07:48:49 +0000834 GetOperatorName(static_cast<DagInit&>(*Case)) != "case")
Mikhail Glushenkov06d26612009-12-07 19:15:57 +0000835 throw "The argument to (actions) should be a 'case' construct!";
Mikhail Glushenkovad889a72008-12-07 16:45:12 +0000836 toolDesc_.Actions = Case;
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000837 }
838
Mikhail Glushenkov24723282009-12-17 07:48:49 +0000839 void onCmdLine (const DagInit& d) {
Mikhail Glushenkov9bef1bd2009-12-23 12:49:41 +0000840 CheckNumberOfArguments(d, 1);
Mikhail Glushenkov24723282009-12-17 07:48:49 +0000841 toolDesc_.CmdLine = d.getArg(0);
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +0000842 }
843
Mikhail Glushenkov24723282009-12-17 07:48:49 +0000844 void onInLanguage (const DagInit& d) {
Mikhail Glushenkov9bef1bd2009-12-23 12:49:41 +0000845 CheckNumberOfArguments(d, 1);
Mikhail Glushenkov24723282009-12-17 07:48:49 +0000846 Init* arg = d.getArg(0);
Mikhail Glushenkovffcf3a12008-05-30 06:18:16 +0000847
848 // Find out the argument's type.
849 if (typeid(*arg) == typeid(StringInit)) {
850 // It's a string.
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000851 toolDesc_.InLanguage.push_back(InitPtrToString(arg));
Mikhail Glushenkovffcf3a12008-05-30 06:18:16 +0000852 }
853 else {
854 // It's a list.
855 const ListInit& lst = InitPtrToList(arg);
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000856 StrVector& out = toolDesc_.InLanguage;
Mikhail Glushenkovffcf3a12008-05-30 06:18:16 +0000857
858 // Copy strings to the output vector.
859 for (ListInit::const_iterator B = lst.begin(), E = lst.end();
860 B != E; ++B) {
861 out.push_back(InitPtrToString(*B));
862 }
863
864 // Remove duplicates.
865 std::sort(out.begin(), out.end());
866 StrVector::iterator newE = std::unique(out.begin(), out.end());
867 out.erase(newE, out.end());
868 }
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +0000869 }
870
Mikhail Glushenkov24723282009-12-17 07:48:49 +0000871 void onJoin (const DagInit& d) {
Mikhail Glushenkov9bef1bd2009-12-23 12:49:41 +0000872 CheckNumberOfArguments(d, 0);
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000873 toolDesc_.setJoin();
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +0000874 }
875
Mikhail Glushenkov24723282009-12-17 07:48:49 +0000876 void onOutLanguage (const DagInit& d) {
Mikhail Glushenkov9bef1bd2009-12-23 12:49:41 +0000877 CheckNumberOfArguments(d, 1);
Mikhail Glushenkov24723282009-12-17 07:48:49 +0000878 toolDesc_.OutLanguage = InitPtrToString(d.getArg(0));
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +0000879 }
880
Mikhail Glushenkov24723282009-12-17 07:48:49 +0000881 void onOutputSuffix (const DagInit& d) {
Mikhail Glushenkov9bef1bd2009-12-23 12:49:41 +0000882 CheckNumberOfArguments(d, 1);
Mikhail Glushenkov24723282009-12-17 07:48:49 +0000883 toolDesc_.OutputSuffix = InitPtrToString(d.getArg(0));
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +0000884 }
885
Mikhail Glushenkov24723282009-12-17 07:48:49 +0000886 void onSink (const DagInit& d) {
Mikhail Glushenkov9bef1bd2009-12-23 12:49:41 +0000887 CheckNumberOfArguments(d, 0);
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000888 toolDesc_.setSink();
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +0000889 }
890
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +0000891};
892
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000893/// CollectToolDescriptions - Gather information about tool properties
Mikhail Glushenkove43228952008-05-30 06:26:08 +0000894/// from the parsed TableGen data (basically a wrapper for the
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000895/// CollectToolProperties function object).
896void CollectToolDescriptions (RecordVector::const_iterator B,
897 RecordVector::const_iterator E,
898 ToolDescriptions& ToolDescs)
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +0000899{
900 // Iterate over a properties list of every Tool definition
901 for (;B!=E;++B) {
Mikhail Glushenkovfa270772008-11-17 17:29:42 +0000902 const Record* T = *B;
Mikhail Glushenkove43228952008-05-30 06:26:08 +0000903 // Throws an exception if the value does not exist.
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +0000904 ListInit* PropList = T->getValueAsListInit("properties");
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +0000905
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000906 IntrusiveRefCntPtr<ToolDescription>
907 ToolDesc(new ToolDescription(T->getName()));
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +0000908
909 std::for_each(PropList->begin(), PropList->end(),
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000910 CollectToolProperties(*ToolDesc));
911 ToolDescs.push_back(ToolDesc);
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +0000912 }
913}
914
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000915/// FillInEdgeVector - Merge all compilation graph definitions into
916/// one single edge list.
917void FillInEdgeVector(RecordVector::const_iterator B,
918 RecordVector::const_iterator E, RecordVector& Out) {
919 for (; B != E; ++B) {
920 const ListInit* edges = (*B)->getValueAsListInit("edges");
Mikhail Glushenkov09b51c32008-05-30 06:27:02 +0000921
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000922 for (unsigned i = 0; i < edges->size(); ++i)
923 Out.push_back(edges->getElementAsRecord(i));
924 }
925}
926
927/// CalculatePriority - Calculate the priority of this plugin.
928int CalculatePriority(RecordVector::const_iterator B,
929 RecordVector::const_iterator E) {
Mikhail Glushenkov2cea7bd2009-10-17 20:08:30 +0000930 int priority = 0;
931
932 if (B != E) {
933 priority = static_cast<int>((*B)->getValueAsInt("priority"));
934
935 if (++B != E)
Mikhail Glushenkov06d26612009-12-07 19:15:57 +0000936 throw "More than one 'PluginPriority' instance found: "
937 "most probably an error!";
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000938 }
Mikhail Glushenkov2cea7bd2009-10-17 20:08:30 +0000939
940 return priority;
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000941}
Mikhail Glushenkove43228952008-05-30 06:26:08 +0000942
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000943/// NotInGraph - Helper function object for FilterNotInGraph.
944struct NotInGraph {
945private:
946 const llvm::StringSet<>& ToolsInGraph_;
947
948public:
949 NotInGraph(const llvm::StringSet<>& ToolsInGraph)
950 : ToolsInGraph_(ToolsInGraph)
951 {}
952
953 bool operator()(const IntrusiveRefCntPtr<ToolDescription>& x) {
954 return (ToolsInGraph_.count(x->Name) == 0);
955 }
956};
957
958/// FilterNotInGraph - Filter out from ToolDescs all Tools not
959/// mentioned in the compilation graph definition.
960void FilterNotInGraph (const RecordVector& EdgeVector,
961 ToolDescriptions& ToolDescs) {
962
963 // List all tools mentioned in the graph.
964 llvm::StringSet<> ToolsInGraph;
965
966 for (RecordVector::const_iterator B = EdgeVector.begin(),
967 E = EdgeVector.end(); B != E; ++B) {
968
969 const Record* Edge = *B;
Mikhail Glushenkov15b71ba2008-12-07 16:44:47 +0000970 const std::string& NodeA = Edge->getValueAsString("a");
971 const std::string& NodeB = Edge->getValueAsString("b");
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000972
Mikhail Glushenkov15b71ba2008-12-07 16:44:47 +0000973 if (NodeA != "root")
974 ToolsInGraph.insert(NodeA);
975 ToolsInGraph.insert(NodeB);
Mikhail Glushenkovf9152532008-12-07 16:41:11 +0000976 }
977
978 // Filter ToolPropertiesList.
979 ToolDescriptions::iterator new_end =
980 std::remove_if(ToolDescs.begin(), ToolDescs.end(),
981 NotInGraph(ToolsInGraph));
982 ToolDescs.erase(new_end, ToolDescs.end());
983}
984
985/// FillInToolToLang - Fills in two tables that map tool names to
986/// (input, output) languages. Helper function used by TypecheckGraph().
987void FillInToolToLang (const ToolDescriptions& ToolDescs,
988 StringMap<StringSet<> >& ToolToInLang,
989 StringMap<std::string>& ToolToOutLang) {
990 for (ToolDescriptions::const_iterator B = ToolDescs.begin(),
991 E = ToolDescs.end(); B != E; ++B) {
992 const ToolDescription& D = *(*B);
993 for (StrVector::const_iterator B = D.InLanguage.begin(),
994 E = D.InLanguage.end(); B != E; ++B)
995 ToolToInLang[D.Name].insert(*B);
996 ToolToOutLang[D.Name] = D.OutLanguage;
Mikhail Glushenkove43228952008-05-30 06:26:08 +0000997 }
998}
999
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00001000/// TypecheckGraph - Check that names for output and input languages
1001/// on all edges do match. This doesn't do much when the information
1002/// about the whole graph is not available (i.e. when compiling most
1003/// plugins).
1004void TypecheckGraph (const RecordVector& EdgeVector,
1005 const ToolDescriptions& ToolDescs) {
1006 StringMap<StringSet<> > ToolToInLang;
1007 StringMap<std::string> ToolToOutLang;
1008
1009 FillInToolToLang(ToolDescs, ToolToInLang, ToolToOutLang);
1010 StringMap<std::string>::iterator IAE = ToolToOutLang.end();
1011 StringMap<StringSet<> >::iterator IBE = ToolToInLang.end();
1012
1013 for (RecordVector::const_iterator B = EdgeVector.begin(),
1014 E = EdgeVector.end(); B != E; ++B) {
1015 const Record* Edge = *B;
Mikhail Glushenkov15b71ba2008-12-07 16:44:47 +00001016 const std::string& NodeA = Edge->getValueAsString("a");
1017 const std::string& NodeB = Edge->getValueAsString("b");
1018 StringMap<std::string>::iterator IA = ToolToOutLang.find(NodeA);
1019 StringMap<StringSet<> >::iterator IB = ToolToInLang.find(NodeB);
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00001020
Mikhail Glushenkov15b71ba2008-12-07 16:44:47 +00001021 if (NodeA != "root") {
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00001022 if (IA != IAE && IB != IBE && IB->second.count(IA->second) == 0)
Mikhail Glushenkov15b71ba2008-12-07 16:44:47 +00001023 throw "Edge " + NodeA + "->" + NodeB
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00001024 + ": output->input language mismatch";
1025 }
1026
Mikhail Glushenkov15b71ba2008-12-07 16:44:47 +00001027 if (NodeB == "root")
Mikhail Glushenkov06d26612009-12-07 19:15:57 +00001028 throw "Edges back to the root are not allowed!";
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00001029 }
1030}
1031
1032/// WalkCase - Walks the 'case' expression DAG and invokes
1033/// TestCallback on every test, and StatementCallback on every
1034/// statement. Handles 'case' nesting, but not the 'and' and 'or'
Mikhail Glushenkov4d21ae72009-10-18 22:51:30 +00001035/// combinators (that is, they are passed directly to TestCallback).
1036/// TestCallback must have type 'void TestCallback(const DagInit*, unsigned
1037/// IndentLevel, bool FirstTest)'.
1038/// StatementCallback must have type 'void StatementCallback(const Init*,
1039/// unsigned IndentLevel)'.
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00001040template <typename F1, typename F2>
Mikhail Glushenkov4d21ae72009-10-18 22:51:30 +00001041void WalkCase(const Init* Case, F1 TestCallback, F2 StatementCallback,
1042 unsigned IndentLevel = 0)
1043{
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00001044 const DagInit& d = InitPtrToDag(Case);
Mikhail Glushenkov4d21ae72009-10-18 22:51:30 +00001045
1046 // Error checks.
1047 if (GetOperatorName(d) != "case")
Mikhail Glushenkov06d26612009-12-07 19:15:57 +00001048 throw "WalkCase should be invoked only on 'case' expressions!";
Mikhail Glushenkov4d21ae72009-10-18 22:51:30 +00001049
1050 if (d.getNumArgs() < 2)
1051 throw "There should be at least one clause in the 'case' expression:\n"
1052 + d.getAsString();
1053
1054 // Main loop.
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00001055 bool even = false;
Mikhail Glushenkov4d21ae72009-10-18 22:51:30 +00001056 const unsigned numArgs = d.getNumArgs();
1057 unsigned i = 1;
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00001058 for (DagInit::const_arg_iterator B = d.arg_begin(), E = d.arg_end();
1059 B != E; ++B) {
1060 Init* arg = *B;
Mikhail Glushenkov4d21ae72009-10-18 22:51:30 +00001061
1062 if (!even)
1063 {
1064 // Handle test.
1065 const DagInit& Test = InitPtrToDag(arg);
1066
1067 if (GetOperatorName(Test) == "default" && (i+1 != numArgs))
Mikhail Glushenkov06d26612009-12-07 19:15:57 +00001068 throw "The 'default' clause should be the last in the "
1069 "'case' construct!";
Mikhail Glushenkov4d21ae72009-10-18 22:51:30 +00001070 if (i == numArgs)
1071 throw "Case construct handler: no corresponding action "
1072 "found for the test " + Test.getAsString() + '!';
1073
Mikhail Glushenkov24723282009-12-17 07:48:49 +00001074 TestCallback(Test, IndentLevel, (i == 1));
Mikhail Glushenkov4d21ae72009-10-18 22:51:30 +00001075 }
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00001076 else
Mikhail Glushenkov4d21ae72009-10-18 22:51:30 +00001077 {
1078 if (dynamic_cast<DagInit*>(arg)
Mikhail Glushenkov24723282009-12-17 07:48:49 +00001079 && GetOperatorName(static_cast<DagInit&>(*arg)) == "case") {
Mikhail Glushenkov4d21ae72009-10-18 22:51:30 +00001080 // Nested 'case'.
1081 WalkCase(arg, TestCallback, StatementCallback, IndentLevel + Indent1);
1082 }
1083
1084 // Handle statement.
1085 StatementCallback(arg, IndentLevel);
1086 }
1087
1088 ++i;
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00001089 even = !even;
1090 }
1091}
1092
1093/// ExtractOptionNames - A helper function object used by
1094/// CheckForSuperfluousOptions() to walk the 'case' DAG.
1095class ExtractOptionNames {
1096 llvm::StringSet<>& OptionNames_;
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00001097
Mikhail Glushenkov08509492008-12-07 16:42:22 +00001098 void processDag(const Init* Statement) {
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00001099 const DagInit& Stmt = InitPtrToDag(Statement);
Mikhail Glushenkov4d21ae72009-10-18 22:51:30 +00001100 const std::string& ActionName = GetOperatorName(Stmt);
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00001101 if (ActionName == "forward" || ActionName == "forward_as" ||
Mikhail Glushenkov8245a1d2009-12-07 17:03:05 +00001102 ActionName == "forward_value" ||
1103 ActionName == "forward_transformed_value" ||
Mikhail Glushenkovd64c9072010-01-01 03:51:02 +00001104 ActionName == "switch_on" || ActionName == "any_switch_on" ||
1105 ActionName == "parameter_equals" ||
Mikhail Glushenkov5b9b3ba2009-12-07 18:25:54 +00001106 ActionName == "element_in_list" || ActionName == "not_empty" ||
1107 ActionName == "empty") {
Mikhail Glushenkov9bef1bd2009-12-23 12:49:41 +00001108 CheckNumberOfArguments(Stmt, 1);
Mikhail Glushenkovd64c9072010-01-01 03:51:02 +00001109
1110 Init* Arg = Stmt.getArg(0);
1111 if (typeid(*Arg) == typeid(StringInit)) {
1112 const std::string& Name = InitPtrToString(Arg);
1113 OptionNames_.insert(Name);
1114 }
1115 else {
1116 // It's a list.
1117 const ListInit& List = InitPtrToList(Arg);
1118 for (ListInit::const_iterator B = List.begin(), E = List.end();
1119 B != E; ++B) {
1120 const std::string& Name = InitPtrToString(*B);
1121 OptionNames_.insert(Name);
1122 }
1123 }
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00001124 }
Mikhail Glushenkovd64c9072010-01-01 03:51:02 +00001125 else if (ActionName == "and" || ActionName == "or" || ActionName == "not") {
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00001126 for (unsigned i = 0, NumArgs = Stmt.getNumArgs(); i < NumArgs; ++i) {
Mikhail Glushenkov08509492008-12-07 16:42:22 +00001127 this->processDag(Stmt.getArg(i));
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00001128 }
1129 }
1130 }
Mikhail Glushenkov08509492008-12-07 16:42:22 +00001131
1132public:
1133 ExtractOptionNames(llvm::StringSet<>& OptionNames) : OptionNames_(OptionNames)
1134 {}
1135
1136 void operator()(const Init* Statement) {
1137 if (typeid(*Statement) == typeid(ListInit)) {
1138 const ListInit& DagList = *static_cast<const ListInit*>(Statement);
1139 for (ListInit::const_iterator B = DagList.begin(), E = DagList.end();
1140 B != E; ++B)
1141 this->processDag(*B);
1142 }
1143 else {
1144 this->processDag(Statement);
1145 }
1146 }
Mikhail Glushenkov4d21ae72009-10-18 22:51:30 +00001147
Mikhail Glushenkov24723282009-12-17 07:48:49 +00001148 void operator()(const DagInit& Test, unsigned, bool) {
1149 this->operator()(&Test);
Mikhail Glushenkov4d21ae72009-10-18 22:51:30 +00001150 }
1151 void operator()(const Init* Statement, unsigned) {
1152 this->operator()(Statement);
1153 }
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00001154};
1155
Mikhail Glushenkova7d0ae32008-05-30 06:28:37 +00001156/// CheckForSuperfluousOptions - Check that there are no side
1157/// effect-free options (specified only in the OptionList). Otherwise,
1158/// output a warning.
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00001159void CheckForSuperfluousOptions (const RecordVector& Edges,
1160 const ToolDescriptions& ToolDescs,
1161 const OptionDescriptions& OptDescs) {
Mikhail Glushenkova7d0ae32008-05-30 06:28:37 +00001162 llvm::StringSet<> nonSuperfluousOptions;
1163
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00001164 // Add all options mentioned in the ToolDesc.Actions to the set of
Mikhail Glushenkova7d0ae32008-05-30 06:28:37 +00001165 // non-superfluous options.
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00001166 for (ToolDescriptions::const_iterator B = ToolDescs.begin(),
1167 E = ToolDescs.end(); B != E; ++B) {
1168 const ToolDescription& TD = *(*B);
1169 ExtractOptionNames Callback(nonSuperfluousOptions);
1170 if (TD.Actions)
1171 WalkCase(TD.Actions, Callback, Callback);
1172 }
1173
1174 // Add all options mentioned in the 'case' clauses of the
1175 // OptionalEdges of the compilation graph to the set of
1176 // non-superfluous options.
1177 for (RecordVector::const_iterator B = Edges.begin(), E = Edges.end();
1178 B != E; ++B) {
1179 const Record* Edge = *B;
Mikhail Glushenkov24723282009-12-17 07:48:49 +00001180 DagInit& Weight = *Edge->getValueAsDag("weight");
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00001181
Mikhail Glushenkov9bef1bd2009-12-23 12:49:41 +00001182 if (!IsDagEmpty(Weight))
Mikhail Glushenkov24723282009-12-17 07:48:49 +00001183 WalkCase(&Weight, ExtractOptionNames(nonSuperfluousOptions), Id());
Mikhail Glushenkova7d0ae32008-05-30 06:28:37 +00001184 }
1185
1186 // Check that all options in OptDescs belong to the set of
1187 // non-superfluous options.
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00001188 for (OptionDescriptions::const_iterator B = OptDescs.begin(),
Mikhail Glushenkova7d0ae32008-05-30 06:28:37 +00001189 E = OptDescs.end(); B != E; ++B) {
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00001190 const OptionDescription& Val = B->second;
Mikhail Glushenkova7d0ae32008-05-30 06:28:37 +00001191 if (!nonSuperfluousOptions.count(Val.Name)
1192 && Val.Type != OptionType::Alias)
Daniel Dunbar1a551802009-07-03 00:10:29 +00001193 llvm::errs() << "Warning: option '-" << Val.Name << "' has no effect! "
Mikhail Glushenkova7d0ae32008-05-30 06:28:37 +00001194 "Probable cause: this option is specified only in the OptionList.\n";
1195 }
1196}
1197
Mikhail Glushenkovad981bf2009-09-28 01:16:42 +00001198/// EmitCaseTest0Args - Helper function used by EmitCaseConstructHandler().
1199bool EmitCaseTest0Args(const std::string& TestName, raw_ostream& O) {
1200 if (TestName == "single_input_file") {
1201 O << "InputFilenames.size() == 1";
1202 return true;
1203 }
1204 else if (TestName == "multiple_input_files") {
1205 O << "InputFilenames.size() > 1";
1206 return true;
1207 }
1208
1209 return false;
1210}
1211
Mikhail Glushenkov4858a1d2009-10-21 02:13:13 +00001212/// EmitListTest - Helper function used by EmitCaseTest1ArgList().
1213template <typename F>
1214void EmitListTest(const ListInit& L, const char* LogicOp,
1215 F Callback, raw_ostream& O)
1216{
1217 // This is a lot like EmitLogicalOperationTest, but works on ListInits instead
1218 // of Dags...
1219 bool isFirst = true;
1220 for (ListInit::const_iterator B = L.begin(), E = L.end(); B != E; ++B) {
1221 if (isFirst)
1222 isFirst = false;
1223 else
Mikhail Glushenkovb7935e02010-01-01 04:40:54 +00001224 O << ' ' << LogicOp << ' ';
Mikhail Glushenkov4858a1d2009-10-21 02:13:13 +00001225 Callback(InitPtrToString(*B), O);
1226 }
1227}
1228
1229// Callbacks for use with EmitListTest.
1230
1231class EmitSwitchOn {
1232 const OptionDescriptions& OptDescs_;
1233public:
1234 EmitSwitchOn(const OptionDescriptions& OptDescs) : OptDescs_(OptDescs)
1235 {}
1236
1237 void operator()(const std::string& OptName, raw_ostream& O) const {
1238 const OptionDescription& OptDesc = OptDescs_.FindSwitch(OptName);
1239 O << OptDesc.GenVariableName();
1240 }
1241};
1242
1243class EmitEmptyTest {
1244 bool EmitNegate_;
1245 const OptionDescriptions& OptDescs_;
1246public:
1247 EmitEmptyTest(bool EmitNegate, const OptionDescriptions& OptDescs)
1248 : EmitNegate_(EmitNegate), OptDescs_(OptDescs)
1249 {}
1250
1251 void operator()(const std::string& OptName, raw_ostream& O) const {
1252 const char* Neg = (EmitNegate_ ? "!" : "");
1253 if (OptName == "o") {
1254 O << Neg << "OutputFilename.empty()";
1255 }
Mikhail Glushenkov97955002009-12-01 06:51:30 +00001256 else if (OptName == "save-temps") {
1257 O << Neg << "(SaveTemps == SaveTempsEnum::Unset)";
1258 }
Mikhail Glushenkov4858a1d2009-10-21 02:13:13 +00001259 else {
1260 const OptionDescription& OptDesc = OptDescs_.FindListOrParameter(OptName);
1261 O << Neg << OptDesc.GenVariableName() << ".empty()";
1262 }
1263 }
1264};
1265
1266
1267/// EmitCaseTest1ArgList - Helper function used by EmitCaseTest1Arg();
1268bool EmitCaseTest1ArgList(const std::string& TestName,
1269 const DagInit& d,
1270 const OptionDescriptions& OptDescs,
1271 raw_ostream& O) {
Mikhail Glushenkov3a481e32010-01-01 03:50:51 +00001272 const ListInit& L = InitPtrToList(d.getArg(0));
Mikhail Glushenkov4858a1d2009-10-21 02:13:13 +00001273
1274 if (TestName == "any_switch_on") {
1275 EmitListTest(L, "||", EmitSwitchOn(OptDescs), O);
1276 return true;
1277 }
1278 else if (TestName == "switch_on") {
1279 EmitListTest(L, "&&", EmitSwitchOn(OptDescs), O);
1280 return true;
1281 }
1282 else if (TestName == "any_not_empty") {
1283 EmitListTest(L, "||", EmitEmptyTest(true, OptDescs), O);
1284 return true;
1285 }
1286 else if (TestName == "any_empty") {
1287 EmitListTest(L, "||", EmitEmptyTest(false, OptDescs), O);
1288 return true;
1289 }
1290 else if (TestName == "not_empty") {
1291 EmitListTest(L, "&&", EmitEmptyTest(true, OptDescs), O);
1292 return true;
1293 }
1294 else if (TestName == "empty") {
1295 EmitListTest(L, "&&", EmitEmptyTest(false, OptDescs), O);
1296 return true;
1297 }
1298
1299 return false;
1300}
1301
Mikhail Glushenkov0a22fb62009-10-17 20:09:29 +00001302/// EmitCaseTest1ArgStr - Helper function used by EmitCaseTest1Arg();
1303bool EmitCaseTest1ArgStr(const std::string& TestName,
1304 const DagInit& d,
1305 const OptionDescriptions& OptDescs,
1306 raw_ostream& O) {
Mikhail Glushenkovb5ccfbf2008-05-30 06:10:19 +00001307 const std::string& OptName = InitPtrToString(d.getArg(0));
Mikhail Glushenkov5c2b6b22008-12-17 02:47:01 +00001308
Mikhail Glushenkovb5ccfbf2008-05-30 06:10:19 +00001309 if (TestName == "switch_on") {
Mikhail Glushenkov4858a1d2009-10-21 02:13:13 +00001310 apply(EmitSwitchOn(OptDescs), OptName, O);
Mikhail Glushenkovb5ccfbf2008-05-30 06:10:19 +00001311 return true;
Mikhail Glushenkov0a22fb62009-10-17 20:09:29 +00001312 }
1313 else if (TestName == "input_languages_contain") {
Mikhail Glushenkovb5ccfbf2008-05-30 06:10:19 +00001314 O << "InLangs.count(\"" << OptName << "\") != 0";
1315 return true;
Mikhail Glushenkov0a22fb62009-10-17 20:09:29 +00001316 }
1317 else if (TestName == "in_language") {
Mikhail Glushenkov07376512008-09-22 20:48:22 +00001318 // This works only for single-argument Tool::GenerateAction. Join
1319 // tools can process several files in different languages simultaneously.
1320
1321 // TODO: make this work with Edge::Weight (if possible).
Mikhail Glushenkov11a353a2008-09-22 20:47:46 +00001322 O << "LangMap.GetLanguage(inFile) == \"" << OptName << '\"';
Mikhail Glushenkov2e73e852008-05-30 06:19:52 +00001323 return true;
Mikhail Glushenkov0a22fb62009-10-17 20:09:29 +00001324 }
1325 else if (TestName == "not_empty" || TestName == "empty") {
Mikhail Glushenkov4858a1d2009-10-21 02:13:13 +00001326 bool EmitNegate = (TestName == "not_empty");
1327 apply(EmitEmptyTest(EmitNegate, OptDescs), OptName, O);
Mikhail Glushenkov0a22fb62009-10-17 20:09:29 +00001328 return true;
1329 }
1330
Mikhail Glushenkov0a22fb62009-10-17 20:09:29 +00001331 return false;
1332}
1333
1334/// EmitCaseTest1Arg - Helper function used by EmitCaseConstructHandler();
1335bool EmitCaseTest1Arg(const std::string& TestName,
1336 const DagInit& d,
1337 const OptionDescriptions& OptDescs,
1338 raw_ostream& O) {
Mikhail Glushenkov9bef1bd2009-12-23 12:49:41 +00001339 CheckNumberOfArguments(d, 1);
Mikhail Glushenkov0a22fb62009-10-17 20:09:29 +00001340 if (typeid(*d.getArg(0)) == typeid(ListInit))
1341 return EmitCaseTest1ArgList(TestName, d, OptDescs, O);
1342 else
1343 return EmitCaseTest1ArgStr(TestName, d, OptDescs, O);
1344}
1345
Mikhail Glushenkovad981bf2009-09-28 01:16:42 +00001346/// EmitCaseTest2Args - Helper function used by EmitCaseConstructHandler().
Mikhail Glushenkovb5ccfbf2008-05-30 06:10:19 +00001347bool EmitCaseTest2Args(const std::string& TestName,
1348 const DagInit& d,
Mikhail Glushenkovf8349ac2009-09-21 15:53:44 +00001349 unsigned IndentLevel,
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00001350 const OptionDescriptions& OptDescs,
Daniel Dunbar1a551802009-07-03 00:10:29 +00001351 raw_ostream& O) {
Mikhail Glushenkov9bef1bd2009-12-23 12:49:41 +00001352 CheckNumberOfArguments(d, 2);
Mikhail Glushenkovb5ccfbf2008-05-30 06:10:19 +00001353 const std::string& OptName = InitPtrToString(d.getArg(0));
1354 const std::string& OptArg = InitPtrToString(d.getArg(1));
Mikhail Glushenkovb5ccfbf2008-05-30 06:10:19 +00001355
1356 if (TestName == "parameter_equals") {
Mikhail Glushenkov4858a1d2009-10-21 02:13:13 +00001357 const OptionDescription& OptDesc = OptDescs.FindParameter(OptName);
Mikhail Glushenkovb5ccfbf2008-05-30 06:10:19 +00001358 O << OptDesc.GenVariableName() << " == \"" << OptArg << "\"";
1359 return true;
1360 }
1361 else if (TestName == "element_in_list") {
Mikhail Glushenkov4858a1d2009-10-21 02:13:13 +00001362 const OptionDescription& OptDesc = OptDescs.FindList(OptName);
Mikhail Glushenkovb5ccfbf2008-05-30 06:10:19 +00001363 const std::string& VarName = OptDesc.GenVariableName();
Mikhail Glushenkovf8349ac2009-09-21 15:53:44 +00001364 O << "std::find(" << VarName << ".begin(),\n";
1365 O.indent(IndentLevel + Indent1)
1366 << VarName << ".end(), \""
Mikhail Glushenkovb5ccfbf2008-05-30 06:10:19 +00001367 << OptArg << "\") != " << VarName << ".end()";
1368 return true;
1369 }
1370
1371 return false;
1372}
1373
1374// Forward declaration.
1375// EmitLogicalOperationTest and EmitCaseTest are mutually recursive.
Mikhail Glushenkovf8349ac2009-09-21 15:53:44 +00001376void EmitCaseTest(const DagInit& d, unsigned IndentLevel,
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00001377 const OptionDescriptions& OptDescs,
Daniel Dunbar1a551802009-07-03 00:10:29 +00001378 raw_ostream& O);
Mikhail Glushenkovb5ccfbf2008-05-30 06:10:19 +00001379
1380/// EmitLogicalOperationTest - Helper function used by
1381/// EmitCaseConstructHandler.
1382void EmitLogicalOperationTest(const DagInit& d, const char* LogicOp,
Mikhail Glushenkovf8349ac2009-09-21 15:53:44 +00001383 unsigned IndentLevel,
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00001384 const OptionDescriptions& OptDescs,
Daniel Dunbar1a551802009-07-03 00:10:29 +00001385 raw_ostream& O) {
Mikhail Glushenkovb5ccfbf2008-05-30 06:10:19 +00001386 O << '(';
1387 for (unsigned j = 0, NumArgs = d.getNumArgs(); j < NumArgs; ++j) {
Mikhail Glushenkovffcf3a12008-05-30 06:18:16 +00001388 const DagInit& InnerTest = InitPtrToDag(d.getArg(j));
Mikhail Glushenkovb5ccfbf2008-05-30 06:10:19 +00001389 EmitCaseTest(InnerTest, IndentLevel, OptDescs, O);
Mikhail Glushenkovf8349ac2009-09-21 15:53:44 +00001390 if (j != NumArgs - 1) {
1391 O << ")\n";
1392 O.indent(IndentLevel + Indent1) << ' ' << LogicOp << " (";
1393 }
1394 else {
Mikhail Glushenkovb5ccfbf2008-05-30 06:10:19 +00001395 O << ')';
Mikhail Glushenkovf8349ac2009-09-21 15:53:44 +00001396 }
Mikhail Glushenkovb5ccfbf2008-05-30 06:10:19 +00001397 }
1398}
1399
Mikhail Glushenkovf8349ac2009-09-21 15:53:44 +00001400void EmitLogicalNot(const DagInit& d, unsigned IndentLevel,
Mikhail Glushenkov684a8b02009-09-10 16:21:38 +00001401 const OptionDescriptions& OptDescs, raw_ostream& O)
1402{
Mikhail Glushenkov9bef1bd2009-12-23 12:49:41 +00001403 CheckNumberOfArguments(d, 1);
Mikhail Glushenkov684a8b02009-09-10 16:21:38 +00001404 const DagInit& InnerTest = InitPtrToDag(d.getArg(0));
1405 O << "! (";
1406 EmitCaseTest(InnerTest, IndentLevel, OptDescs, O);
1407 O << ")";
1408}
1409
Mikhail Glushenkovb5ccfbf2008-05-30 06:10:19 +00001410/// EmitCaseTest - Helper function used by EmitCaseConstructHandler.
Mikhail Glushenkovf8349ac2009-09-21 15:53:44 +00001411void EmitCaseTest(const DagInit& d, unsigned IndentLevel,
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00001412 const OptionDescriptions& OptDescs,
Daniel Dunbar1a551802009-07-03 00:10:29 +00001413 raw_ostream& O) {
Mikhail Glushenkov4d21ae72009-10-18 22:51:30 +00001414 const std::string& TestName = GetOperatorName(d);
Mikhail Glushenkovb5ccfbf2008-05-30 06:10:19 +00001415
1416 if (TestName == "and")
1417 EmitLogicalOperationTest(d, "&&", IndentLevel, OptDescs, O);
1418 else if (TestName == "or")
1419 EmitLogicalOperationTest(d, "||", IndentLevel, OptDescs, O);
Mikhail Glushenkov684a8b02009-09-10 16:21:38 +00001420 else if (TestName == "not")
1421 EmitLogicalNot(d, IndentLevel, OptDescs, O);
Mikhail Glushenkovad981bf2009-09-28 01:16:42 +00001422 else if (EmitCaseTest0Args(TestName, O))
1423 return;
Mikhail Glushenkovb5ccfbf2008-05-30 06:10:19 +00001424 else if (EmitCaseTest1Arg(TestName, d, OptDescs, O))
1425 return;
1426 else if (EmitCaseTest2Args(TestName, d, IndentLevel, OptDescs, O))
1427 return;
1428 else
Mikhail Glushenkov163dd592010-01-01 03:50:34 +00001429 throw "Unknown test '" + TestName + "' used in the 'case' construct!";
Mikhail Glushenkovb5ccfbf2008-05-30 06:10:19 +00001430}
1431
Mikhail Glushenkov4d21ae72009-10-18 22:51:30 +00001432
1433/// EmitCaseTestCallback - Callback used by EmitCaseConstructHandler.
1434class EmitCaseTestCallback {
1435 bool EmitElseIf_;
1436 const OptionDescriptions& OptDescs_;
1437 raw_ostream& O_;
1438public:
1439
1440 EmitCaseTestCallback(bool EmitElseIf,
1441 const OptionDescriptions& OptDescs, raw_ostream& O)
1442 : EmitElseIf_(EmitElseIf), OptDescs_(OptDescs), O_(O)
1443 {}
1444
Mikhail Glushenkov24723282009-12-17 07:48:49 +00001445 void operator()(const DagInit& Test, unsigned IndentLevel, bool FirstTest)
Mikhail Glushenkov4d21ae72009-10-18 22:51:30 +00001446 {
1447 if (GetOperatorName(Test) == "default") {
1448 O_.indent(IndentLevel) << "else {\n";
1449 }
1450 else {
1451 O_.indent(IndentLevel)
1452 << ((!FirstTest && EmitElseIf_) ? "else if (" : "if (");
Mikhail Glushenkov24723282009-12-17 07:48:49 +00001453 EmitCaseTest(Test, IndentLevel, OptDescs_, O_);
Mikhail Glushenkov4d21ae72009-10-18 22:51:30 +00001454 O_ << ") {\n";
1455 }
1456 }
1457};
1458
1459/// EmitCaseStatementCallback - Callback used by EmitCaseConstructHandler.
1460template <typename F>
1461class EmitCaseStatementCallback {
1462 F Callback_;
1463 raw_ostream& O_;
1464public:
1465
1466 EmitCaseStatementCallback(F Callback, raw_ostream& O)
1467 : Callback_(Callback), O_(O)
1468 {}
1469
Mikhail Glushenkov4d21ae72009-10-18 22:51:30 +00001470 void operator() (const Init* Statement, unsigned IndentLevel) {
Mikhail Glushenkovccef6de2009-10-19 21:24:28 +00001471
Mikhail Glushenkov4d21ae72009-10-18 22:51:30 +00001472 // Ignore nested 'case' DAG.
1473 if (!(dynamic_cast<const DagInit*>(Statement) &&
Mikhail Glushenkov24723282009-12-17 07:48:49 +00001474 GetOperatorName(static_cast<const DagInit&>(*Statement)) == "case")) {
Mikhail Glushenkovccef6de2009-10-19 21:24:28 +00001475 if (typeid(*Statement) == typeid(ListInit)) {
1476 const ListInit& DagList = *static_cast<const ListInit*>(Statement);
1477 for (ListInit::const_iterator B = DagList.begin(), E = DagList.end();
1478 B != E; ++B)
1479 Callback_(*B, (IndentLevel + Indent1), O_);
1480 }
1481 else {
1482 Callback_(Statement, (IndentLevel + Indent1), O_);
1483 }
1484 }
Mikhail Glushenkov4d21ae72009-10-18 22:51:30 +00001485 O_.indent(IndentLevel) << "}\n";
1486 }
1487
1488};
1489
Mikhail Glushenkov0a22fb62009-10-17 20:09:29 +00001490/// EmitCaseConstructHandler - Emit code that handles the 'case'
1491/// construct. Takes a function object that should emit code for every case
Mikhail Glushenkov4d21ae72009-10-18 22:51:30 +00001492/// clause. Implemented on top of WalkCase.
Mikhail Glushenkov0a22fb62009-10-17 20:09:29 +00001493/// Callback's type is void F(Init* Statement, unsigned IndentLevel,
1494/// raw_ostream& O).
1495/// EmitElseIf parameter controls the type of condition that is emitted ('if
Mikhail Glushenkov4d21ae72009-10-18 22:51:30 +00001496/// (..) {..} else if (..) {} .. else {..}' vs. 'if (..) {..} if(..) {..}
1497/// .. else {..}').
Mikhail Glushenkovb5ccfbf2008-05-30 06:10:19 +00001498template <typename F>
Mikhail Glushenkov4d21ae72009-10-18 22:51:30 +00001499void EmitCaseConstructHandler(const Init* Case, unsigned IndentLevel,
Mikhail Glushenkov310d2eb2008-05-31 13:43:21 +00001500 F Callback, bool EmitElseIf,
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00001501 const OptionDescriptions& OptDescs,
Daniel Dunbar1a551802009-07-03 00:10:29 +00001502 raw_ostream& O) {
Mikhail Glushenkov4d21ae72009-10-18 22:51:30 +00001503 WalkCase(Case, EmitCaseTestCallback(EmitElseIf, OptDescs, O),
1504 EmitCaseStatementCallback<F>(Callback, O), IndentLevel);
Mikhail Glushenkovb5ccfbf2008-05-30 06:10:19 +00001505}
1506
Mikhail Glushenkov2d366a22009-12-17 07:48:34 +00001507/// TokenizeCmdLine - converts from
Mikhail Glushenkov545f9682009-12-15 07:20:50 +00001508/// "$CALL(HookName, 'Arg1', 'Arg2')/path -arg1 -arg2" to
1509/// ["$CALL(", "HookName", "Arg1", "Arg2", ")/path", "-arg1", "-arg2"].
Mikhail Glushenkov2d366a22009-12-17 07:48:34 +00001510void TokenizeCmdLine(const std::string& CmdLine, StrVector& Out) {
Mikhail Glushenkova298bb72009-01-21 13:04:00 +00001511 const char* Delimiters = " \t\n\v\f\r";
1512 enum TokenizerState
1513 { Normal, SpecialCommand, InsideSpecialCommand, InsideQuotationMarks }
1514 cur_st = Normal;
Mikhail Glushenkov7bba2332009-06-25 18:21:34 +00001515
1516 if (CmdLine.empty())
1517 return;
Mikhail Glushenkova298bb72009-01-21 13:04:00 +00001518 Out.push_back("");
1519
1520 std::string::size_type B = CmdLine.find_first_not_of(Delimiters),
1521 E = CmdLine.size();
Mikhail Glushenkov7bba2332009-06-25 18:21:34 +00001522
Mikhail Glushenkova298bb72009-01-21 13:04:00 +00001523 for (; B != E; ++B) {
1524 char cur_ch = CmdLine[B];
1525
1526 switch (cur_st) {
1527 case Normal:
1528 if (cur_ch == '$') {
1529 cur_st = SpecialCommand;
1530 break;
1531 }
Mikhail Glushenkov9bef1bd2009-12-23 12:49:41 +00001532 if (OneOf(Delimiters, cur_ch)) {
Mikhail Glushenkova298bb72009-01-21 13:04:00 +00001533 // Skip whitespace
1534 B = CmdLine.find_first_not_of(Delimiters, B);
1535 if (B == std::string::npos) {
1536 B = E-1;
1537 continue;
1538 }
1539 --B;
1540 Out.push_back("");
1541 continue;
1542 }
1543 break;
1544
1545
1546 case SpecialCommand:
Mikhail Glushenkov9bef1bd2009-12-23 12:49:41 +00001547 if (OneOf(Delimiters, cur_ch)) {
Mikhail Glushenkova298bb72009-01-21 13:04:00 +00001548 cur_st = Normal;
1549 Out.push_back("");
1550 continue;
1551 }
1552 if (cur_ch == '(') {
1553 Out.push_back("");
1554 cur_st = InsideSpecialCommand;
1555 continue;
1556 }
1557 break;
1558
1559 case InsideSpecialCommand:
Mikhail Glushenkov9bef1bd2009-12-23 12:49:41 +00001560 if (OneOf(Delimiters, cur_ch)) {
Mikhail Glushenkova298bb72009-01-21 13:04:00 +00001561 continue;
1562 }
1563 if (cur_ch == '\'') {
1564 cur_st = InsideQuotationMarks;
1565 Out.push_back("");
1566 continue;
1567 }
1568 if (cur_ch == ')') {
1569 cur_st = Normal;
1570 Out.push_back("");
1571 }
1572 if (cur_ch == ',') {
1573 continue;
1574 }
1575
1576 break;
1577
1578 case InsideQuotationMarks:
1579 if (cur_ch == '\'') {
1580 cur_st = InsideSpecialCommand;
1581 continue;
1582 }
1583 break;
1584 }
1585
1586 Out.back().push_back(cur_ch);
1587 }
1588}
1589
Mikhail Glushenkovabf2d982009-12-15 03:04:02 +00001590/// SubstituteCall - Given "$CALL(HookName, [Arg1 [, Arg2 [...]]])", output
1591/// "hooks::HookName([Arg1 [, Arg2 [, ...]]])". Helper function used by
1592/// SubstituteSpecialCommands().
1593StrVector::const_iterator
1594SubstituteCall (StrVector::const_iterator Pos,
1595 StrVector::const_iterator End,
1596 bool IsJoin, raw_ostream& O)
1597{
1598 const char* errorMessage = "Syntax error in $CALL invocation!";
Mikhail Glushenkov9bef1bd2009-12-23 12:49:41 +00001599 CheckedIncrement(Pos, End, errorMessage);
Mikhail Glushenkovabf2d982009-12-15 03:04:02 +00001600 const std::string& CmdName = *Pos;
1601
1602 if (CmdName == ")")
1603 throw "$CALL invocation: empty argument list!";
1604
1605 O << "hooks::";
1606 O << CmdName << "(";
1607
1608
1609 bool firstIteration = true;
1610 while (true) {
Mikhail Glushenkov9bef1bd2009-12-23 12:49:41 +00001611 CheckedIncrement(Pos, End, errorMessage);
Mikhail Glushenkovabf2d982009-12-15 03:04:02 +00001612 const std::string& Arg = *Pos;
1613 assert(Arg.size() != 0);
1614
1615 if (Arg[0] == ')')
1616 break;
1617
1618 if (firstIteration)
1619 firstIteration = false;
1620 else
1621 O << ", ";
1622
1623 if (Arg == "$INFILE") {
1624 if (IsJoin)
1625 throw "$CALL(Hook, $INFILE) can't be used with a Join tool!";
1626 else
1627 O << "inFile.c_str()";
1628 }
1629 else {
1630 O << '"' << Arg << '"';
1631 }
1632 }
1633
1634 O << ')';
1635
1636 return Pos;
1637}
1638
1639/// SubstituteEnv - Given '$ENV(VAR_NAME)', output 'getenv("VAR_NAME")'. Helper
1640/// function used by SubstituteSpecialCommands().
1641StrVector::const_iterator
1642SubstituteEnv (StrVector::const_iterator Pos,
1643 StrVector::const_iterator End, raw_ostream& O)
1644{
1645 const char* errorMessage = "Syntax error in $ENV invocation!";
Mikhail Glushenkov9bef1bd2009-12-23 12:49:41 +00001646 CheckedIncrement(Pos, End, errorMessage);
Mikhail Glushenkovabf2d982009-12-15 03:04:02 +00001647 const std::string& EnvName = *Pos;
1648
1649 if (EnvName == ")")
1650 throw "$ENV invocation: empty argument list!";
1651
1652 O << "checkCString(std::getenv(\"";
1653 O << EnvName;
1654 O << "\"))";
1655
Mikhail Glushenkov9bef1bd2009-12-23 12:49:41 +00001656 CheckedIncrement(Pos, End, errorMessage);
Mikhail Glushenkovabf2d982009-12-15 03:04:02 +00001657
1658 return Pos;
1659}
1660
1661/// SubstituteSpecialCommands - Given an invocation of $CALL or $ENV, output
1662/// handler code. Helper function used by EmitCmdLineVecFill().
1663StrVector::const_iterator
1664SubstituteSpecialCommands (StrVector::const_iterator Pos,
1665 StrVector::const_iterator End,
1666 bool IsJoin, raw_ostream& O)
Mikhail Glushenkova298bb72009-01-21 13:04:00 +00001667{
Mikhail Glushenkov22424562008-05-30 06:13:29 +00001668
Mikhail Glushenkova298bb72009-01-21 13:04:00 +00001669 const std::string& cmd = *Pos;
1670
Mikhail Glushenkovabf2d982009-12-15 03:04:02 +00001671 // Perform substitution.
Mikhail Glushenkova298bb72009-01-21 13:04:00 +00001672 if (cmd == "$CALL") {
Mikhail Glushenkovabf2d982009-12-15 03:04:02 +00001673 Pos = SubstituteCall(Pos, End, IsJoin, O);
Mikhail Glushenkova298bb72009-01-21 13:04:00 +00001674 }
1675 else if (cmd == "$ENV") {
Mikhail Glushenkovabf2d982009-12-15 03:04:02 +00001676 Pos = SubstituteEnv(Pos, End, O);
Mikhail Glushenkov22424562008-05-30 06:13:29 +00001677 }
1678 else {
1679 throw "Unknown special command: " + cmd;
1680 }
1681
Mikhail Glushenkovabf2d982009-12-15 03:04:02 +00001682 // Handle '$CMD(ARG)/additional/text'.
Mikhail Glushenkova298bb72009-01-21 13:04:00 +00001683 const std::string& Leftover = *Pos;
1684 assert(Leftover.at(0) == ')');
1685 if (Leftover.size() != 1)
1686 O << " + std::string(\"" << (Leftover.c_str() + 1) << "\")";
Mikhail Glushenkov22424562008-05-30 06:13:29 +00001687
Mikhail Glushenkova298bb72009-01-21 13:04:00 +00001688 return Pos;
Mikhail Glushenkov08bd2e72008-05-30 06:12:24 +00001689}
1690
1691/// EmitCmdLineVecFill - Emit code that fills in the command line
1692/// vector. Helper function used by EmitGenerateActionMethod().
Mikhail Glushenkovb5ccfbf2008-05-30 06:10:19 +00001693void EmitCmdLineVecFill(const Init* CmdLine, const std::string& ToolName,
Mikhail Glushenkovf8349ac2009-09-21 15:53:44 +00001694 bool IsJoin, unsigned IndentLevel,
Daniel Dunbar1a551802009-07-03 00:10:29 +00001695 raw_ostream& O) {
Mikhail Glushenkovb5ccfbf2008-05-30 06:10:19 +00001696 StrVector StrVec;
Mikhail Glushenkov2d366a22009-12-17 07:48:34 +00001697 TokenizeCmdLine(InitPtrToString(CmdLine), StrVec);
Mikhail Glushenkova298bb72009-01-21 13:04:00 +00001698
Mikhail Glushenkov08bd2e72008-05-30 06:12:24 +00001699 if (StrVec.empty())
Mikhail Glushenkov7bba2332009-06-25 18:21:34 +00001700 throw "Tool '" + ToolName + "' has empty command line!";
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +00001701
Mikhail Glushenkova298bb72009-01-21 13:04:00 +00001702 StrVector::const_iterator I = StrVec.begin(), E = StrVec.end();
1703
1704 // If there is a hook invocation on the place of the first command, skip it.
Mikhail Glushenkov0941b0f2009-04-19 00:22:35 +00001705 assert(!StrVec[0].empty());
Mikhail Glushenkova298bb72009-01-21 13:04:00 +00001706 if (StrVec[0][0] == '$') {
1707 while (I != E && (*I)[0] != ')' )
1708 ++I;
1709
1710 // Skip the ')' symbol.
1711 ++I;
1712 }
1713 else {
1714 ++I;
1715 }
1716
Mikhail Glushenkov39482dd2009-10-08 04:40:08 +00001717 bool hasINFILE = false;
1718
Mikhail Glushenkova298bb72009-01-21 13:04:00 +00001719 for (; I != E; ++I) {
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +00001720 const std::string& cmd = *I;
Mikhail Glushenkov0941b0f2009-04-19 00:22:35 +00001721 assert(!cmd.empty());
Mikhail Glushenkovf8349ac2009-09-21 15:53:44 +00001722 O.indent(IndentLevel);
Mikhail Glushenkov08bd2e72008-05-30 06:12:24 +00001723 if (cmd.at(0) == '$') {
1724 if (cmd == "$INFILE") {
Mikhail Glushenkov39482dd2009-10-08 04:40:08 +00001725 hasINFILE = true;
Mikhail Glushenkovf8349ac2009-09-21 15:53:44 +00001726 if (IsJoin) {
Mikhail Glushenkov08bd2e72008-05-30 06:12:24 +00001727 O << "for (PathVector::const_iterator B = inFiles.begin()"
Mikhail Glushenkovf8349ac2009-09-21 15:53:44 +00001728 << ", E = inFiles.end();\n";
1729 O.indent(IndentLevel) << "B != E; ++B)\n";
1730 O.indent(IndentLevel + Indent1) << "vec.push_back(B->str());\n";
1731 }
1732 else {
Chris Lattner74382b72009-08-23 22:45:37 +00001733 O << "vec.push_back(inFile.str());\n";
Mikhail Glushenkovf8349ac2009-09-21 15:53:44 +00001734 }
Mikhail Glushenkov08bd2e72008-05-30 06:12:24 +00001735 }
1736 else if (cmd == "$OUTFILE") {
Mikhail Glushenkov39482dd2009-10-08 04:40:08 +00001737 O << "vec.push_back(\"\");\n";
1738 O.indent(IndentLevel) << "out_file_index = vec.size()-1;\n";
Mikhail Glushenkov08bd2e72008-05-30 06:12:24 +00001739 }
1740 else {
Mikhail Glushenkova298bb72009-01-21 13:04:00 +00001741 O << "vec.push_back(";
Mikhail Glushenkovabf2d982009-12-15 03:04:02 +00001742 I = SubstituteSpecialCommands(I, E, IsJoin, O);
Mikhail Glushenkov22424562008-05-30 06:13:29 +00001743 O << ");\n";
Mikhail Glushenkov08bd2e72008-05-30 06:12:24 +00001744 }
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +00001745 }
1746 else {
1747 O << "vec.push_back(\"" << cmd << "\");\n";
1748 }
1749 }
Mikhail Glushenkov39482dd2009-10-08 04:40:08 +00001750 if (!hasINFILE)
1751 throw "Tool '" + ToolName + "' doesn't take any input!";
Mikhail Glushenkova298bb72009-01-21 13:04:00 +00001752
Mikhail Glushenkov39482dd2009-10-08 04:40:08 +00001753 O.indent(IndentLevel) << "cmd = ";
Mikhail Glushenkova298bb72009-01-21 13:04:00 +00001754 if (StrVec[0][0] == '$')
Mikhail Glushenkovabf2d982009-12-15 03:04:02 +00001755 SubstituteSpecialCommands(StrVec.begin(), StrVec.end(), IsJoin, O);
Mikhail Glushenkova298bb72009-01-21 13:04:00 +00001756 else
1757 O << '"' << StrVec[0] << '"';
1758 O << ";\n";
Mikhail Glushenkovb5ccfbf2008-05-30 06:10:19 +00001759}
1760
Mikhail Glushenkov08bd2e72008-05-30 06:12:24 +00001761/// EmitCmdLineVecFillCallback - A function object wrapper around
1762/// EmitCmdLineVecFill(). Used by EmitGenerateActionMethod() as an
1763/// argument to EmitCaseConstructHandler().
Mikhail Glushenkovb5ccfbf2008-05-30 06:10:19 +00001764class EmitCmdLineVecFillCallback {
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00001765 bool IsJoin;
Mikhail Glushenkovb5ccfbf2008-05-30 06:10:19 +00001766 const std::string& ToolName;
1767 public:
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00001768 EmitCmdLineVecFillCallback(bool J, const std::string& TN)
1769 : IsJoin(J), ToolName(TN) {}
Mikhail Glushenkovb5ccfbf2008-05-30 06:10:19 +00001770
Mikhail Glushenkovf8349ac2009-09-21 15:53:44 +00001771 void operator()(const Init* Statement, unsigned IndentLevel,
Daniel Dunbar1a551802009-07-03 00:10:29 +00001772 raw_ostream& O) const
Mikhail Glushenkovb5ccfbf2008-05-30 06:10:19 +00001773 {
Mikhail Glushenkovf8349ac2009-09-21 15:53:44 +00001774 EmitCmdLineVecFill(Statement, ToolName, IsJoin, IndentLevel, O);
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00001775 }
1776};
1777
1778/// EmitForwardOptionPropertyHandlingCode - Helper function used to
1779/// implement EmitActionHandler. Emits code for
1780/// handling the (forward) and (forward_as) option properties.
1781void EmitForwardOptionPropertyHandlingCode (const OptionDescription& D,
Mikhail Glushenkovf8349ac2009-09-21 15:53:44 +00001782 unsigned IndentLevel,
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00001783 const std::string& NewName,
Daniel Dunbar1a551802009-07-03 00:10:29 +00001784 raw_ostream& O) {
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00001785 const std::string& Name = NewName.empty()
1786 ? ("-" + D.Name)
1787 : NewName;
Mikhail Glushenkovf8349ac2009-09-21 15:53:44 +00001788 unsigned IndentLevel1 = IndentLevel + Indent1;
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00001789
1790 switch (D.Type) {
1791 case OptionType::Switch:
Mikhail Glushenkovf8349ac2009-09-21 15:53:44 +00001792 O.indent(IndentLevel) << "vec.push_back(\"" << Name << "\");\n";
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00001793 break;
1794 case OptionType::Parameter:
Mikhail Glushenkov0b1a3952010-02-15 03:17:06 +00001795 O.indent(IndentLevel) << "vec.push_back(\"" << Name << "\");\n";
1796 O.indent(IndentLevel) << "vec.push_back(" << D.GenVariableName() << ");\n";
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00001797 break;
1798 case OptionType::Prefix:
Mikhail Glushenkovf8349ac2009-09-21 15:53:44 +00001799 O.indent(IndentLevel) << "vec.push_back(\"" << Name << "\" + "
1800 << D.GenVariableName() << ");\n";
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00001801 break;
1802 case OptionType::PrefixList:
Mikhail Glushenkovf8349ac2009-09-21 15:53:44 +00001803 O.indent(IndentLevel)
1804 << "for (" << D.GenTypeDeclaration()
1805 << "::iterator B = " << D.GenVariableName() << ".begin(),\n";
1806 O.indent(IndentLevel)
1807 << "E = " << D.GenVariableName() << ".end(); B != E;) {\n";
1808 O.indent(IndentLevel1) << "vec.push_back(\"" << Name << "\" + " << "*B);\n";
1809 O.indent(IndentLevel1) << "++B;\n";
Mikhail Glushenkov19d3e822009-01-28 03:47:20 +00001810
1811 for (int i = 1, j = D.MultiVal; i < j; ++i) {
Mikhail Glushenkovf8349ac2009-09-21 15:53:44 +00001812 O.indent(IndentLevel1) << "vec.push_back(*B);\n";
1813 O.indent(IndentLevel1) << "++B;\n";
Mikhail Glushenkov19d3e822009-01-28 03:47:20 +00001814 }
1815
Mikhail Glushenkovf8349ac2009-09-21 15:53:44 +00001816 O.indent(IndentLevel) << "}\n";
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00001817 break;
1818 case OptionType::ParameterList:
Mikhail Glushenkovf8349ac2009-09-21 15:53:44 +00001819 O.indent(IndentLevel)
1820 << "for (" << D.GenTypeDeclaration() << "::iterator B = "
1821 << D.GenVariableName() << ".begin(),\n";
1822 O.indent(IndentLevel) << "E = " << D.GenVariableName()
1823 << ".end() ; B != E;) {\n";
1824 O.indent(IndentLevel1) << "vec.push_back(\"" << Name << "\");\n";
Mikhail Glushenkov19d3e822009-01-28 03:47:20 +00001825
1826 for (int i = 0, j = D.MultiVal; i < j; ++i) {
Mikhail Glushenkovf8349ac2009-09-21 15:53:44 +00001827 O.indent(IndentLevel1) << "vec.push_back(*B);\n";
1828 O.indent(IndentLevel1) << "++B;\n";
Mikhail Glushenkov19d3e822009-01-28 03:47:20 +00001829 }
1830
Mikhail Glushenkovf8349ac2009-09-21 15:53:44 +00001831 O.indent(IndentLevel) << "}\n";
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00001832 break;
1833 case OptionType::Alias:
1834 default:
Mikhail Glushenkov06d26612009-12-07 19:15:57 +00001835 throw "Aliases are not allowed in tool option descriptions!";
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00001836 }
1837}
1838
Mikhail Glushenkovccef6de2009-10-19 21:24:28 +00001839/// ActionHandlingCallbackBase - Base class of EmitActionHandlersCallback and
1840/// EmitPreprocessOptionsCallback.
Mikhail Glushenkov24723282009-12-17 07:48:49 +00001841struct ActionHandlingCallbackBase
1842{
Mikhail Glushenkovccef6de2009-10-19 21:24:28 +00001843
1844 void onErrorDag(const DagInit& d,
1845 unsigned IndentLevel, raw_ostream& O) const
1846 {
1847 O.indent(IndentLevel)
1848 << "throw std::runtime_error(\"" <<
1849 (d.getNumArgs() >= 1 ? InitPtrToString(d.getArg(0))
1850 : "Unknown error!")
1851 << "\");\n";
1852 }
1853
1854 void onWarningDag(const DagInit& d,
1855 unsigned IndentLevel, raw_ostream& O) const
1856 {
Mikhail Glushenkov9bef1bd2009-12-23 12:49:41 +00001857 CheckNumberOfArguments(d, 1);
Mikhail Glushenkovccef6de2009-10-19 21:24:28 +00001858 O.indent(IndentLevel) << "llvm::errs() << \""
1859 << InitPtrToString(d.getArg(0)) << "\";\n";
1860 }
1861
1862};
1863
1864/// EmitActionHandlersCallback - Emit code that handles actions. Used by
1865/// EmitGenerateActionMethod() as an argument to EmitCaseConstructHandler().
Mikhail Glushenkov24723282009-12-17 07:48:49 +00001866
Mikhail Glushenkov632eb202009-12-07 10:51:55 +00001867class EmitActionHandlersCallback;
Mikhail Glushenkov24723282009-12-17 07:48:49 +00001868
Mikhail Glushenkov632eb202009-12-07 10:51:55 +00001869typedef void (EmitActionHandlersCallback::* EmitActionHandlersCallbackHandler)
1870(const DagInit&, unsigned, raw_ostream&) const;
1871
Mikhail Glushenkov24723282009-12-17 07:48:49 +00001872class EmitActionHandlersCallback :
1873 public ActionHandlingCallbackBase,
Mikhail Glushenkov632eb202009-12-07 10:51:55 +00001874 public HandlerTable<EmitActionHandlersCallbackHandler>
1875{
Mikhail Glushenkov632eb202009-12-07 10:51:55 +00001876 typedef EmitActionHandlersCallbackHandler Handler;
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00001877
Mikhail Glushenkov24723282009-12-17 07:48:49 +00001878 const OptionDescriptions& OptDescs;
1879
Mikhail Glushenkov545f9682009-12-15 07:20:50 +00001880 /// EmitHookInvocation - Common code for hook invocation from actions. Used by
1881 /// onAppendCmd and onOutputSuffix.
1882 void EmitHookInvocation(const std::string& Str,
1883 const char* BlockOpen, const char* BlockClose,
1884 unsigned IndentLevel, raw_ostream& O) const
1885 {
1886 StrVector Out;
Mikhail Glushenkov2d366a22009-12-17 07:48:34 +00001887 TokenizeCmdLine(Str, Out);
Mikhail Glushenkov545f9682009-12-15 07:20:50 +00001888
1889 for (StrVector::const_iterator B = Out.begin(), E = Out.end();
1890 B != E; ++B) {
1891 const std::string& cmd = *B;
1892
1893 O.indent(IndentLevel) << BlockOpen;
1894
1895 if (cmd.at(0) == '$')
1896 B = SubstituteSpecialCommands(B, E, /* IsJoin = */ true, O);
1897 else
1898 O << '"' << cmd << '"';
1899
1900 O << BlockClose;
1901 }
1902 }
1903
Mikhail Glushenkov632eb202009-12-07 10:51:55 +00001904 void onAppendCmd (const DagInit& Dag,
1905 unsigned IndentLevel, raw_ostream& O) const
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00001906 {
Mikhail Glushenkov9bef1bd2009-12-23 12:49:41 +00001907 CheckNumberOfArguments(Dag, 1);
Mikhail Glushenkov545f9682009-12-15 07:20:50 +00001908 this->EmitHookInvocation(InitPtrToString(Dag.getArg(0)),
1909 "vec.push_back(", ");\n", IndentLevel, O);
Mikhail Glushenkov632eb202009-12-07 10:51:55 +00001910 }
Mikhail Glushenkovc52551d2009-02-27 06:46:55 +00001911
Mikhail Glushenkov632eb202009-12-07 10:51:55 +00001912 void onForward (const DagInit& Dag,
1913 unsigned IndentLevel, raw_ostream& O) const
1914 {
Mikhail Glushenkov9bef1bd2009-12-23 12:49:41 +00001915 CheckNumberOfArguments(Dag, 1);
Mikhail Glushenkov632eb202009-12-07 10:51:55 +00001916 const std::string& Name = InitPtrToString(Dag.getArg(0));
1917 EmitForwardOptionPropertyHandlingCode(OptDescs.FindOption(Name),
1918 IndentLevel, "", O);
1919 }
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00001920
Mikhail Glushenkov632eb202009-12-07 10:51:55 +00001921 void onForwardAs (const DagInit& Dag,
1922 unsigned IndentLevel, raw_ostream& O) const
1923 {
Mikhail Glushenkov9bef1bd2009-12-23 12:49:41 +00001924 CheckNumberOfArguments(Dag, 2);
Mikhail Glushenkov632eb202009-12-07 10:51:55 +00001925 const std::string& Name = InitPtrToString(Dag.getArg(0));
1926 const std::string& NewName = InitPtrToString(Dag.getArg(1));
1927 EmitForwardOptionPropertyHandlingCode(OptDescs.FindOption(Name),
1928 IndentLevel, NewName, O);
1929 }
Mikhail Glushenkov19d3e822009-01-28 03:47:20 +00001930
Mikhail Glushenkov8245a1d2009-12-07 17:03:05 +00001931 void onForwardValue (const DagInit& Dag,
1932 unsigned IndentLevel, raw_ostream& O) const
1933 {
Mikhail Glushenkov9bef1bd2009-12-23 12:49:41 +00001934 CheckNumberOfArguments(Dag, 1);
Mikhail Glushenkov8245a1d2009-12-07 17:03:05 +00001935 const std::string& Name = InitPtrToString(Dag.getArg(0));
Mikhail Glushenkovbc39a792009-12-07 19:16:13 +00001936 const OptionDescription& D = OptDescs.FindListOrParameter(Name);
Mikhail Glushenkov8245a1d2009-12-07 17:03:05 +00001937
1938 if (D.isParameter()) {
1939 O.indent(IndentLevel) << "vec.push_back("
1940 << D.GenVariableName() << ");\n";
1941 }
Mikhail Glushenkovbc39a792009-12-07 19:16:13 +00001942 else {
Mikhail Glushenkov8245a1d2009-12-07 17:03:05 +00001943 O.indent(IndentLevel) << "std::copy(" << D.GenVariableName()
1944 << ".begin(), " << D.GenVariableName()
1945 << ".end(), std::back_inserter(vec));\n";
1946 }
Mikhail Glushenkov8245a1d2009-12-07 17:03:05 +00001947 }
1948
1949 void onForwardTransformedValue (const DagInit& Dag,
1950 unsigned IndentLevel, raw_ostream& O) const
1951 {
Mikhail Glushenkov9bef1bd2009-12-23 12:49:41 +00001952 CheckNumberOfArguments(Dag, 2);
Mikhail Glushenkov8245a1d2009-12-07 17:03:05 +00001953 const std::string& Name = InitPtrToString(Dag.getArg(0));
1954 const std::string& Hook = InitPtrToString(Dag.getArg(1));
Mikhail Glushenkovbc39a792009-12-07 19:16:13 +00001955 const OptionDescription& D = OptDescs.FindListOrParameter(Name);
Mikhail Glushenkov8245a1d2009-12-07 17:03:05 +00001956
Mikhail Glushenkovbc39a792009-12-07 19:16:13 +00001957 O.indent(IndentLevel) << "vec.push_back(" << "hooks::"
Mikhail Glushenkove4ac23a2009-12-15 03:04:52 +00001958 << Hook << "(" << D.GenVariableName()
1959 << (D.isParameter() ? ".c_str()" : "") << "));\n";
Mikhail Glushenkov8245a1d2009-12-07 17:03:05 +00001960 }
1961
Mikhail Glushenkov632eb202009-12-07 10:51:55 +00001962 void onOutputSuffix (const DagInit& Dag,
1963 unsigned IndentLevel, raw_ostream& O) const
1964 {
Mikhail Glushenkov9bef1bd2009-12-23 12:49:41 +00001965 CheckNumberOfArguments(Dag, 1);
Mikhail Glushenkov545f9682009-12-15 07:20:50 +00001966 this->EmitHookInvocation(InitPtrToString(Dag.getArg(0)),
1967 "output_suffix = ", ";\n", IndentLevel, O);
Mikhail Glushenkov632eb202009-12-07 10:51:55 +00001968 }
1969
1970 void onStopCompilation (const DagInit& Dag,
1971 unsigned IndentLevel, raw_ostream& O) const
1972 {
1973 O.indent(IndentLevel) << "stop_compilation = true;\n";
1974 }
1975
1976
1977 void onUnpackValues (const DagInit& Dag,
1978 unsigned IndentLevel, raw_ostream& O) const
1979 {
Mikhail Glushenkov5b9b3ba2009-12-07 18:25:54 +00001980 throw "'unpack_values' is deprecated. "
1981 "Use 'comma_separated' + 'forward_value' instead!";
Mikhail Glushenkovb5ccfbf2008-05-30 06:10:19 +00001982 }
Mikhail Glushenkov632eb202009-12-07 10:51:55 +00001983
Mikhail Glushenkov08509492008-12-07 16:42:22 +00001984 public:
Mikhail Glushenkov632eb202009-12-07 10:51:55 +00001985
1986 explicit EmitActionHandlersCallback(const OptionDescriptions& OD)
1987 : OptDescs(OD)
1988 {
1989 if (!staticMembersInitialized_) {
1990 AddHandler("error", &EmitActionHandlersCallback::onErrorDag);
1991 AddHandler("warning", &EmitActionHandlersCallback::onWarningDag);
1992 AddHandler("append_cmd", &EmitActionHandlersCallback::onAppendCmd);
1993 AddHandler("forward", &EmitActionHandlersCallback::onForward);
1994 AddHandler("forward_as", &EmitActionHandlersCallback::onForwardAs);
Mikhail Glushenkov8245a1d2009-12-07 17:03:05 +00001995 AddHandler("forward_value", &EmitActionHandlersCallback::onForwardValue);
1996 AddHandler("forward_transformed_value",
1997 &EmitActionHandlersCallback::onForwardTransformedValue);
Mikhail Glushenkov632eb202009-12-07 10:51:55 +00001998 AddHandler("output_suffix", &EmitActionHandlersCallback::onOutputSuffix);
1999 AddHandler("stop_compilation",
2000 &EmitActionHandlersCallback::onStopCompilation);
2001 AddHandler("unpack_values",
2002 &EmitActionHandlersCallback::onUnpackValues);
2003
2004 staticMembersInitialized_ = true;
2005 }
2006 }
Mikhail Glushenkov08509492008-12-07 16:42:22 +00002007
Mikhail Glushenkov24723282009-12-17 07:48:49 +00002008 void operator()(const Init* I,
Mikhail Glushenkovccef6de2009-10-19 21:24:28 +00002009 unsigned IndentLevel, raw_ostream& O) const
Mikhail Glushenkov08509492008-12-07 16:42:22 +00002010 {
Mikhail Glushenkov24723282009-12-17 07:48:49 +00002011 InvokeDagInitHandler(this, I, IndentLevel, O);
Mikhail Glushenkov08509492008-12-07 16:42:22 +00002012 }
Mikhail Glushenkovb5ccfbf2008-05-30 06:10:19 +00002013};
2014
Mikhail Glushenkov0b599392009-10-09 05:45:21 +00002015bool IsOutFileIndexCheckRequiredStr (const Init* CmdLine) {
2016 StrVector StrVec;
Mikhail Glushenkov2d366a22009-12-17 07:48:34 +00002017 TokenizeCmdLine(InitPtrToString(CmdLine), StrVec);
Mikhail Glushenkov0b599392009-10-09 05:45:21 +00002018
2019 for (StrVector::const_iterator I = StrVec.begin(), E = StrVec.end();
2020 I != E; ++I) {
2021 if (*I == "$OUTFILE")
2022 return false;
2023 }
2024
2025 return true;
2026}
2027
2028class IsOutFileIndexCheckRequiredStrCallback {
2029 bool* ret_;
2030
2031public:
2032 IsOutFileIndexCheckRequiredStrCallback(bool* ret) : ret_(ret)
2033 {}
2034
2035 void operator()(const Init* CmdLine) {
Mikhail Glushenkov4d21ae72009-10-18 22:51:30 +00002036 // Ignore nested 'case' DAG.
2037 if (typeid(*CmdLine) == typeid(DagInit))
2038 return;
2039
Mikhail Glushenkov0b599392009-10-09 05:45:21 +00002040 if (IsOutFileIndexCheckRequiredStr(CmdLine))
2041 *ret_ = true;
2042 }
Mikhail Glushenkov4d21ae72009-10-18 22:51:30 +00002043
2044 void operator()(const DagInit* Test, unsigned, bool) {
2045 this->operator()(Test);
2046 }
2047 void operator()(const Init* Statement, unsigned) {
2048 this->operator()(Statement);
2049 }
Mikhail Glushenkov0b599392009-10-09 05:45:21 +00002050};
2051
2052bool IsOutFileIndexCheckRequiredCase (Init* CmdLine) {
2053 bool ret = false;
2054 WalkCase(CmdLine, Id(), IsOutFileIndexCheckRequiredStrCallback(&ret));
2055 return ret;
2056}
2057
2058/// IsOutFileIndexCheckRequired - Should we emit an "out_file_index != -1" check
2059/// in EmitGenerateActionMethod() ?
2060bool IsOutFileIndexCheckRequired (Init* CmdLine) {
2061 if (typeid(*CmdLine) == typeid(StringInit))
2062 return IsOutFileIndexCheckRequiredStr(CmdLine);
2063 else
2064 return IsOutFileIndexCheckRequiredCase(CmdLine);
2065}
2066
Mikhail Glushenkov632eb202009-12-07 10:51:55 +00002067void EmitGenerateActionMethodHeader(const ToolDescription& D,
2068 bool IsJoin, raw_ostream& O)
2069{
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002070 if (IsJoin)
Mikhail Glushenkovf8349ac2009-09-21 15:53:44 +00002071 O.indent(Indent1) << "Action GenerateAction(const PathVector& inFiles,\n";
Mikhail Glushenkovb5ccfbf2008-05-30 06:10:19 +00002072 else
Mikhail Glushenkovf8349ac2009-09-21 15:53:44 +00002073 O.indent(Indent1) << "Action GenerateAction(const sys::Path& inFile,\n";
Mikhail Glushenkovb5ccfbf2008-05-30 06:10:19 +00002074
Mikhail Glushenkovf8349ac2009-09-21 15:53:44 +00002075 O.indent(Indent2) << "bool HasChildren,\n";
2076 O.indent(Indent2) << "const llvm::sys::Path& TempDir,\n";
2077 O.indent(Indent2) << "const InputLanguagesSet& InLangs,\n";
2078 O.indent(Indent2) << "const LanguageMap& LangMap) const\n";
2079 O.indent(Indent1) << "{\n";
2080 O.indent(Indent2) << "std::string cmd;\n";
2081 O.indent(Indent2) << "std::vector<std::string> vec;\n";
2082 O.indent(Indent2) << "bool stop_compilation = !HasChildren;\n";
2083 O.indent(Indent2) << "const char* output_suffix = \""
2084 << D.OutputSuffix << "\";\n";
Mikhail Glushenkov632eb202009-12-07 10:51:55 +00002085}
2086
2087// EmitGenerateActionMethod - Emit either a normal or a "join" version of the
2088// Tool::GenerateAction() method.
2089void EmitGenerateActionMethod (const ToolDescription& D,
2090 const OptionDescriptions& OptDescs,
2091 bool IsJoin, raw_ostream& O) {
2092
2093 EmitGenerateActionMethodHeader(D, IsJoin, O);
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002094
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002095 if (!D.CmdLine)
2096 throw "Tool " + D.Name + " has no cmd_line property!";
Mikhail Glushenkov0b599392009-10-09 05:45:21 +00002097
2098 bool IndexCheckRequired = IsOutFileIndexCheckRequired(D.CmdLine);
2099 O.indent(Indent2) << "int out_file_index"
2100 << (IndexCheckRequired ? " = -1" : "")
2101 << ";\n\n";
2102
2103 // Process the cmd_line property.
2104 if (typeid(*D.CmdLine) == typeid(StringInit))
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002105 EmitCmdLineVecFill(D.CmdLine, D.Name, IsJoin, Indent2, O);
2106 else
2107 EmitCaseConstructHandler(D.CmdLine, Indent2,
2108 EmitCmdLineVecFillCallback(IsJoin, D.Name),
2109 true, OptDescs, O);
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +00002110
Mikhail Glushenkov39482dd2009-10-08 04:40:08 +00002111 // For every understood option, emit handling code.
2112 if (D.Actions)
Mikhail Glushenkovd5a72d92009-10-27 09:02:49 +00002113 EmitCaseConstructHandler(D.Actions, Indent2,
2114 EmitActionHandlersCallback(OptDescs),
Mikhail Glushenkov39482dd2009-10-08 04:40:08 +00002115 false, OptDescs, O);
2116
2117 O << '\n';
2118 O.indent(Indent2)
2119 << "std::string out_file = OutFilename("
2120 << (IsJoin ? "sys::Path(),\n" : "inFile,\n");
2121 O.indent(Indent3) << "TempDir, stop_compilation, output_suffix).str();\n\n";
Mikhail Glushenkov0b599392009-10-09 05:45:21 +00002122
2123 if (IndexCheckRequired)
2124 O.indent(Indent2) << "if (out_file_index != -1)\n";
2125 O.indent(IndexCheckRequired ? Indent3 : Indent2)
2126 << "vec[out_file_index] = out_file;\n";
Mikhail Glushenkov39482dd2009-10-08 04:40:08 +00002127
Mikhail Glushenkov8e7254c2008-05-09 08:27:26 +00002128 // Handle the Sink property.
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002129 if (D.isSink()) {
Mikhail Glushenkovf8349ac2009-09-21 15:53:44 +00002130 O.indent(Indent2) << "if (!" << SinkOptionName << ".empty()) {\n";
2131 O.indent(Indent3) << "vec.insert(vec.end(), "
2132 << SinkOptionName << ".begin(), " << SinkOptionName
2133 << ".end());\n";
2134 O.indent(Indent2) << "}\n";
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +00002135 }
2136
Mikhail Glushenkovf8349ac2009-09-21 15:53:44 +00002137 O.indent(Indent2) << "return Action(cmd, vec, stop_compilation, out_file);\n";
2138 O.indent(Indent1) << "}\n\n";
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +00002139}
2140
Mikhail Glushenkov8e7254c2008-05-09 08:27:26 +00002141/// EmitGenerateActionMethods - Emit two GenerateAction() methods for
2142/// a given Tool class.
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002143void EmitGenerateActionMethods (const ToolDescription& ToolDesc,
2144 const OptionDescriptions& OptDescs,
Daniel Dunbar1a551802009-07-03 00:10:29 +00002145 raw_ostream& O) {
Mikhail Glushenkovf8349ac2009-09-21 15:53:44 +00002146 if (!ToolDesc.isJoin()) {
2147 O.indent(Indent1) << "Action GenerateAction(const PathVector& inFiles,\n";
2148 O.indent(Indent2) << "bool HasChildren,\n";
2149 O.indent(Indent2) << "const llvm::sys::Path& TempDir,\n";
2150 O.indent(Indent2) << "const InputLanguagesSet& InLangs,\n";
2151 O.indent(Indent2) << "const LanguageMap& LangMap) const\n";
2152 O.indent(Indent1) << "{\n";
2153 O.indent(Indent2) << "throw std::runtime_error(\"" << ToolDesc.Name
2154 << " is not a Join tool!\");\n";
2155 O.indent(Indent1) << "}\n\n";
2156 }
2157 else {
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002158 EmitGenerateActionMethod(ToolDesc, OptDescs, true, O);
Mikhail Glushenkovf8349ac2009-09-21 15:53:44 +00002159 }
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +00002160
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002161 EmitGenerateActionMethod(ToolDesc, OptDescs, false, O);
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +00002162}
2163
Mikhail Glushenkov4561ab52008-05-07 21:50:19 +00002164/// EmitInOutLanguageMethods - Emit the [Input,Output]Language()
2165/// methods for a given Tool class.
Daniel Dunbar1a551802009-07-03 00:10:29 +00002166void EmitInOutLanguageMethods (const ToolDescription& D, raw_ostream& O) {
Mikhail Glushenkovf8349ac2009-09-21 15:53:44 +00002167 O.indent(Indent1) << "const char** InputLanguages() const {\n";
2168 O.indent(Indent2) << "return InputLanguages_;\n";
2169 O.indent(Indent1) << "}\n\n";
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +00002170
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002171 if (D.OutLanguage.empty())
2172 throw "Tool " + D.Name + " has no 'out_language' property!";
2173
Mikhail Glushenkovf8349ac2009-09-21 15:53:44 +00002174 O.indent(Indent1) << "const char* OutputLanguage() const {\n";
2175 O.indent(Indent2) << "return \"" << D.OutLanguage << "\";\n";
2176 O.indent(Indent1) << "}\n\n";
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +00002177}
2178
Mikhail Glushenkov4561ab52008-05-07 21:50:19 +00002179/// EmitNameMethod - Emit the Name() method for a given Tool class.
Daniel Dunbar1a551802009-07-03 00:10:29 +00002180void EmitNameMethod (const ToolDescription& D, raw_ostream& O) {
Mikhail Glushenkovf8349ac2009-09-21 15:53:44 +00002181 O.indent(Indent1) << "const char* Name() const {\n";
2182 O.indent(Indent2) << "return \"" << D.Name << "\";\n";
2183 O.indent(Indent1) << "}\n\n";
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +00002184}
2185
Mikhail Glushenkov4561ab52008-05-07 21:50:19 +00002186/// EmitIsJoinMethod - Emit the IsJoin() method for a given Tool
2187/// class.
Daniel Dunbar1a551802009-07-03 00:10:29 +00002188void EmitIsJoinMethod (const ToolDescription& D, raw_ostream& O) {
Mikhail Glushenkovf8349ac2009-09-21 15:53:44 +00002189 O.indent(Indent1) << "bool IsJoin() const {\n";
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002190 if (D.isJoin())
Mikhail Glushenkovf8349ac2009-09-21 15:53:44 +00002191 O.indent(Indent2) << "return true;\n";
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +00002192 else
Mikhail Glushenkovf8349ac2009-09-21 15:53:44 +00002193 O.indent(Indent2) << "return false;\n";
2194 O.indent(Indent1) << "}\n\n";
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +00002195}
2196
Mikhail Glushenkov5fe84752008-05-30 06:24:49 +00002197/// EmitStaticMemberDefinitions - Emit static member definitions for a
2198/// given Tool class.
Daniel Dunbar1a551802009-07-03 00:10:29 +00002199void EmitStaticMemberDefinitions(const ToolDescription& D, raw_ostream& O) {
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002200 if (D.InLanguage.empty())
2201 throw "Tool " + D.Name + " has no 'in_language' property!";
2202
2203 O << "const char* " << D.Name << "::InputLanguages_[] = {";
2204 for (StrVector::const_iterator B = D.InLanguage.begin(),
2205 E = D.InLanguage.end(); B != E; ++B)
Mikhail Glushenkov5fe84752008-05-30 06:24:49 +00002206 O << '\"' << *B << "\", ";
2207 O << "0};\n\n";
2208}
2209
Mikhail Glushenkov4561ab52008-05-07 21:50:19 +00002210/// EmitToolClassDefinition - Emit a Tool class definition.
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002211void EmitToolClassDefinition (const ToolDescription& D,
2212 const OptionDescriptions& OptDescs,
Daniel Dunbar1a551802009-07-03 00:10:29 +00002213 raw_ostream& O) {
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002214 if (D.Name == "root")
Mikhail Glushenkov0d08db02008-05-06 16:35:25 +00002215 return;
2216
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +00002217 // Header
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002218 O << "class " << D.Name << " : public ";
2219 if (D.isJoin())
Mikhail Glushenkovc74bfc92008-05-06 17:26:53 +00002220 O << "JoinTool";
2221 else
2222 O << "Tool";
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +00002223
Mikhail Glushenkovf8bc1e42009-12-15 07:21:14 +00002224 O << " {\nprivate:\n";
Mikhail Glushenkovf8349ac2009-09-21 15:53:44 +00002225 O.indent(Indent1) << "static const char* InputLanguages_[];\n\n";
Mikhail Glushenkov5fe84752008-05-30 06:24:49 +00002226
2227 O << "public:\n";
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002228 EmitNameMethod(D, O);
2229 EmitInOutLanguageMethods(D, O);
2230 EmitIsJoinMethod(D, O);
2231 EmitGenerateActionMethods(D, OptDescs, O);
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +00002232
2233 // Close class definition
Mikhail Glushenkov5fe84752008-05-30 06:24:49 +00002234 O << "};\n";
2235
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002236 EmitStaticMemberDefinitions(D, O);
Mikhail Glushenkov5fe84752008-05-30 06:24:49 +00002237
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +00002238}
2239
Mikhail Glushenkov7c8deb32009-06-23 20:45:07 +00002240/// EmitOptionDefinitions - Iterate over a list of option descriptions
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002241/// and emit registration code.
Mikhail Glushenkov7c8deb32009-06-23 20:45:07 +00002242void EmitOptionDefinitions (const OptionDescriptions& descs,
2243 bool HasSink, bool HasExterns,
Daniel Dunbar1a551802009-07-03 00:10:29 +00002244 raw_ostream& O)
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +00002245{
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002246 std::vector<OptionDescription> Aliases;
Mikhail Glushenkov6be4ffc2008-05-30 06:22:52 +00002247
Mikhail Glushenkov34f37622008-05-30 06:23:29 +00002248 // Emit static cl::Option variables.
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002249 for (OptionDescriptions::const_iterator B = descs.begin(),
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +00002250 E = descs.end(); B!=E; ++B) {
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002251 const OptionDescription& val = B->second;
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +00002252
Mikhail Glushenkov6be4ffc2008-05-30 06:22:52 +00002253 if (val.Type == OptionType::Alias) {
2254 Aliases.push_back(val);
2255 continue;
2256 }
2257
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002258 if (val.isExtern())
2259 O << "extern ";
2260
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +00002261 O << val.GenTypeDeclaration() << ' '
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002262 << val.GenVariableName();
2263
2264 if (val.isExtern()) {
2265 O << ";\n";
2266 continue;
2267 }
2268
Mikhail Glushenkov0cbb5902009-06-23 20:45:31 +00002269 O << "(\"" << val.Name << "\"\n";
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +00002270
2271 if (val.Type == OptionType::Prefix || val.Type == OptionType::PrefixList)
2272 O << ", cl::Prefix";
2273
2274 if (val.isRequired()) {
Mikhail Glushenkovcbc360d2009-07-07 16:08:11 +00002275 if (val.isList() && !val.isMultiVal())
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +00002276 O << ", cl::OneOrMore";
Mikhail Glushenkov19d3e822009-01-28 03:47:20 +00002277 else
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +00002278 O << ", cl::Required";
Mikhail Glushenkov19d3e822009-01-28 03:47:20 +00002279 }
Mikhail Glushenkovcbc360d2009-07-07 16:08:11 +00002280 else if (val.isOneOrMore() && val.isList()) {
Mikhail Glushenkov19d3e822009-01-28 03:47:20 +00002281 O << ", cl::OneOrMore";
2282 }
Mikhail Glushenkove4ac23a2009-12-15 03:04:52 +00002283 else if (val.isOptional() && val.isList()) {
2284 O << ", cl::Optional";
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +00002285 }
2286
Mikhail Glushenkov5b9b3ba2009-12-07 18:25:54 +00002287 if (val.isReallyHidden())
Mikhail Glushenkov19d3e822009-01-28 03:47:20 +00002288 O << ", cl::ReallyHidden";
Mikhail Glushenkov5b9b3ba2009-12-07 18:25:54 +00002289 else if (val.isHidden())
Mikhail Glushenkov19d3e822009-01-28 03:47:20 +00002290 O << ", cl::Hidden";
Mikhail Glushenkov5b9b3ba2009-12-07 18:25:54 +00002291
2292 if (val.isCommaSeparated())
2293 O << ", cl::CommaSeparated";
Mikhail Glushenkov19d3e822009-01-28 03:47:20 +00002294
2295 if (val.MultiVal > 1)
Mikhail Glushenkov8fe44472009-07-07 16:08:41 +00002296 O << ", cl::multi_val(" << val.MultiVal << ')';
2297
2298 if (val.InitVal) {
2299 const std::string& str = val.InitVal->getAsString();
2300 O << ", cl::init(" << str << ')';
2301 }
Mikhail Glushenkov739c7202008-11-28 00:13:25 +00002302
Mikhail Glushenkov6be4ffc2008-05-30 06:22:52 +00002303 if (!val.Help.empty())
2304 O << ", cl::desc(\"" << val.Help << "\")";
2305
Mikhail Glushenkov0cbb5902009-06-23 20:45:31 +00002306 O << ");\n\n";
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +00002307 }
2308
Mikhail Glushenkov6be4ffc2008-05-30 06:22:52 +00002309 // Emit the aliases (they should go after all the 'proper' options).
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002310 for (std::vector<OptionDescription>::const_iterator
Mikhail Glushenkov6be4ffc2008-05-30 06:22:52 +00002311 B = Aliases.begin(), E = Aliases.end(); B != E; ++B) {
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002312 const OptionDescription& val = *B;
Mikhail Glushenkov6be4ffc2008-05-30 06:22:52 +00002313
2314 O << val.GenTypeDeclaration() << ' '
2315 << val.GenVariableName()
2316 << "(\"" << val.Name << '\"';
2317
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002318 const OptionDescription& D = descs.FindOption(val.Help);
2319 O << ", cl::aliasopt(" << D.GenVariableName() << ")";
Mikhail Glushenkov6be4ffc2008-05-30 06:22:52 +00002320
2321 O << ", cl::desc(\"" << "An alias for -" + val.Help << "\"));\n";
2322 }
2323
2324 // Emit the sink option.
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002325 if (HasSink)
Mikhail Glushenkovb59dbad2008-12-07 16:42:47 +00002326 O << (HasExterns ? "extern cl" : "cl")
2327 << "::list<std::string> " << SinkOptionName
2328 << (HasExterns ? ";\n" : "(cl::Sink);\n");
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +00002329
2330 O << '\n';
2331}
2332
Mikhail Glushenkovccef6de2009-10-19 21:24:28 +00002333/// EmitPreprocessOptionsCallback - Helper function passed to
Mikhail Glushenkov0a22fb62009-10-17 20:09:29 +00002334/// EmitCaseConstructHandler() by EmitPreprocessOptions().
Mikhail Glushenkov24723282009-12-17 07:48:49 +00002335
2336class EmitPreprocessOptionsCallback;
2337
2338typedef void
2339(EmitPreprocessOptionsCallback::* EmitPreprocessOptionsCallbackHandler)
2340(const DagInit&, unsigned, raw_ostream&) const;
2341
2342class EmitPreprocessOptionsCallback :
2343 public ActionHandlingCallbackBase,
2344 public HandlerTable<EmitPreprocessOptionsCallbackHandler>
2345{
2346 typedef EmitPreprocessOptionsCallbackHandler Handler;
Mikhail Glushenkov994dbe02009-12-17 07:49:16 +00002347 typedef void
2348 (EmitPreprocessOptionsCallback::* HandlerImpl)
2349 (const Init*, unsigned, raw_ostream&) const;
Mikhail Glushenkov24723282009-12-17 07:48:49 +00002350
Mikhail Glushenkov0a22fb62009-10-17 20:09:29 +00002351 const OptionDescriptions& OptDescs_;
2352
Mikhail Glushenkove0b65702009-12-23 12:49:30 +00002353 void onListOrDag(const DagInit& d, HandlerImpl h,
2354 unsigned IndentLevel, raw_ostream& O) const
Mikhail Glushenkov994dbe02009-12-17 07:49:16 +00002355 {
Mikhail Glushenkov9bef1bd2009-12-23 12:49:41 +00002356 CheckNumberOfArguments(d, 1);
Mikhail Glushenkov994dbe02009-12-17 07:49:16 +00002357 const Init* I = d.getArg(0);
2358
2359 // If I is a list, apply h to each element.
2360 if (typeid(*I) == typeid(ListInit)) {
2361 const ListInit& L = *static_cast<const ListInit*>(I);
2362 for (ListInit::const_iterator B = L.begin(), E = L.end(); B != E; ++B)
2363 ((this)->*(h))(*B, IndentLevel, O);
2364 }
2365 // Otherwise, apply h to I.
2366 else {
2367 ((this)->*(h))(I, IndentLevel, O);
2368 }
2369 }
2370
2371 void onUnsetOptionImpl(const Init* I,
2372 unsigned IndentLevel, raw_ostream& O) const
Mikhail Glushenkov24723282009-12-17 07:48:49 +00002373 {
2374 const std::string& OptName = InitPtrToString(I);
Mikhail Glushenkov0a22fb62009-10-17 20:09:29 +00002375 const OptionDescription& OptDesc = OptDescs_.FindOption(OptName);
Mikhail Glushenkov0a22fb62009-10-17 20:09:29 +00002376
Mikhail Glushenkovb6c34832009-10-22 04:15:07 +00002377 if (OptDesc.isSwitch()) {
Mikhail Glushenkov0a22fb62009-10-17 20:09:29 +00002378 O.indent(IndentLevel) << OptDesc.GenVariableName() << " = false;\n";
2379 }
Mikhail Glushenkovb6c34832009-10-22 04:15:07 +00002380 else if (OptDesc.isParameter()) {
Mikhail Glushenkov0a22fb62009-10-17 20:09:29 +00002381 O.indent(IndentLevel) << OptDesc.GenVariableName() << " = \"\";\n";
2382 }
Mikhail Glushenkovb6c34832009-10-22 04:15:07 +00002383 else if (OptDesc.isList()) {
2384 O.indent(IndentLevel) << OptDesc.GenVariableName() << ".clear();\n";
2385 }
Mikhail Glushenkov0a22fb62009-10-17 20:09:29 +00002386 else {
Mikhail Glushenkov8245a1d2009-12-07 17:03:05 +00002387 throw "Can't apply 'unset_option' to alias option '" + OptName + "'!";
Mikhail Glushenkov0a22fb62009-10-17 20:09:29 +00002388 }
2389 }
2390
Mikhail Glushenkov24723282009-12-17 07:48:49 +00002391 void onUnsetOption(const DagInit& d,
2392 unsigned IndentLevel, raw_ostream& O) const
2393 {
Mikhail Glushenkove0b65702009-12-23 12:49:30 +00002394 this->onListOrDag(d, &EmitPreprocessOptionsCallback::onUnsetOptionImpl,
2395 IndentLevel, O);
Mikhail Glushenkov994dbe02009-12-17 07:49:16 +00002396 }
Mikhail Glushenkov24723282009-12-17 07:48:49 +00002397
Mikhail Glushenkove0b65702009-12-23 12:49:30 +00002398 void onSetOptionImpl(const DagInit& d,
2399 unsigned IndentLevel, raw_ostream& O) const {
Mikhail Glushenkov9bef1bd2009-12-23 12:49:41 +00002400 CheckNumberOfArguments(d, 2);
Mikhail Glushenkov994dbe02009-12-17 07:49:16 +00002401 const std::string& OptName = InitPtrToString(d.getArg(0));
Mikhail Glushenkov9503b492009-12-18 11:27:26 +00002402 const Init* Value = d.getArg(1);
Mikhail Glushenkov994dbe02009-12-17 07:49:16 +00002403 const OptionDescription& OptDesc = OptDescs_.FindOption(OptName);
2404
Mikhail Glushenkov9503b492009-12-18 11:27:26 +00002405 if (OptDesc.isList()) {
2406 const ListInit& List = InitPtrToList(Value);
2407
2408 O.indent(IndentLevel) << OptDesc.GenVariableName() << ".clear();\n";
2409 for (ListInit::const_iterator B = List.begin(), E = List.end();
2410 B != E; ++B) {
2411 O.indent(IndentLevel) << OptDesc.GenVariableName() << ".push_back(\""
2412 << InitPtrToString(*B) << "\");\n";
2413 }
2414 }
Mikhail Glushenkove0b65702009-12-23 12:49:30 +00002415 else if (OptDesc.isSwitch()) {
2416 CheckBooleanConstant(Value);
2417 O.indent(IndentLevel) << OptDesc.GenVariableName()
2418 << " = " << Value->getAsString() << ";\n";
2419 }
Mikhail Glushenkov9503b492009-12-18 11:27:26 +00002420 else if (OptDesc.isParameter()) {
2421 const std::string& Str = InitPtrToString(Value);
Mikhail Glushenkov994dbe02009-12-17 07:49:16 +00002422 O.indent(IndentLevel) << OptDesc.GenVariableName()
Mikhail Glushenkov9503b492009-12-18 11:27:26 +00002423 << " = \"" << Str << "\";\n";
2424 }
2425 else {
Mikhail Glushenkove0b65702009-12-23 12:49:30 +00002426 throw "Can't apply 'set_option' to alias option -" + OptName + " !";
Mikhail Glushenkov9503b492009-12-18 11:27:26 +00002427 }
Mikhail Glushenkov994dbe02009-12-17 07:49:16 +00002428 }
2429
2430 void onSetSwitch(const Init* I,
2431 unsigned IndentLevel, raw_ostream& O) const {
2432 const std::string& OptName = InitPtrToString(I);
2433 const OptionDescription& OptDesc = OptDescs_.FindOption(OptName);
2434
2435 if (OptDesc.isSwitch())
2436 O.indent(IndentLevel) << OptDesc.GenVariableName() << " = true;\n";
2437 else
Mikhail Glushenkov9503b492009-12-18 11:27:26 +00002438 throw "set_option: -" + OptName + " is not a switch option!";
Mikhail Glushenkov994dbe02009-12-17 07:49:16 +00002439 }
2440
2441 void onSetOption(const DagInit& d,
2442 unsigned IndentLevel, raw_ostream& O) const
2443 {
Mikhail Glushenkov9bef1bd2009-12-23 12:49:41 +00002444 CheckNumberOfArguments(d, 1);
Mikhail Glushenkov994dbe02009-12-17 07:49:16 +00002445
Mikhail Glushenkove0b65702009-12-23 12:49:30 +00002446 // Two arguments: (set_option "parameter", VALUE), where VALUE can be a
2447 // boolean, a string or a string list.
Mikhail Glushenkov994dbe02009-12-17 07:49:16 +00002448 if (d.getNumArgs() > 1)
Mikhail Glushenkove0b65702009-12-23 12:49:30 +00002449 this->onSetOptionImpl(d, IndentLevel, O);
Mikhail Glushenkov994dbe02009-12-17 07:49:16 +00002450 // One argument: (set_option "switch")
2451 // or (set_option ["switch1", "switch2", ...])
2452 else
Mikhail Glushenkove0b65702009-12-23 12:49:30 +00002453 this->onListOrDag(d, &EmitPreprocessOptionsCallback::onSetSwitch,
2454 IndentLevel, O);
Mikhail Glushenkov0a22fb62009-10-17 20:09:29 +00002455 }
2456
2457public:
2458
Mikhail Glushenkovccef6de2009-10-19 21:24:28 +00002459 EmitPreprocessOptionsCallback(const OptionDescriptions& OptDescs)
Mikhail Glushenkov0a22fb62009-10-17 20:09:29 +00002460 : OptDescs_(OptDescs)
Mikhail Glushenkov24723282009-12-17 07:48:49 +00002461 {
2462 if (!staticMembersInitialized_) {
2463 AddHandler("error", &EmitPreprocessOptionsCallback::onErrorDag);
2464 AddHandler("warning", &EmitPreprocessOptionsCallback::onWarningDag);
2465 AddHandler("unset_option", &EmitPreprocessOptionsCallback::onUnsetOption);
Mikhail Glushenkov994dbe02009-12-17 07:49:16 +00002466 AddHandler("set_option", &EmitPreprocessOptionsCallback::onSetOption);
Mikhail Glushenkov24723282009-12-17 07:48:49 +00002467
2468 staticMembersInitialized_ = true;
2469 }
2470 }
2471
2472 void operator()(const Init* I,
2473 unsigned IndentLevel, raw_ostream& O) const
2474 {
2475 InvokeDagInitHandler(this, I, IndentLevel, O);
2476 }
2477
Mikhail Glushenkov0a22fb62009-10-17 20:09:29 +00002478};
2479
2480/// EmitPreprocessOptions - Emit the PreprocessOptionsLocal() function.
2481void EmitPreprocessOptions (const RecordKeeper& Records,
2482 const OptionDescriptions& OptDecs, raw_ostream& O)
2483{
2484 O << "void PreprocessOptionsLocal() {\n";
2485
2486 const RecordVector& OptionPreprocessors =
2487 Records.getAllDerivedDefinitions("OptionPreprocessor");
2488
2489 for (RecordVector::const_iterator B = OptionPreprocessors.begin(),
2490 E = OptionPreprocessors.end(); B!=E; ++B) {
2491 DagInit* Case = (*B)->getValueAsDag("preprocessor");
Mikhail Glushenkovccef6de2009-10-19 21:24:28 +00002492 EmitCaseConstructHandler(Case, Indent1,
2493 EmitPreprocessOptionsCallback(OptDecs),
Mikhail Glushenkov0a22fb62009-10-17 20:09:29 +00002494 false, OptDecs, O);
2495 }
2496
2497 O << "}\n\n";
2498}
2499
2500/// EmitPopulateLanguageMap - Emit the PopulateLanguageMapLocal() function.
Daniel Dunbar1a551802009-07-03 00:10:29 +00002501void EmitPopulateLanguageMap (const RecordKeeper& Records, raw_ostream& O)
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +00002502{
Mikhail Glushenkovc82ce4a2008-09-22 20:49:34 +00002503 O << "void PopulateLanguageMapLocal(LanguageMap& langMap) {\n";
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +00002504
Mikhail Glushenkov01088772008-11-17 17:29:18 +00002505 // Get the relevant field out of RecordKeeper
Mikhail Glushenkovfa270772008-11-17 17:29:42 +00002506 const Record* LangMapRecord = Records.getDef("LanguageMap");
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +00002507
Mikhail Glushenkov01088772008-11-17 17:29:18 +00002508 // It is allowed for a plugin to have no language map.
2509 if (LangMapRecord) {
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +00002510
Mikhail Glushenkov01088772008-11-17 17:29:18 +00002511 ListInit* LangsToSuffixesList = LangMapRecord->getValueAsListInit("map");
2512 if (!LangsToSuffixesList)
Mikhail Glushenkov06d26612009-12-07 19:15:57 +00002513 throw "Error in the language map definition!";
Mikhail Glushenkov01088772008-11-17 17:29:18 +00002514
2515 for (unsigned i = 0; i < LangsToSuffixesList->size(); ++i) {
Mikhail Glushenkovfa270772008-11-17 17:29:42 +00002516 const Record* LangToSuffixes = LangsToSuffixesList->getElementAsRecord(i);
Mikhail Glushenkov01088772008-11-17 17:29:18 +00002517
2518 const std::string& Lang = LangToSuffixes->getValueAsString("lang");
2519 const ListInit* Suffixes = LangToSuffixes->getValueAsListInit("suffixes");
2520
2521 for (unsigned i = 0; i < Suffixes->size(); ++i)
Mikhail Glushenkovf8349ac2009-09-21 15:53:44 +00002522 O.indent(Indent1) << "langMap[\""
2523 << InitPtrToString(Suffixes->getElement(i))
2524 << "\"] = \"" << Lang << "\";\n";
Mikhail Glushenkov01088772008-11-17 17:29:18 +00002525 }
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +00002526 }
2527
Mikhail Glushenkove1d44b52008-12-11 10:34:18 +00002528 O << "}\n\n";
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +00002529}
2530
Mikhail Glushenkov08bd2e72008-05-30 06:12:24 +00002531/// IncDecWeight - Helper function passed to EmitCaseConstructHandler()
2532/// by EmitEdgeClass().
Mikhail Glushenkovf8349ac2009-09-21 15:53:44 +00002533void IncDecWeight (const Init* i, unsigned IndentLevel,
Daniel Dunbar1a551802009-07-03 00:10:29 +00002534 raw_ostream& O) {
Mikhail Glushenkovffcf3a12008-05-30 06:18:16 +00002535 const DagInit& d = InitPtrToDag(i);
Mikhail Glushenkov4d21ae72009-10-18 22:51:30 +00002536 const std::string& OpName = GetOperatorName(d);
Mikhail Glushenkove5557f42008-05-30 06:08:50 +00002537
Mikhail Glushenkov5c2b6b22008-12-17 02:47:01 +00002538 if (OpName == "inc_weight") {
Mikhail Glushenkovf8349ac2009-09-21 15:53:44 +00002539 O.indent(IndentLevel) << "ret += ";
Mikhail Glushenkov5c2b6b22008-12-17 02:47:01 +00002540 }
2541 else if (OpName == "dec_weight") {
Mikhail Glushenkovf8349ac2009-09-21 15:53:44 +00002542 O.indent(IndentLevel) << "ret -= ";
Mikhail Glushenkov5c2b6b22008-12-17 02:47:01 +00002543 }
2544 else if (OpName == "error") {
Mikhail Glushenkov9bef1bd2009-12-23 12:49:41 +00002545 CheckNumberOfArguments(d, 1);
Mikhail Glushenkov0a22fb62009-10-17 20:09:29 +00002546 O.indent(IndentLevel) << "throw std::runtime_error(\""
2547 << InitPtrToString(d.getArg(0))
2548 << "\");\n";
Mikhail Glushenkov5c2b6b22008-12-17 02:47:01 +00002549 return;
2550 }
Mikhail Glushenkov0a22fb62009-10-17 20:09:29 +00002551 else {
2552 throw "Unknown operator in edge properties list: '" + OpName + "'!"
Mikhail Glushenkov65ee1e62008-12-18 04:06:58 +00002553 "\nOnly 'inc_weight', 'dec_weight' and 'error' are allowed.";
Mikhail Glushenkov0a22fb62009-10-17 20:09:29 +00002554 }
Mikhail Glushenkove5557f42008-05-30 06:08:50 +00002555
2556 if (d.getNumArgs() > 0)
2557 O << InitPtrToInt(d.getArg(0)) << ";\n";
2558 else
2559 O << "2;\n";
2560
Mikhail Glushenkov29063552008-05-06 18:18:20 +00002561}
2562
Mikhail Glushenkov4561ab52008-05-07 21:50:19 +00002563/// EmitEdgeClass - Emit a single Edge# class.
Mikhail Glushenkovb5ccfbf2008-05-30 06:10:19 +00002564void EmitEdgeClass (unsigned N, const std::string& Target,
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002565 DagInit* Case, const OptionDescriptions& OptDescs,
Daniel Dunbar1a551802009-07-03 00:10:29 +00002566 raw_ostream& O) {
Mikhail Glushenkov9ef501b2008-05-06 17:23:14 +00002567
2568 // Class constructor.
2569 O << "class Edge" << N << ": public Edge {\n"
Mikhail Glushenkovf8349ac2009-09-21 15:53:44 +00002570 << "public:\n";
2571 O.indent(Indent1) << "Edge" << N << "() : Edge(\"" << Target
2572 << "\") {}\n\n";
Mikhail Glushenkov9ef501b2008-05-06 17:23:14 +00002573
Mikhail Glushenkovbb8b58d2008-05-06 18:14:24 +00002574 // Function Weight().
Mikhail Glushenkovf8349ac2009-09-21 15:53:44 +00002575 O.indent(Indent1)
2576 << "unsigned Weight(const InputLanguagesSet& InLangs) const {\n";
2577 O.indent(Indent2) << "unsigned ret = 0;\n";
Mikhail Glushenkov9ef501b2008-05-06 17:23:14 +00002578
Mikhail Glushenkove5557f42008-05-30 06:08:50 +00002579 // Handle the 'case' construct.
Mikhail Glushenkov2d0dc9a2008-05-30 06:22:15 +00002580 EmitCaseConstructHandler(Case, Indent2, IncDecWeight, false, OptDescs, O);
Mikhail Glushenkovbb8b58d2008-05-06 18:14:24 +00002581
Mikhail Glushenkovf8349ac2009-09-21 15:53:44 +00002582 O.indent(Indent2) << "return ret;\n";
Daniel Dunbar96a47822009-12-24 17:49:28 +00002583 O.indent(Indent1) << "}\n\n};\n\n";
Mikhail Glushenkov9ef501b2008-05-06 17:23:14 +00002584}
2585
Mikhail Glushenkov08bd2e72008-05-30 06:12:24 +00002586/// EmitEdgeClasses - Emit Edge* classes that represent graph edges.
Mikhail Glushenkovad746be2008-11-28 00:13:47 +00002587void EmitEdgeClasses (const RecordVector& EdgeVector,
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002588 const OptionDescriptions& OptDescs,
Daniel Dunbar1a551802009-07-03 00:10:29 +00002589 raw_ostream& O) {
Mikhail Glushenkovad746be2008-11-28 00:13:47 +00002590 int i = 0;
Mikhail Glushenkov15b71ba2008-12-07 16:44:47 +00002591 for (RecordVector::const_iterator B = EdgeVector.begin(),
2592 E = EdgeVector.end(); B != E; ++B) {
2593 const Record* Edge = *B;
2594 const std::string& NodeB = Edge->getValueAsString("b");
Mikhail Glushenkov24723282009-12-17 07:48:49 +00002595 DagInit& Weight = *Edge->getValueAsDag("weight");
Mikhail Glushenkov0a174932008-05-06 16:36:06 +00002596
Mikhail Glushenkov9bef1bd2009-12-23 12:49:41 +00002597 if (!IsDagEmpty(Weight))
Mikhail Glushenkov24723282009-12-17 07:48:49 +00002598 EmitEdgeClass(i, NodeB, &Weight, OptDescs, O);
Mikhail Glushenkovad746be2008-11-28 00:13:47 +00002599 ++i;
Mikhail Glushenkov0a174932008-05-06 16:36:06 +00002600 }
2601}
2602
Mikhail Glushenkov0a22fb62009-10-17 20:09:29 +00002603/// EmitPopulateCompilationGraph - Emit the PopulateCompilationGraphLocal()
Mikhail Glushenkov4561ab52008-05-07 21:50:19 +00002604/// function.
Mikhail Glushenkovad746be2008-11-28 00:13:47 +00002605void EmitPopulateCompilationGraph (const RecordVector& EdgeVector,
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002606 const ToolDescriptions& ToolDescs,
Daniel Dunbar1a551802009-07-03 00:10:29 +00002607 raw_ostream& O)
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +00002608{
Mikhail Glushenkovc82ce4a2008-09-22 20:49:34 +00002609 O << "void PopulateCompilationGraphLocal(CompilationGraph& G) {\n";
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +00002610
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002611 for (ToolDescriptions::const_iterator B = ToolDescs.begin(),
2612 E = ToolDescs.end(); B != E; ++B)
Mikhail Glushenkovf8349ac2009-09-21 15:53:44 +00002613 O.indent(Indent1) << "G.insertNode(new " << (*B)->Name << "());\n";
Mikhail Glushenkov262d2482008-11-12 00:05:17 +00002614
Mikhail Glushenkov0d08db02008-05-06 16:35:25 +00002615 O << '\n';
2616
Mikhail Glushenkov262d2482008-11-12 00:05:17 +00002617 // Insert edges.
2618
Mikhail Glushenkovad746be2008-11-28 00:13:47 +00002619 int i = 0;
Mikhail Glushenkov15b71ba2008-12-07 16:44:47 +00002620 for (RecordVector::const_iterator B = EdgeVector.begin(),
2621 E = EdgeVector.end(); B != E; ++B) {
2622 const Record* Edge = *B;
2623 const std::string& NodeA = Edge->getValueAsString("a");
2624 const std::string& NodeB = Edge->getValueAsString("b");
Mikhail Glushenkov24723282009-12-17 07:48:49 +00002625 DagInit& Weight = *Edge->getValueAsDag("weight");
Mikhail Glushenkovd752c3f2008-05-06 16:36:50 +00002626
Mikhail Glushenkovf8349ac2009-09-21 15:53:44 +00002627 O.indent(Indent1) << "G.insertEdge(\"" << NodeA << "\", ";
Mikhail Glushenkovd752c3f2008-05-06 16:36:50 +00002628
Mikhail Glushenkov9bef1bd2009-12-23 12:49:41 +00002629 if (IsDagEmpty(Weight))
Mikhail Glushenkov15b71ba2008-12-07 16:44:47 +00002630 O << "new SimpleEdge(\"" << NodeB << "\")";
Mikhail Glushenkovd752c3f2008-05-06 16:36:50 +00002631 else
2632 O << "new Edge" << i << "()";
2633
2634 O << ");\n";
Mikhail Glushenkovad746be2008-11-28 00:13:47 +00002635 ++i;
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +00002636 }
2637
Mikhail Glushenkove1d44b52008-12-11 10:34:18 +00002638 O << "}\n\n";
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +00002639}
2640
Mikhail Glushenkov8245a1d2009-12-07 17:03:05 +00002641/// HookInfo - Information about the hook type and number of arguments.
2642struct HookInfo {
2643
2644 // A hook can either have a single parameter of type std::vector<std::string>,
2645 // or NumArgs parameters of type const char*.
2646 enum HookType { ListHook, ArgHook };
2647
2648 HookType Type;
2649 unsigned NumArgs;
2650
2651 HookInfo() : Type(ArgHook), NumArgs(1)
2652 {}
2653
2654 HookInfo(HookType T) : Type(T), NumArgs(1)
2655 {}
2656
2657 HookInfo(unsigned N) : Type(ArgHook), NumArgs(N)
2658 {}
2659};
2660
2661typedef llvm::StringMap<HookInfo> HookInfoMap;
2662
Mikhail Glushenkov08bd2e72008-05-30 06:12:24 +00002663/// ExtractHookNames - Extract the hook names from all instances of
Mikhail Glushenkov8245a1d2009-12-07 17:03:05 +00002664/// $CALL(HookName) in the provided command line string/action. Helper
Mikhail Glushenkov08bd2e72008-05-30 06:12:24 +00002665/// function used by FillInHookNames().
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002666class ExtractHookNames {
Mikhail Glushenkov8245a1d2009-12-07 17:03:05 +00002667 HookInfoMap& HookNames_;
2668 const OptionDescriptions& OptDescs_;
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002669public:
Mikhail Glushenkov8245a1d2009-12-07 17:03:05 +00002670 ExtractHookNames(HookInfoMap& HookNames, const OptionDescriptions& OptDescs)
2671 : HookNames_(HookNames), OptDescs_(OptDescs)
2672 {}
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002673
Mikhail Glushenkov8245a1d2009-12-07 17:03:05 +00002674 void onAction (const DagInit& Dag) {
Mikhail Glushenkov545f9682009-12-15 07:20:50 +00002675 const std::string& Name = GetOperatorName(Dag);
2676
2677 if (Name == "forward_transformed_value") {
Mikhail Glushenkov9bef1bd2009-12-23 12:49:41 +00002678 CheckNumberOfArguments(Dag, 2);
Mikhail Glushenkov8245a1d2009-12-07 17:03:05 +00002679 const std::string& OptName = InitPtrToString(Dag.getArg(0));
2680 const std::string& HookName = InitPtrToString(Dag.getArg(1));
2681 const OptionDescription& D = OptDescs_.FindOption(OptName);
Mikhail Glushenkov4d21ae72009-10-18 22:51:30 +00002682
Mikhail Glushenkov8245a1d2009-12-07 17:03:05 +00002683 HookNames_[HookName] = HookInfo(D.isList() ? HookInfo::ListHook
2684 : HookInfo::ArgHook);
2685 }
Mikhail Glushenkov545f9682009-12-15 07:20:50 +00002686 else if (Name == "append_cmd" || Name == "output_suffix") {
Mikhail Glushenkov9bef1bd2009-12-23 12:49:41 +00002687 CheckNumberOfArguments(Dag, 1);
Mikhail Glushenkov545f9682009-12-15 07:20:50 +00002688 this->onCmdLine(InitPtrToString(Dag.getArg(0)));
2689 }
2690 }
2691
2692 void onCmdLine(const std::string& Cmd) {
2693 StrVector cmds;
Mikhail Glushenkov2d366a22009-12-17 07:48:34 +00002694 TokenizeCmdLine(Cmd, cmds);
Mikhail Glushenkov545f9682009-12-15 07:20:50 +00002695
2696 for (StrVector::const_iterator B = cmds.begin(), E = cmds.end();
2697 B != E; ++B) {
2698 const std::string& cmd = *B;
2699
2700 if (cmd == "$CALL") {
2701 unsigned NumArgs = 0;
Mikhail Glushenkov9bef1bd2009-12-23 12:49:41 +00002702 CheckedIncrement(B, E, "Syntax error in $CALL invocation!");
Mikhail Glushenkov545f9682009-12-15 07:20:50 +00002703 const std::string& HookName = *B;
2704
2705 if (HookName.at(0) == ')')
2706 throw "$CALL invoked with no arguments!";
2707
2708 while (++B != E && B->at(0) != ')') {
2709 ++NumArgs;
2710 }
2711
2712 HookInfoMap::const_iterator H = HookNames_.find(HookName);
2713
2714 if (H != HookNames_.end() && H->second.NumArgs != NumArgs &&
2715 H->second.Type != HookInfo::ArgHook)
2716 throw "Overloading of hooks is not allowed. Overloaded hook: "
2717 + HookName;
2718 else
2719 HookNames_[HookName] = HookInfo(NumArgs);
2720 }
2721 }
Mikhail Glushenkov8245a1d2009-12-07 17:03:05 +00002722 }
2723
2724 void operator()(const Init* Arg) {
2725
2726 // We're invoked on an action (either a dag or a dag list).
2727 if (typeid(*Arg) == typeid(DagInit)) {
2728 const DagInit& Dag = InitPtrToDag(Arg);
2729 this->onAction(Dag);
Mikhail Glushenkov4d21ae72009-10-18 22:51:30 +00002730 return;
Mikhail Glushenkov8245a1d2009-12-07 17:03:05 +00002731 }
2732 else if (typeid(*Arg) == typeid(ListInit)) {
2733 const ListInit& List = InitPtrToList(Arg);
2734 for (ListInit::const_iterator B = List.begin(), E = List.end(); B != E;
2735 ++B) {
2736 const DagInit& Dag = InitPtrToDag(*B);
2737 this->onAction(Dag);
2738 }
2739 return;
2740 }
Mikhail Glushenkov4d21ae72009-10-18 22:51:30 +00002741
Mikhail Glushenkov8245a1d2009-12-07 17:03:05 +00002742 // We're invoked on a command line.
Mikhail Glushenkov545f9682009-12-15 07:20:50 +00002743 this->onCmdLine(InitPtrToString(Arg));
Mikhail Glushenkov08bd2e72008-05-30 06:12:24 +00002744 }
Mikhail Glushenkov4d21ae72009-10-18 22:51:30 +00002745
2746 void operator()(const DagInit* Test, unsigned, bool) {
2747 this->operator()(Test);
2748 }
2749 void operator()(const Init* Statement, unsigned) {
2750 this->operator()(Statement);
2751 }
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002752};
Mikhail Glushenkov2d0dc9a2008-05-30 06:22:15 +00002753
Mikhail Glushenkov08bd2e72008-05-30 06:12:24 +00002754/// FillInHookNames - Actually extract the hook names from all command
2755/// line strings. Helper function used by EmitHookDeclarations().
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002756void FillInHookNames(const ToolDescriptions& ToolDescs,
Mikhail Glushenkov8245a1d2009-12-07 17:03:05 +00002757 const OptionDescriptions& OptDescs,
2758 HookInfoMap& HookNames)
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002759{
Mikhail Glushenkov8245a1d2009-12-07 17:03:05 +00002760 // For all tool descriptions:
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002761 for (ToolDescriptions::const_iterator B = ToolDescs.begin(),
2762 E = ToolDescs.end(); B != E; ++B) {
2763 const ToolDescription& D = *(*B);
Mikhail Glushenkov8245a1d2009-12-07 17:03:05 +00002764
2765 // Look for 'forward_transformed_value' in 'actions'.
2766 if (D.Actions)
2767 WalkCase(D.Actions, Id(), ExtractHookNames(HookNames, OptDescs));
2768
2769 // Look for hook invocations in 'cmd_line'.
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002770 if (!D.CmdLine)
Mikhail Glushenkov08bd2e72008-05-30 06:12:24 +00002771 continue;
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002772 if (dynamic_cast<StringInit*>(D.CmdLine))
Mikhail Glushenkov08bd2e72008-05-30 06:12:24 +00002773 // This is a string.
Mikhail Glushenkov8245a1d2009-12-07 17:03:05 +00002774 ExtractHookNames(HookNames, OptDescs).operator()(D.CmdLine);
Mikhail Glushenkov2d0dc9a2008-05-30 06:22:15 +00002775 else
Mikhail Glushenkov08bd2e72008-05-30 06:12:24 +00002776 // This is a 'case' construct.
Mikhail Glushenkov8245a1d2009-12-07 17:03:05 +00002777 WalkCase(D.CmdLine, Id(), ExtractHookNames(HookNames, OptDescs));
Mikhail Glushenkov08bd2e72008-05-30 06:12:24 +00002778 }
2779}
2780
2781/// EmitHookDeclarations - Parse CmdLine fields of all the tool
2782/// property records and emit hook function declaration for each
2783/// instance of $CALL(HookName).
Mikhail Glushenkov8245a1d2009-12-07 17:03:05 +00002784void EmitHookDeclarations(const ToolDescriptions& ToolDescs,
2785 const OptionDescriptions& OptDescs, raw_ostream& O) {
2786 HookInfoMap HookNames;
Mikhail Glushenkova298bb72009-01-21 13:04:00 +00002787
Mikhail Glushenkov8245a1d2009-12-07 17:03:05 +00002788 FillInHookNames(ToolDescs, OptDescs, HookNames);
Mikhail Glushenkov08bd2e72008-05-30 06:12:24 +00002789 if (HookNames.empty())
2790 return;
Mikhail Glushenkov08bd2e72008-05-30 06:12:24 +00002791
2792 O << "namespace hooks {\n";
Mikhail Glushenkov8245a1d2009-12-07 17:03:05 +00002793 for (HookInfoMap::const_iterator B = HookNames.begin(),
Mikhail Glushenkova298bb72009-01-21 13:04:00 +00002794 E = HookNames.end(); B != E; ++B) {
Mikhail Glushenkov8245a1d2009-12-07 17:03:05 +00002795 const char* HookName = B->first();
2796 const HookInfo& Info = B->second;
Mikhail Glushenkov08bd2e72008-05-30 06:12:24 +00002797
Mikhail Glushenkov8245a1d2009-12-07 17:03:05 +00002798 O.indent(Indent1) << "std::string " << HookName << "(";
2799
2800 if (Info.Type == HookInfo::ArgHook) {
2801 for (unsigned i = 0, j = Info.NumArgs; i < j; ++i) {
2802 O << "const char* Arg" << i << (i+1 == j ? "" : ", ");
2803 }
2804 }
2805 else {
2806 O << "const std::vector<std::string>& Arg";
Mikhail Glushenkova298bb72009-01-21 13:04:00 +00002807 }
2808
2809 O <<");\n";
2810 }
Mikhail Glushenkov08bd2e72008-05-30 06:12:24 +00002811 O << "}\n\n";
2812}
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +00002813
Mikhail Glushenkovc82ce4a2008-09-22 20:49:34 +00002814/// EmitRegisterPlugin - Emit code to register this plugin.
Daniel Dunbar1a551802009-07-03 00:10:29 +00002815void EmitRegisterPlugin(int Priority, raw_ostream& O) {
Mikhail Glushenkovf8349ac2009-09-21 15:53:44 +00002816 O << "struct Plugin : public llvmc::BasePlugin {\n\n";
2817 O.indent(Indent1) << "int Priority() const { return "
2818 << Priority << "; }\n\n";
Mikhail Glushenkov0a22fb62009-10-17 20:09:29 +00002819 O.indent(Indent1) << "void PreprocessOptions() const\n";
2820 O.indent(Indent1) << "{ PreprocessOptionsLocal(); }\n\n";
Mikhail Glushenkovf8349ac2009-09-21 15:53:44 +00002821 O.indent(Indent1) << "void PopulateLanguageMap(LanguageMap& langMap) const\n";
2822 O.indent(Indent1) << "{ PopulateLanguageMapLocal(langMap); }\n\n";
2823 O.indent(Indent1)
2824 << "void PopulateCompilationGraph(CompilationGraph& graph) const\n";
2825 O.indent(Indent1) << "{ PopulateCompilationGraphLocal(graph); }\n"
2826 << "};\n\n"
2827 << "static llvmc::RegisterPlugin<Plugin> RP;\n\n";
Mikhail Glushenkovc82ce4a2008-09-22 20:49:34 +00002828}
2829
Mikhail Glushenkov67665722008-11-12 12:41:18 +00002830/// EmitIncludes - Emit necessary #include directives and some
2831/// additional declarations.
Daniel Dunbar1a551802009-07-03 00:10:29 +00002832void EmitIncludes(raw_ostream& O) {
Mikhail Glushenkovad981bf2009-09-28 01:16:42 +00002833 O << "#include \"llvm/CompilerDriver/BuiltinOptions.h\"\n"
2834 << "#include \"llvm/CompilerDriver/CompilationGraph.h\"\n"
Mikhail Glushenkovd80d8692009-06-23 20:46:48 +00002835 << "#include \"llvm/CompilerDriver/ForceLinkageMacros.h\"\n"
Mikhail Glushenkov4a1a77c2008-09-22 20:50:40 +00002836 << "#include \"llvm/CompilerDriver/Plugin.h\"\n"
2837 << "#include \"llvm/CompilerDriver/Tool.h\"\n\n"
Mikhail Glushenkovc82ce4a2008-09-22 20:49:34 +00002838
Mikhail Glushenkov0a22fb62009-10-17 20:09:29 +00002839 << "#include \"llvm/Support/CommandLine.h\"\n"
2840 << "#include \"llvm/Support/raw_ostream.h\"\n\n"
Mikhail Glushenkovc82ce4a2008-09-22 20:49:34 +00002841
Mikhail Glushenkov8245a1d2009-12-07 17:03:05 +00002842 << "#include <algorithm>\n"
Mikhail Glushenkovc82ce4a2008-09-22 20:49:34 +00002843 << "#include <cstdlib>\n"
Mikhail Glushenkov8245a1d2009-12-07 17:03:05 +00002844 << "#include <iterator>\n"
Mikhail Glushenkovc82ce4a2008-09-22 20:49:34 +00002845 << "#include <stdexcept>\n\n"
2846
2847 << "using namespace llvm;\n"
2848 << "using namespace llvmc;\n\n"
2849
Mikhail Glushenkov67665722008-11-12 12:41:18 +00002850 << "extern cl::opt<std::string> OutputFilename;\n\n"
2851
2852 << "inline const char* checkCString(const char* s)\n"
2853 << "{ return s == NULL ? \"\" : s; }\n\n";
Mikhail Glushenkovc82ce4a2008-09-22 20:49:34 +00002854}
2855
Mikhail Glushenkovfa270772008-11-17 17:29:42 +00002856
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002857/// PluginData - Holds all information about a plugin.
2858struct PluginData {
2859 OptionDescriptions OptDescs;
2860 bool HasSink;
Mikhail Glushenkovb59dbad2008-12-07 16:42:47 +00002861 bool HasExterns;
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002862 ToolDescriptions ToolDescs;
2863 RecordVector Edges;
2864 int Priority;
Mikhail Glushenkovfa270772008-11-17 17:29:42 +00002865};
2866
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002867/// HasSink - Go through the list of tool descriptions and check if
Mikhail Glushenkovb59dbad2008-12-07 16:42:47 +00002868/// there are any with the 'sink' property set.
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002869bool HasSink(const ToolDescriptions& ToolDescs) {
2870 for (ToolDescriptions::const_iterator B = ToolDescs.begin(),
2871 E = ToolDescs.end(); B != E; ++B)
2872 if ((*B)->isSink())
2873 return true;
Mikhail Glushenkovfa270772008-11-17 17:29:42 +00002874
Mikhail Glushenkovb59dbad2008-12-07 16:42:47 +00002875 return false;
2876}
2877
2878/// HasExterns - Go through the list of option descriptions and check
2879/// if there are any external options.
2880bool HasExterns(const OptionDescriptions& OptDescs) {
2881 for (OptionDescriptions::const_iterator B = OptDescs.begin(),
2882 E = OptDescs.end(); B != E; ++B)
2883 if (B->second.isExtern())
2884 return true;
2885
2886 return false;
Mikhail Glushenkovfa270772008-11-17 17:29:42 +00002887}
2888
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002889/// CollectPluginData - Collect tool and option properties,
2890/// compilation graph edges and plugin priority from the parse tree.
2891void CollectPluginData (const RecordKeeper& Records, PluginData& Data) {
2892 // Collect option properties.
2893 const RecordVector& OptionLists =
2894 Records.getAllDerivedDefinitions("OptionList");
2895 CollectOptionDescriptions(OptionLists.begin(), OptionLists.end(),
2896 Data.OptDescs);
2897
2898 // Collect tool properties.
2899 const RecordVector& Tools = Records.getAllDerivedDefinitions("Tool");
2900 CollectToolDescriptions(Tools.begin(), Tools.end(), Data.ToolDescs);
2901 Data.HasSink = HasSink(Data.ToolDescs);
Mikhail Glushenkovb59dbad2008-12-07 16:42:47 +00002902 Data.HasExterns = HasExterns(Data.OptDescs);
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002903
2904 // Collect compilation graph edges.
2905 const RecordVector& CompilationGraphs =
2906 Records.getAllDerivedDefinitions("CompilationGraph");
2907 FillInEdgeVector(CompilationGraphs.begin(), CompilationGraphs.end(),
2908 Data.Edges);
2909
2910 // Calculate the priority of this plugin.
2911 const RecordVector& Priorities =
2912 Records.getAllDerivedDefinitions("PluginPriority");
2913 Data.Priority = CalculatePriority(Priorities.begin(), Priorities.end());
Mikhail Glushenkov35fde152008-11-17 17:30:25 +00002914}
2915
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002916/// CheckPluginData - Perform some sanity checks on the collected data.
2917void CheckPluginData(PluginData& Data) {
2918 // Filter out all tools not mentioned in the compilation graph.
2919 FilterNotInGraph(Data.Edges, Data.ToolDescs);
Mikhail Glushenkovad746be2008-11-28 00:13:47 +00002920
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002921 // Typecheck the compilation graph.
2922 TypecheckGraph(Data.Edges, Data.ToolDescs);
2923
2924 // Check that there are no options without side effects (specified
2925 // only in the OptionList).
2926 CheckForSuperfluousOptions(Data.Edges, Data.ToolDescs, Data.OptDescs);
Mikhail Glushenkovad746be2008-11-28 00:13:47 +00002927}
2928
Daniel Dunbar1a551802009-07-03 00:10:29 +00002929void EmitPluginCode(const PluginData& Data, raw_ostream& O) {
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002930 // Emit file header.
2931 EmitIncludes(O);
2932
2933 // Emit global option registration code.
Mikhail Glushenkov7c8deb32009-06-23 20:45:07 +00002934 EmitOptionDefinitions(Data.OptDescs, Data.HasSink, Data.HasExterns, O);
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002935
2936 // Emit hook declarations.
Mikhail Glushenkov8245a1d2009-12-07 17:03:05 +00002937 EmitHookDeclarations(Data.ToolDescs, Data.OptDescs, O);
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002938
Mikhail Glushenkove1d44b52008-12-11 10:34:18 +00002939 O << "namespace {\n\n";
2940
Mikhail Glushenkov0a22fb62009-10-17 20:09:29 +00002941 // Emit PreprocessOptionsLocal() function.
2942 EmitPreprocessOptions(Records, Data.OptDescs, O);
2943
2944 // Emit PopulateLanguageMapLocal() function
2945 // (language map maps from file extensions to language names).
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002946 EmitPopulateLanguageMap(Records, O);
2947
2948 // Emit Tool classes.
2949 for (ToolDescriptions::const_iterator B = Data.ToolDescs.begin(),
2950 E = Data.ToolDescs.end(); B!=E; ++B)
2951 EmitToolClassDefinition(*(*B), Data.OptDescs, O);
2952
2953 // Emit Edge# classes.
2954 EmitEdgeClasses(Data.Edges, Data.OptDescs, O);
2955
Mikhail Glushenkov0a22fb62009-10-17 20:09:29 +00002956 // Emit PopulateCompilationGraphLocal() function.
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002957 EmitPopulateCompilationGraph(Data.Edges, Data.ToolDescs, O);
2958
2959 // Emit code for plugin registration.
2960 EmitRegisterPlugin(Data.Priority, O);
2961
Mikhail Glushenkovd80d8692009-06-23 20:46:48 +00002962 O << "} // End anonymous namespace.\n\n";
2963
2964 // Force linkage magic.
2965 O << "namespace llvmc {\n";
2966 O << "LLVMC_FORCE_LINKAGE_DECL(LLVMC_PLUGIN_NAME) {}\n";
2967 O << "}\n";
2968
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002969 // EOF
2970}
2971
2972
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +00002973// End of anonymous namespace
Mikhail Glushenkov895820d2008-05-06 18:12:03 +00002974}
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +00002975
Mikhail Glushenkov4561ab52008-05-07 21:50:19 +00002976/// run - The back-end entry point.
Daniel Dunbar1a551802009-07-03 00:10:29 +00002977void LLVMCConfigurationEmitter::run (raw_ostream &O) {
Mikhail Glushenkov4fb71ea2008-05-30 06:21:48 +00002978 try {
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002979 PluginData Data;
Mikhail Glushenkov4561ab52008-05-07 21:50:19 +00002980
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002981 CollectPluginData(Records, Data);
2982 CheckPluginData(Data);
2983
Mikhail Glushenkovbe9d9a12008-05-06 18:08:59 +00002984 EmitSourceFileHeader("LLVMC Configuration Library", O);
Mikhail Glushenkovf9152532008-12-07 16:41:11 +00002985 EmitPluginCode(Data, O);
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +00002986
Mikhail Glushenkov4fb71ea2008-05-30 06:21:48 +00002987 } catch (std::exception& Error) {
2988 throw Error.what() + std::string(" - usually this means a syntax error.");
2989 }
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +00002990}