blob: 97ea3d6834661d604355c149e265b6392a2339c3 [file] [log] [blame]
Mikhail Glushenkov2d3327f2008-05-30 06:20:54 +00001//===- LLVMCConfigurationEmitter.cpp - Generate LLVMC config ----*- C++ -*-===//
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00002//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open
6// Source License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
Mikhail Glushenkov34307a92008-05-06 18:08:59 +000010// This tablegen backend is responsible for emitting LLVMC configuration code.
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +000011//
12//===----------------------------------------------------------------------===//
13
Mikhail Glushenkov41405722008-05-06 18:09:29 +000014#include "LLVMCConfigurationEmitter.h"
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +000015#include "Record.h"
16
17#include "llvm/ADT/IntrusiveRefCntPtr.h"
18#include "llvm/ADT/SmallVector.h"
19#include "llvm/ADT/StringExtras.h"
20#include "llvm/ADT/StringMap.h"
Mikhail Glushenkov0e92d2f2008-05-30 06:18:16 +000021#include "llvm/ADT/StringSet.h"
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +000022#include "llvm/Support/Streams.h"
Mikhail Glushenkovb08aafd2008-11-12 00:04:46 +000023
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +000024#include <algorithm>
25#include <cassert>
26#include <functional>
Mikhail Glushenkovffe736e2008-05-30 06:21:48 +000027#include <stdexcept>
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +000028#include <string>
Chris Lattner52aa6862008-06-04 04:46:14 +000029#include <typeinfo>
Mikhail Glushenkovb08aafd2008-11-12 00:04:46 +000030
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +000031using namespace llvm;
32
Mikhail Glushenkovc1f738d2008-05-06 18:12:03 +000033namespace {
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +000034
35//===----------------------------------------------------------------------===//
36/// Typedefs
37
38typedef std::vector<Record*> RecordVector;
39typedef std::vector<std::string> StrVector;
40
41//===----------------------------------------------------------------------===//
42/// Constants
43
Mikhail Glushenkovbe46ae12008-05-07 21:50:19 +000044// Indentation strings.
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +000045const char * Indent1 = " ";
46const char * Indent2 = " ";
47const char * Indent3 = " ";
48const char * Indent4 = " ";
49
Mikhail Glushenkovbe46ae12008-05-07 21:50:19 +000050// Default help string.
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +000051const char * DefaultHelpString = "NO HELP MESSAGE PROVIDED";
52
Mikhail Glushenkovbe46ae12008-05-07 21:50:19 +000053// Name for the "sink" option.
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +000054const char * SinkOptionName = "AutoGeneratedSinkOption";
55
56//===----------------------------------------------------------------------===//
57/// Helper functions
58
Mikhail Glushenkov35576b02008-05-30 06:10:19 +000059int InitPtrToInt(const Init* ptr) {
60 const IntInit& val = dynamic_cast<const IntInit&>(*ptr);
Mikhail Glushenkovdfcad6c2008-05-06 18:18:20 +000061 return val.getValue();
62}
63
Mikhail Glushenkov0e92d2f2008-05-30 06:18:16 +000064const std::string& InitPtrToString(const Init* ptr) {
65 const StringInit& val = dynamic_cast<const StringInit&>(*ptr);
66 return val.getValue();
67}
68
69const ListInit& InitPtrToList(const Init* ptr) {
70 const ListInit& val = dynamic_cast<const ListInit&>(*ptr);
71 return val;
72}
73
74const DagInit& InitPtrToDag(const Init* ptr) {
Mikhail Glushenkov35576b02008-05-30 06:10:19 +000075 const DagInit& val = dynamic_cast<const DagInit&>(*ptr);
Mikhail Glushenkovdfcad6c2008-05-06 18:18:20 +000076 return val;
77}
78
Mikhail Glushenkovbe46ae12008-05-07 21:50:19 +000079// checkNumberOfArguments - Ensure that the number of args in d is
Mikhail Glushenkovdedba642008-05-30 06:08:50 +000080// less than or equal to min_arguments, otherwise throw an exception.
Mikhail Glushenkova5922cc2008-05-06 17:22:03 +000081void checkNumberOfArguments (const DagInit* d, unsigned min_arguments) {
82 if (d->getNumArgs() < min_arguments)
83 throw "Property " + d->getOperator()->getAsString()
84 + " has too few arguments!";
85}
86
Mikhail Glushenkovdedba642008-05-30 06:08:50 +000087// isDagEmpty - is this DAG marked with an empty marker?
88bool isDagEmpty (const DagInit* d) {
89 return d->getOperator()->getAsString() == "empty";
90}
Mikhail Glushenkova5922cc2008-05-06 17:22:03 +000091
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +000092//===----------------------------------------------------------------------===//
93/// Back-end specific code
94
95// A command-line option can have one of the following types:
96//
Mikhail Glushenkovb623c322008-05-30 06:22:52 +000097// Alias - an alias for another option.
98//
99// Switch - a simple switch without arguments, e.g. -O2
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000100//
101// Parameter - an option that takes one(and only one) argument, e.g. -o file,
102// --output=file
103//
104// ParameterList - same as Parameter, but more than one occurence
105// of the option is allowed, e.g. -lm -lpthread
106//
107// Prefix - argument is everything after the prefix,
108// e.g. -Wa,-foo,-bar, -DNAME=VALUE
109//
110// PrefixList - same as Prefix, but more than one option occurence is
Mikhail Glushenkovb623c322008-05-30 06:22:52 +0000111// allowed.
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000112
113namespace OptionType {
Mikhail Glushenkovb623c322008-05-30 06:22:52 +0000114 enum OptionType { Alias, Switch,
115 Parameter, ParameterList, Prefix, PrefixList};
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000116}
117
118bool IsListOptionType (OptionType::OptionType t) {
119 return (t == OptionType::ParameterList || t == OptionType::PrefixList);
120}
121
122// Code duplication here is necessary because one option can affect
123// several tools and those tools may have different actions associated
124// with this option. GlobalOptionDescriptions are used to generate
125// the option registration code, while ToolOptionDescriptions are used
126// to generate tool-specific code.
127
Mikhail Glushenkovbe46ae12008-05-07 21:50:19 +0000128/// OptionDescription - Base class for option descriptions.
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000129struct OptionDescription {
130 OptionType::OptionType Type;
131 std::string Name;
132
133 OptionDescription(OptionType::OptionType t = OptionType::Switch,
134 const std::string& n = "")
135 : Type(t), Name(n)
136 {}
137
138 const char* GenTypeDeclaration() const {
139 switch (Type) {
Mikhail Glushenkovb623c322008-05-30 06:22:52 +0000140 case OptionType::Alias:
141 return "cl::alias";
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000142 case OptionType::PrefixList:
143 case OptionType::ParameterList:
144 return "cl::list<std::string>";
145 case OptionType::Switch:
146 return "cl::opt<bool>";
147 case OptionType::Parameter:
148 case OptionType::Prefix:
149 default:
150 return "cl::opt<std::string>";
151 }
152 }
153
Mikhail Glushenkov4019e952008-05-12 16:33:06 +0000154 // Escape commas and other symbols not allowed in the C++ variable
155 // names. Makes it possible to use options with names like "Wa,"
156 // (useful for prefix options).
157 std::string EscapeVariableName(const std::string& Var) const {
158 std::string ret;
159 for (unsigned i = 0; i != Var.size(); ++i) {
Mikhail Glushenkov50084e82008-09-22 20:46:19 +0000160 char cur_char = Var[i];
161 if (cur_char == ',') {
162 ret += "_comma_";
163 }
164 else if (cur_char == '+') {
165 ret += "_plus_";
166 }
Anton Korobeynikov992846d2008-11-08 10:16:21 +0000167 else if (cur_char == '-') {
168 ret += "_dash_";
Mikhail Glushenkov4019e952008-05-12 16:33:06 +0000169 }
170 else {
Mikhail Glushenkov50084e82008-09-22 20:46:19 +0000171 ret.push_back(cur_char);
Mikhail Glushenkov4019e952008-05-12 16:33:06 +0000172 }
173 }
174 return ret;
175 }
176
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000177 std::string GenVariableName() const {
Mikhail Glushenkov4019e952008-05-12 16:33:06 +0000178 const std::string& EscapedName = EscapeVariableName(Name);
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000179 switch (Type) {
Mikhail Glushenkovb623c322008-05-30 06:22:52 +0000180 case OptionType::Alias:
181 return "AutoGeneratedAlias" + EscapedName;
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000182 case OptionType::Switch:
Mikhail Glushenkovb623c322008-05-30 06:22:52 +0000183 return "AutoGeneratedSwitch" + EscapedName;
184 case OptionType::Prefix:
185 return "AutoGeneratedPrefix" + EscapedName;
186 case OptionType::PrefixList:
187 return "AutoGeneratedPrefixList" + EscapedName;
188 case OptionType::Parameter:
189 return "AutoGeneratedParameter" + EscapedName;
190 case OptionType::ParameterList:
191 default:
192 return "AutoGeneratedParameterList" + EscapedName;
193 }
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000194 }
195
196};
197
Mikhail Glushenkovbe46ae12008-05-07 21:50:19 +0000198// Global option description.
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000199
200namespace GlobalOptionDescriptionFlags {
Mikhail Glushenkovc9b650d2008-11-28 00:13:25 +0000201 enum GlobalOptionDescriptionFlags { Required = 0x1, Hidden = 0x2,
202 ReallyHidden = 0x4 };
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000203}
204
205struct GlobalOptionDescription : public OptionDescription {
206 std::string Help;
207 unsigned Flags;
208
Mikhail Glushenkov7adcf1e2008-05-09 08:27:26 +0000209 // We need to provide a default constructor because
210 // StringMap can only store DefaultConstructible objects.
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000211 GlobalOptionDescription() : OptionDescription(), Flags(0)
212 {}
213
Mikhail Glushenkovb623c322008-05-30 06:22:52 +0000214 GlobalOptionDescription (OptionType::OptionType t, const std::string& n,
215 const std::string& h = DefaultHelpString)
216 : OptionDescription(t, n), Help(h), Flags(0)
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000217 {}
218
219 bool isRequired() const {
220 return Flags & GlobalOptionDescriptionFlags::Required;
221 }
222 void setRequired() {
223 Flags |= GlobalOptionDescriptionFlags::Required;
224 }
225
Mikhail Glushenkovc9b650d2008-11-28 00:13:25 +0000226 bool isHidden() const {
227 return Flags & GlobalOptionDescriptionFlags::Hidden;
228 }
229 void setHidden() {
230 Flags |= GlobalOptionDescriptionFlags::Hidden;
231 }
232
233 bool isReallyHidden() const {
234 return Flags & GlobalOptionDescriptionFlags::ReallyHidden;
235 }
236 void setReallyHidden() {
237 Flags |= GlobalOptionDescriptionFlags::ReallyHidden;
238 }
239
Mikhail Glushenkovbe46ae12008-05-07 21:50:19 +0000240 /// Merge - Merge two option descriptions.
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000241 void Merge (const GlobalOptionDescription& other)
242 {
243 if (other.Type != Type)
244 throw "Conflicting definitions for the option " + Name + "!";
245
Mikhail Glushenkov5ca18a12008-11-26 10:55:45 +0000246 if (Help == other.Help || Help == DefaultHelpString)
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000247 Help = other.Help;
Mikhail Glushenkov434816d2008-05-06 18:13:00 +0000248 else if (other.Help != DefaultHelpString) {
Mikhail Glushenkov5ca18a12008-11-26 10:55:45 +0000249 llvm::cerr << "Warning: several different help strings"
250 " defined for option " + Name + "\n";
Mikhail Glushenkov434816d2008-05-06 18:13:00 +0000251 }
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000252
253 Flags |= other.Flags;
254 }
255};
256
Mikhail Glushenkovbe46ae12008-05-07 21:50:19 +0000257/// GlobalOptionDescriptions - A GlobalOptionDescription array
258/// together with some flags affecting generation of option
259/// declarations.
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000260struct GlobalOptionDescriptions {
261 typedef StringMap<GlobalOptionDescription> container_type;
262 typedef container_type::const_iterator const_iterator;
263
Mikhail Glushenkovbe46ae12008-05-07 21:50:19 +0000264 /// Descriptions - A list of GlobalOptionDescriptions.
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000265 container_type Descriptions;
Mikhail Glushenkovbe46ae12008-05-07 21:50:19 +0000266 /// HasSink - Should the emitter generate a "cl::sink" option?
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000267 bool HasSink;
268
Mikhail Glushenkove5fcb552008-05-30 06:28:37 +0000269 /// FindOption - exception-throwing wrapper for find().
Mikhail Glushenkova5922cc2008-05-06 17:22:03 +0000270 const GlobalOptionDescription& FindOption(const std::string& OptName) const {
271 const_iterator I = Descriptions.find(OptName);
272 if (I != Descriptions.end())
273 return I->second;
274 else
275 throw OptName + ": no such option!";
276 }
277
Mikhail Glushenkove5fcb552008-05-30 06:28:37 +0000278 /// insertDescription - Insert new GlobalOptionDescription into
279 /// GlobalOptionDescriptions list
Mikhail Glushenkovbf774352008-05-30 06:27:02 +0000280 void insertDescription (const GlobalOptionDescription& o)
281 {
282 container_type::iterator I = Descriptions.find(o.Name);
283 if (I != Descriptions.end()) {
284 GlobalOptionDescription& D = I->second;
285 D.Merge(o);
286 }
287 else {
288 Descriptions[o.Name] = o;
289 }
290 }
291
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000292 // Support for STL-style iteration
293 const_iterator begin() const { return Descriptions.begin(); }
294 const_iterator end() const { return Descriptions.end(); }
295};
296
297
Mikhail Glushenkov7adcf1e2008-05-09 08:27:26 +0000298// Tool-local option description.
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000299
Mikhail Glushenkov7adcf1e2008-05-09 08:27:26 +0000300// Properties without arguments are implemented as flags.
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000301namespace ToolOptionDescriptionFlags {
302 enum ToolOptionDescriptionFlags { StopCompilation = 0x1,
303 Forward = 0x2, UnpackValues = 0x4};
304}
305namespace OptionPropertyType {
Mikhail Glushenkov50084e82008-09-22 20:46:19 +0000306 enum OptionPropertyType { AppendCmd, ForwardAs, OutputSuffix };
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000307}
308
309typedef std::pair<OptionPropertyType::OptionPropertyType, std::string>
310OptionProperty;
311typedef SmallVector<OptionProperty, 4> OptionPropertyList;
312
313struct ToolOptionDescription : public OptionDescription {
314 unsigned Flags;
315 OptionPropertyList Props;
316
317 // StringMap can only store DefaultConstructible objects
Mikhail Glushenkov18cbe892008-03-27 09:53:47 +0000318 ToolOptionDescription() : OptionDescription(), Flags(0) {}
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000319
320 ToolOptionDescription (OptionType::OptionType t, const std::string& n)
321 : OptionDescription(t, n)
322 {}
323
324 // Various boolean properties
325 bool isStopCompilation() const {
326 return Flags & ToolOptionDescriptionFlags::StopCompilation;
327 }
328 void setStopCompilation() {
329 Flags |= ToolOptionDescriptionFlags::StopCompilation;
330 }
331
332 bool isForward() const {
333 return Flags & ToolOptionDescriptionFlags::Forward;
334 }
335 void setForward() {
336 Flags |= ToolOptionDescriptionFlags::Forward;
337 }
338
339 bool isUnpackValues() const {
340 return Flags & ToolOptionDescriptionFlags::UnpackValues;
341 }
342 void setUnpackValues() {
343 Flags |= ToolOptionDescriptionFlags::UnpackValues;
344 }
345
346 void AddProperty (OptionPropertyType::OptionPropertyType t,
347 const std::string& val)
348 {
349 Props.push_back(std::make_pair(t, val));
350 }
351};
352
353typedef StringMap<ToolOptionDescription> ToolOptionDescriptions;
354
355// Tool information record
356
357namespace ToolFlags {
358 enum ToolFlags { Join = 0x1, Sink = 0x2 };
359}
360
361struct ToolProperties : public RefCountedBase<ToolProperties> {
362 std::string Name;
Mikhail Glushenkov35576b02008-05-30 06:10:19 +0000363 Init* CmdLine;
Mikhail Glushenkov0e92d2f2008-05-30 06:18:16 +0000364 StrVector InLanguage;
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000365 std::string OutLanguage;
366 std::string OutputSuffix;
367 unsigned Flags;
368 ToolOptionDescriptions OptDescs;
369
370 // Various boolean properties
371 void setSink() { Flags |= ToolFlags::Sink; }
372 bool isSink() const { return Flags & ToolFlags::Sink; }
373 void setJoin() { Flags |= ToolFlags::Join; }
374 bool isJoin() const { return Flags & ToolFlags::Join; }
375
376 // Default ctor here is needed because StringMap can only store
377 // DefaultConstructible objects
Anton Korobeynikov246fced2008-06-01 16:22:49 +0000378 ToolProperties() : CmdLine(0), Flags(0) {}
379 ToolProperties (const std::string& n) : Name(n), CmdLine(0), Flags(0) {}
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000380};
381
382
Mikhail Glushenkovbe46ae12008-05-07 21:50:19 +0000383/// ToolPropertiesList - A list of Tool information records
384/// IntrusiveRefCntPtrs are used here because StringMap has no copy
385/// constructor (and we want to avoid copying ToolProperties anyway).
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000386typedef std::vector<IntrusiveRefCntPtr<ToolProperties> > ToolPropertiesList;
387
388
Mikhail Glushenkovbf774352008-05-30 06:27:02 +0000389/// CollectOptionProperties - Function object for iterating over a
390/// list (usually, a DAG) of option property records.
391class CollectOptionProperties {
392private:
393 // Implementation details.
394
395 /// OptionPropertyHandler - a function that extracts information
396 /// about a given option property from its DAG representation.
397 typedef void (CollectOptionProperties::* OptionPropertyHandler)
398 (const DagInit*);
399
400 /// OptionPropertyHandlerMap - A map from option property names to
401 /// option property handlers
402 typedef StringMap<OptionPropertyHandler> OptionPropertyHandlerMap;
403
404 static OptionPropertyHandlerMap optionPropertyHandlers_;
405 static bool staticMembersInitialized_;
406
407 /// This is where the information is stored
408
409 /// toolProps_ - Properties of the current Tool.
410 ToolProperties* toolProps_;
411 /// optDescs_ - OptionDescriptions table (used to register options
412 /// globally).
413 GlobalOptionDescription& optDesc_;
414
415public:
416
417 explicit CollectOptionProperties(ToolProperties* TP,
418 GlobalOptionDescription& OD)
419 : toolProps_(TP), optDesc_(OD)
420 {
421 if (!staticMembersInitialized_) {
422 optionPropertyHandlers_["append_cmd"] =
423 &CollectOptionProperties::onAppendCmd;
424 optionPropertyHandlers_["forward"] =
425 &CollectOptionProperties::onForward;
Mikhail Glushenkov50084e82008-09-22 20:46:19 +0000426 optionPropertyHandlers_["forward_as"] =
427 &CollectOptionProperties::onForwardAs;
Mikhail Glushenkovbf774352008-05-30 06:27:02 +0000428 optionPropertyHandlers_["help"] =
429 &CollectOptionProperties::onHelp;
Mikhail Glushenkovc9b650d2008-11-28 00:13:25 +0000430 optionPropertyHandlers_["hidden"] =
431 &CollectOptionProperties::onHidden;
Mikhail Glushenkovbf774352008-05-30 06:27:02 +0000432 optionPropertyHandlers_["output_suffix"] =
433 &CollectOptionProperties::onOutputSuffix;
Mikhail Glushenkovc9b650d2008-11-28 00:13:25 +0000434 optionPropertyHandlers_["really_hidden"] =
435 &CollectOptionProperties::onReallyHidden;
Mikhail Glushenkovbf774352008-05-30 06:27:02 +0000436 optionPropertyHandlers_["required"] =
437 &CollectOptionProperties::onRequired;
438 optionPropertyHandlers_["stop_compilation"] =
439 &CollectOptionProperties::onStopCompilation;
440 optionPropertyHandlers_["unpack_values"] =
441 &CollectOptionProperties::onUnpackValues;
442
443 staticMembersInitialized_ = true;
444 }
445 }
446
447 /// operator() - Gets called for every option property; Just forwards
448 /// to the corresponding property handler.
449 void operator() (Init* i) {
450 const DagInit& option_property = InitPtrToDag(i);
451 const std::string& option_property_name
452 = option_property.getOperator()->getAsString();
453 OptionPropertyHandlerMap::iterator method
454 = optionPropertyHandlers_.find(option_property_name);
455
456 if (method != optionPropertyHandlers_.end()) {
457 OptionPropertyHandler h = method->second;
458 (this->*h)(&option_property);
459 }
460 else {
461 throw "Unknown option property: " + option_property_name + "!";
462 }
463 }
464
465private:
466
467 /// Option property handlers --
468 /// Methods that handle properties that are common for all types of
469 /// options (like append_cmd, stop_compilation)
470
471 void onAppendCmd (const DagInit* d) {
472 checkNumberOfArguments(d, 1);
473 checkToolProps(d);
474 const std::string& cmd = InitPtrToString(d->getArg(0));
475
476 toolProps_->OptDescs[optDesc_.Name].
477 AddProperty(OptionPropertyType::AppendCmd, cmd);
478 }
479
480 void onOutputSuffix (const DagInit* d) {
481 checkNumberOfArguments(d, 1);
482 checkToolProps(d);
483 const std::string& suf = InitPtrToString(d->getArg(0));
484
485 if (toolProps_->OptDescs[optDesc_.Name].Type != OptionType::Switch)
486 throw "Option " + optDesc_.Name
487 + " can't have 'output_suffix' property since it isn't a switch!";
488
489 toolProps_->OptDescs[optDesc_.Name].AddProperty
490 (OptionPropertyType::OutputSuffix, suf);
491 }
492
493 void onForward (const DagInit* d) {
494 checkNumberOfArguments(d, 0);
495 checkToolProps(d);
496 toolProps_->OptDescs[optDesc_.Name].setForward();
497 }
498
Mikhail Glushenkov50084e82008-09-22 20:46:19 +0000499 void onForwardAs (const DagInit* d) {
500 checkNumberOfArguments(d, 1);
501 checkToolProps(d);
502 const std::string& cmd = InitPtrToString(d->getArg(0));
503
504 toolProps_->OptDescs[optDesc_.Name].
505 AddProperty(OptionPropertyType::ForwardAs, cmd);
506 }
507
Mikhail Glushenkovbf774352008-05-30 06:27:02 +0000508 void onHelp (const DagInit* d) {
509 checkNumberOfArguments(d, 1);
510 const std::string& help_message = InitPtrToString(d->getArg(0));
511
512 optDesc_.Help = help_message;
513 }
514
Mikhail Glushenkovc9b650d2008-11-28 00:13:25 +0000515 void onHidden (const DagInit* d) {
516 checkNumberOfArguments(d, 0);
517 checkToolProps(d);
518 optDesc_.setHidden();
519 }
520
521 void onReallyHidden (const DagInit* d) {
522 checkNumberOfArguments(d, 0);
523 checkToolProps(d);
524 optDesc_.setReallyHidden();
525 }
526
Mikhail Glushenkovbf774352008-05-30 06:27:02 +0000527 void onRequired (const DagInit* d) {
528 checkNumberOfArguments(d, 0);
529 checkToolProps(d);
530 optDesc_.setRequired();
531 }
532
533 void onStopCompilation (const DagInit* d) {
534 checkNumberOfArguments(d, 0);
535 checkToolProps(d);
536 if (optDesc_.Type != OptionType::Switch)
537 throw std::string("Only options of type Switch can stop compilation!");
538 toolProps_->OptDescs[optDesc_.Name].setStopCompilation();
539 }
540
541 void onUnpackValues (const DagInit* d) {
542 checkNumberOfArguments(d, 0);
543 checkToolProps(d);
544 toolProps_->OptDescs[optDesc_.Name].setUnpackValues();
545 }
546
547 // Helper functions
548
549 /// checkToolProps - Throw an error if toolProps_ == 0.
550 void checkToolProps(const DagInit* d) {
551 if (!d)
552 throw "Option property " + d->getOperator()->getAsString()
553 + " can't be used in this context";
554 }
555
556};
557
558CollectOptionProperties::OptionPropertyHandlerMap
559CollectOptionProperties::optionPropertyHandlers_;
560
561bool CollectOptionProperties::staticMembersInitialized_ = false;
562
563
564/// processOptionProperties - Go through the list of option
565/// properties and call a corresponding handler for each.
566void processOptionProperties (const DagInit* d, ToolProperties* t,
567 GlobalOptionDescription& o) {
568 checkNumberOfArguments(d, 2);
569 DagInit::const_arg_iterator B = d->arg_begin();
570 // Skip the first argument: it's always the option name.
571 ++B;
572 std::for_each(B, d->arg_end(), CollectOptionProperties(t, o));
573}
574
Mikhail Glushenkove62df252008-05-30 06:27:29 +0000575/// AddOption - A function object wrapper for
576/// processOptionProperties. Used by CollectProperties and
577/// CollectPropertiesFromOptionList.
578class AddOption {
579private:
580 GlobalOptionDescriptions& OptDescs_;
581 ToolProperties* ToolProps_;
582
583public:
584 explicit AddOption(GlobalOptionDescriptions& OD, ToolProperties* TP = 0)
585 : OptDescs_(OD), ToolProps_(TP)
586 {}
587
588 void operator()(const Init* i) {
589 const DagInit& d = InitPtrToDag(i);
590 checkNumberOfArguments(&d, 2);
591
592 const OptionType::OptionType Type =
593 getOptionType(d.getOperator()->getAsString());
594 const std::string& Name = InitPtrToString(d.getArg(0));
595
596 GlobalOptionDescription OD(Type, Name);
597 if (Type != OptionType::Alias) {
598 processOptionProperties(&d, ToolProps_, OD);
599 if (ToolProps_) {
600 ToolProps_->OptDescs[Name].Type = Type;
601 ToolProps_->OptDescs[Name].Name = Name;
602 }
603 }
604 else {
605 OD.Help = InitPtrToString(d.getArg(1));
606 }
607 OptDescs_.insertDescription(OD);
608 }
609
610private:
611 OptionType::OptionType getOptionType(const std::string& T) const {
612 if (T == "alias_option")
613 return OptionType::Alias;
614 else if (T == "switch_option")
615 return OptionType::Switch;
616 else if (T == "parameter_option")
617 return OptionType::Parameter;
618 else if (T == "parameter_list_option")
619 return OptionType::ParameterList;
620 else if (T == "prefix_option")
621 return OptionType::Prefix;
622 else if (T == "prefix_list_option")
623 return OptionType::PrefixList;
624 else
625 throw "Unknown option type: " + T + '!';
626 }
627};
628
629
Mikhail Glushenkovbe46ae12008-05-07 21:50:19 +0000630/// CollectProperties - Function object for iterating over a list of
Mikhail Glushenkov7adcf1e2008-05-09 08:27:26 +0000631/// tool property records.
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000632class CollectProperties {
633private:
634
Mikhail Glushenkovbf774352008-05-30 06:27:02 +0000635 // Implementation details
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000636
Mikhail Glushenkovbe46ae12008-05-07 21:50:19 +0000637 /// PropertyHandler - a function that extracts information
638 /// about a given tool property from its DAG representation
Mikhail Glushenkovdfcad6c2008-05-06 18:18:20 +0000639 typedef void (CollectProperties::*PropertyHandler)(const DagInit*);
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000640
Mikhail Glushenkovbe46ae12008-05-07 21:50:19 +0000641 /// PropertyHandlerMap - A map from property names to property
642 /// handlers.
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000643 typedef StringMap<PropertyHandler> PropertyHandlerMap;
644
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000645 // Static maps from strings to CollectProperties methods("handlers")
646 static PropertyHandlerMap propertyHandlers_;
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000647 static bool staticMembersInitialized_;
648
649
650 /// This is where the information is stored
651
Mikhail Glushenkovbe46ae12008-05-07 21:50:19 +0000652 /// toolProps_ - Properties of the current Tool.
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000653 ToolProperties& toolProps_;
Mikhail Glushenkovbe46ae12008-05-07 21:50:19 +0000654 /// optDescs_ - OptionDescriptions table (used to register options
655 /// globally).
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000656 GlobalOptionDescriptions& optDescs_;
657
658public:
659
660 explicit CollectProperties (ToolProperties& p, GlobalOptionDescriptions& d)
661 : toolProps_(p), optDescs_(d)
662 {
663 if (!staticMembersInitialized_) {
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000664 propertyHandlers_["cmd_line"] = &CollectProperties::onCmdLine;
665 propertyHandlers_["in_language"] = &CollectProperties::onInLanguage;
666 propertyHandlers_["join"] = &CollectProperties::onJoin;
667 propertyHandlers_["out_language"] = &CollectProperties::onOutLanguage;
668 propertyHandlers_["output_suffix"] = &CollectProperties::onOutputSuffix;
669 propertyHandlers_["parameter_option"]
Mikhail Glushenkove62df252008-05-30 06:27:29 +0000670 = &CollectProperties::addOption;
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000671 propertyHandlers_["parameter_list_option"] =
Mikhail Glushenkove62df252008-05-30 06:27:29 +0000672 &CollectProperties::addOption;
673 propertyHandlers_["prefix_option"] = &CollectProperties::addOption;
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000674 propertyHandlers_["prefix_list_option"] =
Mikhail Glushenkove62df252008-05-30 06:27:29 +0000675 &CollectProperties::addOption;
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000676 propertyHandlers_["sink"] = &CollectProperties::onSink;
Mikhail Glushenkove62df252008-05-30 06:27:29 +0000677 propertyHandlers_["switch_option"] = &CollectProperties::addOption;
678 propertyHandlers_["alias_option"] = &CollectProperties::addOption;
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000679
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000680 staticMembersInitialized_ = true;
681 }
682 }
683
Mikhail Glushenkovbe46ae12008-05-07 21:50:19 +0000684 /// operator() - Gets called for every tool property; Just forwards
685 /// to the corresponding property handler.
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000686 void operator() (Init* i) {
Mikhail Glushenkov0e92d2f2008-05-30 06:18:16 +0000687 const DagInit& d = InitPtrToDag(i);
Mikhail Glushenkova5922cc2008-05-06 17:22:03 +0000688 const std::string& property_name = d.getOperator()->getAsString();
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000689 PropertyHandlerMap::iterator method
690 = propertyHandlers_.find(property_name);
691
692 if (method != propertyHandlers_.end()) {
693 PropertyHandler h = method->second;
694 (this->*h)(&d);
695 }
696 else {
697 throw "Unknown tool property: " + property_name + "!";
698 }
699 }
700
701private:
702
703 /// Property handlers --
704 /// Functions that extract information about tool properties from
705 /// DAG representation.
706
Mikhail Glushenkovdfcad6c2008-05-06 18:18:20 +0000707 void onCmdLine (const DagInit* d) {
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000708 checkNumberOfArguments(d, 1);
Mikhail Glushenkov35576b02008-05-30 06:10:19 +0000709 toolProps_.CmdLine = d->getArg(0);
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000710 }
711
Mikhail Glushenkovdfcad6c2008-05-06 18:18:20 +0000712 void onInLanguage (const DagInit* d) {
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000713 checkNumberOfArguments(d, 1);
Mikhail Glushenkov0e92d2f2008-05-30 06:18:16 +0000714 Init* arg = d->getArg(0);
715
716 // Find out the argument's type.
717 if (typeid(*arg) == typeid(StringInit)) {
718 // It's a string.
719 toolProps_.InLanguage.push_back(InitPtrToString(arg));
720 }
721 else {
722 // It's a list.
723 const ListInit& lst = InitPtrToList(arg);
724 StrVector& out = toolProps_.InLanguage;
725
726 // Copy strings to the output vector.
727 for (ListInit::const_iterator B = lst.begin(), E = lst.end();
728 B != E; ++B) {
729 out.push_back(InitPtrToString(*B));
730 }
731
732 // Remove duplicates.
733 std::sort(out.begin(), out.end());
734 StrVector::iterator newE = std::unique(out.begin(), out.end());
735 out.erase(newE, out.end());
736 }
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000737 }
738
Mikhail Glushenkovdfcad6c2008-05-06 18:18:20 +0000739 void onJoin (const DagInit* d) {
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000740 checkNumberOfArguments(d, 0);
741 toolProps_.setJoin();
742 }
743
Mikhail Glushenkovdfcad6c2008-05-06 18:18:20 +0000744 void onOutLanguage (const DagInit* d) {
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000745 checkNumberOfArguments(d, 1);
746 toolProps_.OutLanguage = InitPtrToString(d->getArg(0));
747 }
748
Mikhail Glushenkovdfcad6c2008-05-06 18:18:20 +0000749 void onOutputSuffix (const DagInit* d) {
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000750 checkNumberOfArguments(d, 1);
751 toolProps_.OutputSuffix = InitPtrToString(d->getArg(0));
752 }
753
Mikhail Glushenkovdfcad6c2008-05-06 18:18:20 +0000754 void onSink (const DagInit* d) {
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000755 checkNumberOfArguments(d, 0);
756 optDescs_.HasSink = true;
757 toolProps_.setSink();
758 }
759
Mikhail Glushenkove62df252008-05-30 06:27:29 +0000760 // Just forwards to the AddOption function object. Somewhat
761 // non-optimal, but avoids code duplication.
762 void addOption (const DagInit* d) {
Mikhail Glushenkovb623c322008-05-30 06:22:52 +0000763 checkNumberOfArguments(d, 2);
Mikhail Glushenkove62df252008-05-30 06:27:29 +0000764 AddOption(optDescs_, &toolProps_)(d);
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000765 }
766
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000767};
768
Mikhail Glushenkovbf774352008-05-30 06:27:02 +0000769// Defintions of static members of CollectProperties.
770CollectProperties::PropertyHandlerMap CollectProperties::propertyHandlers_;
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000771bool CollectProperties::staticMembersInitialized_ = false;
772
773
Mikhail Glushenkovd638e852008-05-30 06:26:08 +0000774/// CollectToolProperties - Gather information about tool properties
775/// from the parsed TableGen data (basically a wrapper for the
776/// CollectProperties function object).
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000777void CollectToolProperties (RecordVector::const_iterator B,
778 RecordVector::const_iterator E,
779 ToolPropertiesList& TPList,
780 GlobalOptionDescriptions& OptDescs)
781{
782 // Iterate over a properties list of every Tool definition
783 for (;B!=E;++B) {
Mikhail Glushenkov973b3a32008-11-17 17:29:42 +0000784 const Record* T = *B;
Mikhail Glushenkovd638e852008-05-30 06:26:08 +0000785 // Throws an exception if the value does not exist.
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000786 ListInit* PropList = T->getValueAsListInit("properties");
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +0000787
788 IntrusiveRefCntPtr<ToolProperties>
789 ToolProps(new ToolProperties(T->getName()));
790
791 std::for_each(PropList->begin(), PropList->end(),
792 CollectProperties(*ToolProps, OptDescs));
793 TPList.push_back(ToolProps);
794 }
795}
796
Mikhail Glushenkovbf774352008-05-30 06:27:02 +0000797
Mikhail Glushenkovfa990682008-11-17 17:29:18 +0000798/// CollectPropertiesFromOptionLists - Gather information about
799/// *global* option properties from all OptionLists.
800void CollectPropertiesFromOptionLists (RecordVector::const_iterator B,
801 RecordVector::const_iterator E,
802 GlobalOptionDescriptions& OptDescs)
Mikhail Glushenkovd638e852008-05-30 06:26:08 +0000803{
804 // Iterate over a properties list of every Tool definition
Mikhail Glushenkoveb71ecf2008-11-17 17:30:25 +0000805 for (; B!=E; ++B) {
Mikhail Glushenkovd638e852008-05-30 06:26:08 +0000806 RecordVector::value_type T = *B;
807 // Throws an exception if the value does not exist.
808 ListInit* PropList = T->getValueAsListInit("options");
809
Mikhail Glushenkovbf774352008-05-30 06:27:02 +0000810 std::for_each(PropList->begin(), PropList->end(), AddOption(OptDescs));
Mikhail Glushenkovd638e852008-05-30 06:26:08 +0000811 }
812}
813
Mikhail Glushenkove5fcb552008-05-30 06:28:37 +0000814/// CheckForSuperfluousOptions - Check that there are no side
815/// effect-free options (specified only in the OptionList). Otherwise,
816/// output a warning.
817void CheckForSuperfluousOptions (const ToolPropertiesList& TPList,
818 const GlobalOptionDescriptions& OptDescs) {
819 llvm::StringSet<> nonSuperfluousOptions;
820
821 // Add all options mentioned in the TPList to the set of
822 // non-superfluous options.
823 for (ToolPropertiesList::const_iterator B = TPList.begin(),
824 E = TPList.end(); B != E; ++B) {
825 const ToolProperties& TP = *(*B);
826 for (ToolOptionDescriptions::const_iterator B = TP.OptDescs.begin(),
827 E = TP.OptDescs.end(); B != E; ++B) {
828 nonSuperfluousOptions.insert(B->first());
829 }
830 }
831
832 // Check that all options in OptDescs belong to the set of
833 // non-superfluous options.
834 for (GlobalOptionDescriptions::const_iterator B = OptDescs.begin(),
835 E = OptDescs.end(); B != E; ++B) {
836 const GlobalOptionDescription& Val = B->second;
837 if (!nonSuperfluousOptions.count(Val.Name)
838 && Val.Type != OptionType::Alias)
Mikhail Glushenkovfa990682008-11-17 17:29:18 +0000839 llvm::cerr << "Warning: option '-" << Val.Name << "' has no effect! "
Mikhail Glushenkove5fcb552008-05-30 06:28:37 +0000840 "Probable cause: this option is specified only in the OptionList.\n";
841 }
842}
843
Mikhail Glushenkov35576b02008-05-30 06:10:19 +0000844/// EmitCaseTest1Arg - Helper function used by
845/// EmitCaseConstructHandler.
846bool EmitCaseTest1Arg(const std::string& TestName,
847 const DagInit& d,
848 const GlobalOptionDescriptions& OptDescs,
849 std::ostream& O) {
850 checkNumberOfArguments(&d, 1);
851 const std::string& OptName = InitPtrToString(d.getArg(0));
852 if (TestName == "switch_on") {
853 const GlobalOptionDescription& OptDesc = OptDescs.FindOption(OptName);
854 if (OptDesc.Type != OptionType::Switch)
855 throw OptName + ": incorrect option type!";
856 O << OptDesc.GenVariableName();
857 return true;
858 } else if (TestName == "input_languages_contain") {
859 O << "InLangs.count(\"" << OptName << "\") != 0";
860 return true;
Mikhail Glushenkov242d0e62008-05-30 06:19:52 +0000861 } else if (TestName == "in_language") {
Mikhail Glushenkov56a625a2008-09-22 20:48:22 +0000862 // This works only for single-argument Tool::GenerateAction. Join
863 // tools can process several files in different languages simultaneously.
864
865 // TODO: make this work with Edge::Weight (if possible).
Mikhail Glushenkovcdbfa1a2008-09-22 20:47:46 +0000866 O << "LangMap.GetLanguage(inFile) == \"" << OptName << '\"';
Mikhail Glushenkov242d0e62008-05-30 06:19:52 +0000867 return true;
868 } else if (TestName == "not_empty") {
Mikhail Glushenkovb4833872008-05-30 06:24:07 +0000869 if (OptName == "o") {
870 O << "!OutputFilename.empty()";
871 return true;
872 }
873 else {
874 const GlobalOptionDescription& OptDesc = OptDescs.FindOption(OptName);
875 if (OptDesc.Type == OptionType::Switch)
876 throw OptName + ": incorrect option type!";
877 O << '!' << OptDesc.GenVariableName() << ".empty()";
878 return true;
879 }
Mikhail Glushenkov35576b02008-05-30 06:10:19 +0000880 }
881
882 return false;
883}
884
885/// EmitCaseTest2Args - Helper function used by
886/// EmitCaseConstructHandler.
887bool EmitCaseTest2Args(const std::string& TestName,
888 const DagInit& d,
889 const char* IndentLevel,
890 const GlobalOptionDescriptions& OptDescs,
891 std::ostream& O) {
892 checkNumberOfArguments(&d, 2);
893 const std::string& OptName = InitPtrToString(d.getArg(0));
894 const std::string& OptArg = InitPtrToString(d.getArg(1));
895 const GlobalOptionDescription& OptDesc = OptDescs.FindOption(OptName);
896
897 if (TestName == "parameter_equals") {
898 if (OptDesc.Type != OptionType::Parameter
899 && OptDesc.Type != OptionType::Prefix)
900 throw OptName + ": incorrect option type!";
901 O << OptDesc.GenVariableName() << " == \"" << OptArg << "\"";
902 return true;
903 }
904 else if (TestName == "element_in_list") {
905 if (OptDesc.Type != OptionType::ParameterList
906 && OptDesc.Type != OptionType::PrefixList)
907 throw OptName + ": incorrect option type!";
908 const std::string& VarName = OptDesc.GenVariableName();
909 O << "std::find(" << VarName << ".begin(),\n"
910 << IndentLevel << Indent1 << VarName << ".end(), \""
911 << OptArg << "\") != " << VarName << ".end()";
912 return true;
913 }
914
915 return false;
916}
917
918// Forward declaration.
919// EmitLogicalOperationTest and EmitCaseTest are mutually recursive.
920void EmitCaseTest(const DagInit& d, const char* IndentLevel,
921 const GlobalOptionDescriptions& OptDescs,
922 std::ostream& O);
923
924/// EmitLogicalOperationTest - Helper function used by
925/// EmitCaseConstructHandler.
926void EmitLogicalOperationTest(const DagInit& d, const char* LogicOp,
927 const char* IndentLevel,
928 const GlobalOptionDescriptions& OptDescs,
929 std::ostream& O) {
930 O << '(';
931 for (unsigned j = 0, NumArgs = d.getNumArgs(); j < NumArgs; ++j) {
Mikhail Glushenkov0e92d2f2008-05-30 06:18:16 +0000932 const DagInit& InnerTest = InitPtrToDag(d.getArg(j));
Mikhail Glushenkov35576b02008-05-30 06:10:19 +0000933 EmitCaseTest(InnerTest, IndentLevel, OptDescs, O);
934 if (j != NumArgs - 1)
935 O << ")\n" << IndentLevel << Indent1 << ' ' << LogicOp << " (";
936 else
937 O << ')';
938 }
939}
940
941/// EmitCaseTest - Helper function used by EmitCaseConstructHandler.
942void EmitCaseTest(const DagInit& d, const char* IndentLevel,
943 const GlobalOptionDescriptions& OptDescs,
944 std::ostream& O) {
945 const std::string& TestName = d.getOperator()->getAsString();
946
947 if (TestName == "and")
948 EmitLogicalOperationTest(d, "&&", IndentLevel, OptDescs, O);
949 else if (TestName == "or")
950 EmitLogicalOperationTest(d, "||", IndentLevel, OptDescs, O);
951 else if (EmitCaseTest1Arg(TestName, d, OptDescs, O))
952 return;
953 else if (EmitCaseTest2Args(TestName, d, IndentLevel, OptDescs, O))
954 return;
955 else
956 throw TestName + ": unknown edge property!";
957}
958
959// Emit code that handles the 'case' construct.
960// Takes a function object that should emit code for every case clause.
961// Callback's type is
962// void F(Init* Statement, const char* IndentLevel, std::ostream& O).
963template <typename F>
964void EmitCaseConstructHandler(const DagInit* d, const char* IndentLevel,
Mikhail Glushenkov1d95e9f2008-05-31 13:43:21 +0000965 F Callback, bool EmitElseIf,
Mikhail Glushenkov35576b02008-05-30 06:10:19 +0000966 const GlobalOptionDescriptions& OptDescs,
967 std::ostream& O) {
968 assert(d->getOperator()->getAsString() == "case");
969
Mikhail Glushenkov31681512008-05-30 06:15:47 +0000970 unsigned numArgs = d->getNumArgs();
971 if (d->getNumArgs() < 2)
972 throw "There should be at least one clause in the 'case' expression:\n"
973 + d->getAsString();
974
975 for (unsigned i = 0; i != numArgs; ++i) {
Mikhail Glushenkov0e92d2f2008-05-30 06:18:16 +0000976 const DagInit& Test = InitPtrToDag(d->getArg(i));
Mikhail Glushenkov35576b02008-05-30 06:10:19 +0000977
Mikhail Glushenkov31681512008-05-30 06:15:47 +0000978 // Emit the test.
Mikhail Glushenkov35576b02008-05-30 06:10:19 +0000979 if (Test.getOperator()->getAsString() == "default") {
980 if (i+2 != numArgs)
981 throw std::string("The 'default' clause should be the last in the"
982 "'case' construct!");
983 O << IndentLevel << "else {\n";
984 }
985 else {
Mikhail Glushenkovb24c8b22008-05-30 06:22:15 +0000986 O << IndentLevel << ((i != 0 && EmitElseIf) ? "else if (" : "if (");
Mikhail Glushenkov35576b02008-05-30 06:10:19 +0000987 EmitCaseTest(Test, IndentLevel, OptDescs, O);
988 O << ") {\n";
989 }
990
Mikhail Glushenkov31681512008-05-30 06:15:47 +0000991 // Emit the corresponding statement.
Mikhail Glushenkov35576b02008-05-30 06:10:19 +0000992 ++i;
993 if (i == numArgs)
994 throw "Case construct handler: no corresponding action "
995 "found for the test " + Test.getAsString() + '!';
996
Mikhail Glushenkovb24c8b22008-05-30 06:22:15 +0000997 Init* arg = d->getArg(i);
998 if (dynamic_cast<DagInit*>(arg)
999 && static_cast<DagInit*>(arg)->getOperator()->getAsString() == "case") {
1000 EmitCaseConstructHandler(static_cast<DagInit*>(arg),
1001 (std::string(IndentLevel) + Indent1).c_str(),
1002 Callback, EmitElseIf, OptDescs, O);
1003 }
1004 else {
1005 Callback(arg, IndentLevel, O);
1006 }
Mikhail Glushenkov35576b02008-05-30 06:10:19 +00001007 O << IndentLevel << "}\n";
1008 }
1009}
1010
Mikhail Glushenkov7adcf1e2008-05-09 08:27:26 +00001011/// EmitForwardOptionPropertyHandlingCode - Helper function used to
1012/// implement EmitOptionPropertyHandlingCode(). Emits code for
Mikhail Glushenkov50084e82008-09-22 20:46:19 +00001013/// handling the (forward) and (forward_as) option properties.
Mikhail Glushenkov7adcf1e2008-05-09 08:27:26 +00001014void EmitForwardOptionPropertyHandlingCode (const ToolOptionDescription& D,
Mikhail Glushenkov50084e82008-09-22 20:46:19 +00001015 const std::string& NewName,
Mikhail Glushenkov7adcf1e2008-05-09 08:27:26 +00001016 std::ostream& O) {
Mikhail Glushenkov50084e82008-09-22 20:46:19 +00001017 const std::string& Name = NewName.empty()
1018 ? ("-" + D.Name)
1019 : NewName;
1020
Mikhail Glushenkov7adcf1e2008-05-09 08:27:26 +00001021 switch (D.Type) {
1022 case OptionType::Switch:
Mikhail Glushenkov50084e82008-09-22 20:46:19 +00001023 O << Indent3 << "vec.push_back(\"" << Name << "\");\n";
Mikhail Glushenkov7adcf1e2008-05-09 08:27:26 +00001024 break;
1025 case OptionType::Parameter:
Mikhail Glushenkov50084e82008-09-22 20:46:19 +00001026 O << Indent3 << "vec.push_back(\"" << Name << "\");\n";
Mikhail Glushenkov7adcf1e2008-05-09 08:27:26 +00001027 O << Indent3 << "vec.push_back(" << D.GenVariableName() << ");\n";
1028 break;
1029 case OptionType::Prefix:
Mikhail Glushenkov50084e82008-09-22 20:46:19 +00001030 O << Indent3 << "vec.push_back(\"" << Name << "\" + "
Mikhail Glushenkov7adcf1e2008-05-09 08:27:26 +00001031 << D.GenVariableName() << ");\n";
1032 break;
1033 case OptionType::PrefixList:
1034 O << Indent3 << "for (" << D.GenTypeDeclaration()
1035 << "::iterator B = " << D.GenVariableName() << ".begin(),\n"
1036 << Indent3 << "E = " << D.GenVariableName() << ".end(); B != E; ++B)\n"
Mikhail Glushenkov50084e82008-09-22 20:46:19 +00001037 << Indent4 << "vec.push_back(\"" << Name << "\" + "
Mikhail Glushenkov7adcf1e2008-05-09 08:27:26 +00001038 << "*B);\n";
1039 break;
1040 case OptionType::ParameterList:
1041 O << Indent3 << "for (" << D.GenTypeDeclaration()
1042 << "::iterator B = " << D.GenVariableName() << ".begin(),\n"
1043 << Indent3 << "E = " << D.GenVariableName()
1044 << ".end() ; B != E; ++B) {\n"
Mikhail Glushenkov50084e82008-09-22 20:46:19 +00001045 << Indent4 << "vec.push_back(\"" << Name << "\");\n"
Mikhail Glushenkov7adcf1e2008-05-09 08:27:26 +00001046 << Indent4 << "vec.push_back(*B);\n"
1047 << Indent3 << "}\n";
1048 break;
Mikhail Glushenkovb623c322008-05-30 06:22:52 +00001049 case OptionType::Alias:
1050 default:
1051 throw std::string("Aliases are not allowed in tool option descriptions!");
Mikhail Glushenkov7adcf1e2008-05-09 08:27:26 +00001052 }
1053}
1054
Mikhail Glushenkovea6ce492008-05-30 06:15:20 +00001055// ToolOptionHasInterestingProperties - A helper function used by
1056// EmitOptionPropertyHandlingCode() that tells us whether we should
1057// emit any property handling code at all.
Mikhail Glushenkov31f52152008-05-30 06:10:47 +00001058bool ToolOptionHasInterestingProperties(const ToolOptionDescription& D) {
Mikhail Glushenkovea6ce492008-05-30 06:15:20 +00001059 bool ret = false;
1060 for (OptionPropertyList::const_iterator B = D.Props.begin(),
1061 E = D.Props.end(); B != E; ++B) {
1062 const OptionProperty& OptProp = *B;
Mikhail Glushenkov50084e82008-09-22 20:46:19 +00001063 if (OptProp.first == OptionPropertyType::AppendCmd
1064 || OptProp.first == OptionPropertyType::ForwardAs)
Mikhail Glushenkovea6ce492008-05-30 06:15:20 +00001065 ret = true;
1066 }
1067 if (D.isForward() || D.isUnpackValues())
1068 ret = true;
1069 return ret;
Mikhail Glushenkov31f52152008-05-30 06:10:47 +00001070}
1071
Mikhail Glushenkov7adcf1e2008-05-09 08:27:26 +00001072/// EmitOptionPropertyHandlingCode - Helper function used by
1073/// EmitGenerateActionMethod(). Emits code that handles option
1074/// properties.
Mikhail Glushenkov31f52152008-05-30 06:10:47 +00001075void EmitOptionPropertyHandlingCode (const ToolOptionDescription& D,
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001076 std::ostream& O)
1077{
Mikhail Glushenkov31f52152008-05-30 06:10:47 +00001078 if (!ToolOptionHasInterestingProperties(D))
1079 return;
Mikhail Glushenkov7adcf1e2008-05-09 08:27:26 +00001080 // Start of the if-clause.
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001081 O << Indent2 << "if (";
1082 if (D.Type == OptionType::Switch)
1083 O << D.GenVariableName();
1084 else
1085 O << '!' << D.GenVariableName() << ".empty()";
1086
1087 O <<") {\n";
1088
Mikhail Glushenkov7adcf1e2008-05-09 08:27:26 +00001089 // Handle option properties that take an argument.
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001090 for (OptionPropertyList::const_iterator B = D.Props.begin(),
1091 E = D.Props.end(); B!=E; ++B) {
1092 const OptionProperty& val = *B;
1093
1094 switch (val.first) {
1095 // (append_cmd cmd) property
1096 case OptionPropertyType::AppendCmd:
1097 O << Indent3 << "vec.push_back(\"" << val.second << "\");\n";
1098 break;
Mikhail Glushenkov50084e82008-09-22 20:46:19 +00001099 // (forward_as) property
1100 case OptionPropertyType::ForwardAs:
1101 EmitForwardOptionPropertyHandlingCode(D, val.second, O);
1102 break;
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001103 // Other properties with argument
1104 default:
1105 break;
1106 }
1107 }
1108
1109 // Handle flags
1110
1111 // (forward) property
Mikhail Glushenkov7adcf1e2008-05-09 08:27:26 +00001112 if (D.isForward())
Mikhail Glushenkov50084e82008-09-22 20:46:19 +00001113 EmitForwardOptionPropertyHandlingCode(D, "", O);
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001114
1115 // (unpack_values) property
1116 if (D.isUnpackValues()) {
1117 if (IsListOptionType(D.Type)) {
1118 O << Indent3 << "for (" << D.GenTypeDeclaration()
1119 << "::iterator B = " << D.GenVariableName() << ".begin(),\n"
1120 << Indent3 << "E = " << D.GenVariableName()
1121 << ".end(); B != E; ++B)\n"
Mikhail Glushenkov028f18e2008-05-06 18:13:45 +00001122 << Indent4 << "llvm::SplitString(*B, vec, \",\");\n";
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001123 }
1124 else if (D.Type == OptionType::Prefix || D.Type == OptionType::Parameter){
Mikhail Glushenkov028f18e2008-05-06 18:13:45 +00001125 O << Indent3 << "llvm::SplitString("
1126 << D.GenVariableName() << ", vec, \",\");\n";
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001127 }
1128 else {
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001129 throw std::string("Switches can't have unpack_values property!");
1130 }
1131 }
1132
Mikhail Glushenkov7adcf1e2008-05-09 08:27:26 +00001133 // End of the if-clause.
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001134 O << Indent2 << "}\n";
1135}
1136
Mikhail Glushenkov793f63d2008-05-30 06:12:24 +00001137/// SubstituteSpecialCommands - Perform string substitution for $CALL
1138/// and $ENV. Helper function used by EmitCmdLineVecFill().
1139std::string SubstituteSpecialCommands(const std::string& cmd) {
Mikhail Glushenkov1e453b02008-05-30 06:13:29 +00001140 size_t cparen = cmd.find(")");
1141 std::string ret;
1142
1143 if (cmd.find("$CALL(") == 0) {
1144 if (cmd.size() == 6)
1145 throw std::string("$CALL invocation: empty argument list!");
1146
1147 ret += "hooks::";
1148 ret += std::string(cmd.begin() + 6, cmd.begin() + cparen);
1149 ret += "()";
1150 }
1151 else if (cmd.find("$ENV(") == 0) {
1152 if (cmd.size() == 5)
1153 throw std::string("$ENV invocation: empty argument list!");
1154
Mikhail Glushenkovb4890702008-11-12 12:41:18 +00001155 ret += "checkCString(std::getenv(\"";
Mikhail Glushenkov1e453b02008-05-30 06:13:29 +00001156 ret += std::string(cmd.begin() + 5, cmd.begin() + cparen);
Mikhail Glushenkovb4890702008-11-12 12:41:18 +00001157 ret += "\"))";
Mikhail Glushenkov1e453b02008-05-30 06:13:29 +00001158 }
1159 else {
1160 throw "Unknown special command: " + cmd;
1161 }
1162
1163 if (cmd.begin() + cparen + 1 != cmd.end()) {
1164 ret += " + std::string(\"";
1165 ret += (cmd.c_str() + cparen + 1);
1166 ret += "\")";
1167 }
1168
1169 return ret;
Mikhail Glushenkov793f63d2008-05-30 06:12:24 +00001170}
1171
1172/// EmitCmdLineVecFill - Emit code that fills in the command line
1173/// vector. Helper function used by EmitGenerateActionMethod().
Mikhail Glushenkov35576b02008-05-30 06:10:19 +00001174void EmitCmdLineVecFill(const Init* CmdLine, const std::string& ToolName,
1175 bool Version, const char* IndentLevel,
1176 std::ostream& O) {
1177 StrVector StrVec;
Mikhail Glushenkov1e453b02008-05-30 06:13:29 +00001178 SplitString(InitPtrToString(CmdLine), StrVec);
Mikhail Glushenkov793f63d2008-05-30 06:12:24 +00001179 if (StrVec.empty())
Mikhail Glushenkov35576b02008-05-30 06:10:19 +00001180 throw "Tool " + ToolName + " has empty command line!";
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001181
Mikhail Glushenkov35576b02008-05-30 06:10:19 +00001182 StrVector::const_iterator I = StrVec.begin();
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001183 ++I;
Mikhail Glushenkov35576b02008-05-30 06:10:19 +00001184 for (StrVector::const_iterator E = StrVec.end(); I != E; ++I) {
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001185 const std::string& cmd = *I;
Mikhail Glushenkov35576b02008-05-30 06:10:19 +00001186 O << IndentLevel;
Mikhail Glushenkov793f63d2008-05-30 06:12:24 +00001187 if (cmd.at(0) == '$') {
1188 if (cmd == "$INFILE") {
1189 if (Version)
1190 O << "for (PathVector::const_iterator B = inFiles.begin()"
1191 << ", E = inFiles.end();\n"
1192 << IndentLevel << "B != E; ++B)\n"
1193 << IndentLevel << Indent1 << "vec.push_back(B->toString());\n";
1194 else
1195 O << "vec.push_back(inFile.toString());\n";
1196 }
1197 else if (cmd == "$OUTFILE") {
1198 O << "vec.push_back(outFile.toString());\n";
1199 }
1200 else {
Mikhail Glushenkov1e453b02008-05-30 06:13:29 +00001201 O << "vec.push_back(" << SubstituteSpecialCommands(cmd);
1202 O << ");\n";
Mikhail Glushenkov793f63d2008-05-30 06:12:24 +00001203 }
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001204 }
1205 else {
1206 O << "vec.push_back(\"" << cmd << "\");\n";
1207 }
1208 }
Mikhail Glushenkov52a54132008-05-30 06:23:29 +00001209 O << IndentLevel << "cmd = "
Mikhail Glushenkov793f63d2008-05-30 06:12:24 +00001210 << ((StrVec[0][0] == '$') ? SubstituteSpecialCommands(StrVec[0])
1211 : "\"" + StrVec[0] + "\"")
Mikhail Glushenkov52a54132008-05-30 06:23:29 +00001212 << ";\n";
Mikhail Glushenkov35576b02008-05-30 06:10:19 +00001213}
1214
Mikhail Glushenkov793f63d2008-05-30 06:12:24 +00001215/// EmitCmdLineVecFillCallback - A function object wrapper around
1216/// EmitCmdLineVecFill(). Used by EmitGenerateActionMethod() as an
1217/// argument to EmitCaseConstructHandler().
Mikhail Glushenkov35576b02008-05-30 06:10:19 +00001218class EmitCmdLineVecFillCallback {
1219 bool Version;
1220 const std::string& ToolName;
1221 public:
1222 EmitCmdLineVecFillCallback(bool Ver, const std::string& TN)
1223 : Version(Ver), ToolName(TN) {}
1224
1225 void operator()(const Init* Statement, const char* IndentLevel,
1226 std::ostream& O) const
1227 {
Mikhail Glushenkov31f52152008-05-30 06:10:47 +00001228 EmitCmdLineVecFill(Statement, ToolName, Version,
1229 (std::string(IndentLevel) + Indent1).c_str(), O);
Mikhail Glushenkov35576b02008-05-30 06:10:19 +00001230 }
1231};
1232
1233// EmitGenerateActionMethod - Emit one of two versions of the
1234// Tool::GenerateAction() method.
1235void EmitGenerateActionMethod (const ToolProperties& P,
1236 const GlobalOptionDescriptions& OptDescs,
1237 bool Version, std::ostream& O) {
1238 if (Version)
1239 O << Indent1 << "Action GenerateAction(const PathVector& inFiles,\n";
1240 else
1241 O << Indent1 << "Action GenerateAction(const sys::Path& inFile,\n";
1242
1243 O << Indent2 << "const sys::Path& outFile,\n"
Mikhail Glushenkovcdbfa1a2008-09-22 20:47:46 +00001244 << Indent2 << "const InputLanguagesSet& InLangs,\n"
1245 << Indent2 << "const LanguageMap& LangMap) const\n"
Mikhail Glushenkov35576b02008-05-30 06:10:19 +00001246 << Indent1 << "{\n"
foldre4a81682008-11-08 19:43:32 +00001247 << Indent2 << "std::string cmd;\n"
Mikhail Glushenkov35576b02008-05-30 06:10:19 +00001248 << Indent2 << "std::vector<std::string> vec;\n";
1249
1250 // cmd_line is either a string or a 'case' construct.
1251 if (typeid(*P.CmdLine) == typeid(StringInit))
1252 EmitCmdLineVecFill(P.CmdLine, P.Name, Version, Indent2, O);
1253 else
Mikhail Glushenkov0e92d2f2008-05-30 06:18:16 +00001254 EmitCaseConstructHandler(&InitPtrToDag(P.CmdLine), Indent2,
Mikhail Glushenkov35576b02008-05-30 06:10:19 +00001255 EmitCmdLineVecFillCallback(Version, P.Name),
Mikhail Glushenkovb24c8b22008-05-30 06:22:15 +00001256 true, OptDescs, O);
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001257
Mikhail Glushenkov7adcf1e2008-05-09 08:27:26 +00001258 // For every understood option, emit handling code.
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001259 for (ToolOptionDescriptions::const_iterator B = P.OptDescs.begin(),
1260 E = P.OptDescs.end(); B != E; ++B) {
1261 const ToolOptionDescription& val = B->second;
Mikhail Glushenkov31f52152008-05-30 06:10:47 +00001262 EmitOptionPropertyHandlingCode(val, O);
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001263 }
1264
Mikhail Glushenkov7adcf1e2008-05-09 08:27:26 +00001265 // Handle the Sink property.
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001266 if (P.isSink()) {
1267 O << Indent2 << "if (!" << SinkOptionName << ".empty()) {\n"
1268 << Indent3 << "vec.insert(vec.end(), "
1269 << SinkOptionName << ".begin(), " << SinkOptionName << ".end());\n"
1270 << Indent2 << "}\n";
1271 }
1272
Mikhail Glushenkov52a54132008-05-30 06:23:29 +00001273 O << Indent2 << "return Action(cmd, vec);\n"
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001274 << Indent1 << "}\n\n";
1275}
1276
Mikhail Glushenkov7adcf1e2008-05-09 08:27:26 +00001277/// EmitGenerateActionMethods - Emit two GenerateAction() methods for
1278/// a given Tool class.
Mikhail Glushenkov35576b02008-05-30 06:10:19 +00001279void EmitGenerateActionMethods (const ToolProperties& P,
1280 const GlobalOptionDescriptions& OptDescs,
1281 std::ostream& O) {
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001282 if (!P.isJoin())
1283 O << Indent1 << "Action GenerateAction(const PathVector& inFiles,\n"
Mikhail Glushenkov35576b02008-05-30 06:10:19 +00001284 << Indent2 << "const llvm::sys::Path& outFile,\n"
Mikhail Glushenkovcdbfa1a2008-09-22 20:47:46 +00001285 << Indent2 << "const InputLanguagesSet& InLangs,\n"
1286 << Indent2 << "const LanguageMap& LangMap) const\n"
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001287 << Indent1 << "{\n"
1288 << Indent2 << "throw std::runtime_error(\"" << P.Name
1289 << " is not a Join tool!\");\n"
1290 << Indent1 << "}\n\n";
1291 else
Mikhail Glushenkov35576b02008-05-30 06:10:19 +00001292 EmitGenerateActionMethod(P, OptDescs, true, O);
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001293
Mikhail Glushenkov35576b02008-05-30 06:10:19 +00001294 EmitGenerateActionMethod(P, OptDescs, false, O);
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001295}
1296
Mikhail Glushenkov7adcf1e2008-05-09 08:27:26 +00001297/// EmitIsLastMethod - Emit the IsLast() method for a given Tool
1298/// class.
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001299void EmitIsLastMethod (const ToolProperties& P, std::ostream& O) {
1300 O << Indent1 << "bool IsLast() const {\n"
1301 << Indent2 << "bool last = false;\n";
1302
1303 for (ToolOptionDescriptions::const_iterator B = P.OptDescs.begin(),
1304 E = P.OptDescs.end(); B != E; ++B) {
1305 const ToolOptionDescription& val = B->second;
1306
1307 if (val.isStopCompilation())
1308 O << Indent2
1309 << "if (" << val.GenVariableName()
1310 << ")\n" << Indent3 << "last = true;\n";
1311 }
1312
1313 O << Indent2 << "return last;\n"
1314 << Indent1 << "}\n\n";
1315}
1316
Mikhail Glushenkovbe46ae12008-05-07 21:50:19 +00001317/// EmitInOutLanguageMethods - Emit the [Input,Output]Language()
1318/// methods for a given Tool class.
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001319void EmitInOutLanguageMethods (const ToolProperties& P, std::ostream& O) {
Mikhail Glushenkov61923cb2008-05-30 06:24:49 +00001320 O << Indent1 << "const char** InputLanguages() const {\n"
1321 << Indent2 << "return InputLanguages_;\n"
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001322 << Indent1 << "}\n\n";
1323
Mikhail Glushenkovd379d162008-05-06 17:24:26 +00001324 O << Indent1 << "const char* OutputLanguage() const {\n"
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001325 << Indent2 << "return \"" << P.OutLanguage << "\";\n"
1326 << Indent1 << "}\n\n";
1327}
1328
Mikhail Glushenkovbe46ae12008-05-07 21:50:19 +00001329/// EmitOutputSuffixMethod - Emit the OutputSuffix() method for a
1330/// given Tool class.
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001331void EmitOutputSuffixMethod (const ToolProperties& P, std::ostream& O) {
Mikhail Glushenkovd379d162008-05-06 17:24:26 +00001332 O << Indent1 << "const char* OutputSuffix() const {\n"
Mikhail Glushenkovabab33b2008-05-30 06:13:02 +00001333 << Indent2 << "const char* ret = \"" << P.OutputSuffix << "\";\n";
1334
1335 for (ToolOptionDescriptions::const_iterator B = P.OptDescs.begin(),
1336 E = P.OptDescs.end(); B != E; ++B) {
1337 const ToolOptionDescription& OptDesc = B->second;
1338 for (OptionPropertyList::const_iterator B = OptDesc.Props.begin(),
1339 E = OptDesc.Props.end(); B != E; ++B) {
1340 const OptionProperty& OptProp = *B;
1341 if (OptProp.first == OptionPropertyType::OutputSuffix) {
1342 O << Indent2 << "if (" << OptDesc.GenVariableName() << ")\n"
1343 << Indent3 << "ret = \"" << OptProp.second << "\";\n";
1344 }
1345 }
1346 }
1347
1348 O << Indent2 << "return ret;\n"
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001349 << Indent1 << "}\n\n";
1350}
1351
Mikhail Glushenkovbe46ae12008-05-07 21:50:19 +00001352/// EmitNameMethod - Emit the Name() method for a given Tool class.
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001353void EmitNameMethod (const ToolProperties& P, std::ostream& O) {
Mikhail Glushenkovd379d162008-05-06 17:24:26 +00001354 O << Indent1 << "const char* Name() const {\n"
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001355 << Indent2 << "return \"" << P.Name << "\";\n"
1356 << Indent1 << "}\n\n";
1357}
1358
Mikhail Glushenkovbe46ae12008-05-07 21:50:19 +00001359/// EmitIsJoinMethod - Emit the IsJoin() method for a given Tool
1360/// class.
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001361void EmitIsJoinMethod (const ToolProperties& P, std::ostream& O) {
1362 O << Indent1 << "bool IsJoin() const {\n";
1363 if (P.isJoin())
1364 O << Indent2 << "return true;\n";
1365 else
1366 O << Indent2 << "return false;\n";
1367 O << Indent1 << "}\n\n";
1368}
1369
Mikhail Glushenkov61923cb2008-05-30 06:24:49 +00001370/// EmitStaticMemberDefinitions - Emit static member definitions for a
1371/// given Tool class.
1372void EmitStaticMemberDefinitions(const ToolProperties& P, std::ostream& O) {
1373 O << "const char* " << P.Name << "::InputLanguages_[] = {";
1374 for (StrVector::const_iterator B = P.InLanguage.begin(),
1375 E = P.InLanguage.end(); B != E; ++B)
1376 O << '\"' << *B << "\", ";
1377 O << "0};\n\n";
1378}
1379
Mikhail Glushenkovbe46ae12008-05-07 21:50:19 +00001380/// EmitToolClassDefinition - Emit a Tool class definition.
Mikhail Glushenkov35576b02008-05-30 06:10:19 +00001381void EmitToolClassDefinition (const ToolProperties& P,
1382 const GlobalOptionDescriptions& OptDescs,
1383 std::ostream& O) {
1384 if (P.Name == "root")
Mikhail Glushenkov2cfd2232008-05-06 16:35:25 +00001385 return;
1386
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001387 // Header
Mikhail Glushenkov121889c2008-05-06 17:26:53 +00001388 O << "class " << P.Name << " : public ";
1389 if (P.isJoin())
1390 O << "JoinTool";
1391 else
1392 O << "Tool";
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001393
Mikhail Glushenkov61923cb2008-05-30 06:24:49 +00001394 O << "{\nprivate:\n"
1395 << Indent1 << "static const char* InputLanguages_[];\n\n";
1396
1397 O << "public:\n";
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001398 EmitNameMethod(P, O);
1399 EmitInOutLanguageMethods(P, O);
1400 EmitOutputSuffixMethod(P, O);
1401 EmitIsJoinMethod(P, O);
Mikhail Glushenkov35576b02008-05-30 06:10:19 +00001402 EmitGenerateActionMethods(P, OptDescs, O);
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001403 EmitIsLastMethod(P, O);
1404
1405 // Close class definition
Mikhail Glushenkov61923cb2008-05-30 06:24:49 +00001406 O << "};\n";
1407
1408 EmitStaticMemberDefinitions(P, O);
1409
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001410}
1411
Mikhail Glushenkovbe46ae12008-05-07 21:50:19 +00001412/// EmitOptionDescriptions - Iterate over a list of option
1413/// descriptions and emit registration code.
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001414void EmitOptionDescriptions (const GlobalOptionDescriptions& descs,
1415 std::ostream& O)
1416{
Mikhail Glushenkovb623c322008-05-30 06:22:52 +00001417 std::vector<GlobalOptionDescription> Aliases;
1418
Mikhail Glushenkov52a54132008-05-30 06:23:29 +00001419 // Emit static cl::Option variables.
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001420 for (GlobalOptionDescriptions::const_iterator B = descs.begin(),
1421 E = descs.end(); B!=E; ++B) {
1422 const GlobalOptionDescription& val = B->second;
1423
Mikhail Glushenkovb623c322008-05-30 06:22:52 +00001424 if (val.Type == OptionType::Alias) {
1425 Aliases.push_back(val);
1426 continue;
1427 }
1428
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001429 O << val.GenTypeDeclaration() << ' '
1430 << val.GenVariableName()
1431 << "(\"" << val.Name << '\"';
1432
1433 if (val.Type == OptionType::Prefix || val.Type == OptionType::PrefixList)
1434 O << ", cl::Prefix";
1435
1436 if (val.isRequired()) {
1437 switch (val.Type) {
1438 case OptionType::PrefixList:
1439 case OptionType::ParameterList:
1440 O << ", cl::OneOrMore";
1441 break;
1442 default:
1443 O << ", cl::Required";
1444 }
1445 }
1446
Mikhail Glushenkovc9b650d2008-11-28 00:13:25 +00001447 if (val.isReallyHidden() || val.isHidden()) {
1448 if (val.isRequired())
1449 O << " |";
1450 else
1451 O << ",";
1452 if (val.isReallyHidden())
1453 O << " cl::ReallyHidden";
1454 else
1455 O << " cl::Hidden";
1456 }
1457
Mikhail Glushenkovb623c322008-05-30 06:22:52 +00001458 if (!val.Help.empty())
1459 O << ", cl::desc(\"" << val.Help << "\")";
1460
1461 O << ");\n";
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001462 }
1463
Mikhail Glushenkovb623c322008-05-30 06:22:52 +00001464 // Emit the aliases (they should go after all the 'proper' options).
1465 for (std::vector<GlobalOptionDescription>::const_iterator
1466 B = Aliases.begin(), E = Aliases.end(); B != E; ++B) {
1467 const GlobalOptionDescription& val = *B;
1468
1469 O << val.GenTypeDeclaration() << ' '
1470 << val.GenVariableName()
1471 << "(\"" << val.Name << '\"';
1472
1473 GlobalOptionDescriptions::container_type
1474 ::const_iterator F = descs.Descriptions.find(val.Help);
1475 if (F != descs.Descriptions.end())
1476 O << ", cl::aliasopt(" << F->second.GenVariableName() << ")";
1477 else
1478 throw val.Name + ": alias to an unknown option!";
1479
1480 O << ", cl::desc(\"" << "An alias for -" + val.Help << "\"));\n";
1481 }
1482
1483 // Emit the sink option.
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001484 if (descs.HasSink)
1485 O << "cl::list<std::string> " << SinkOptionName << "(cl::Sink);\n";
1486
1487 O << '\n';
1488}
1489
Mikhail Glushenkovbe46ae12008-05-07 21:50:19 +00001490/// EmitPopulateLanguageMap - Emit the PopulateLanguageMap() function.
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001491void EmitPopulateLanguageMap (const RecordKeeper& Records, std::ostream& O)
1492{
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001493 // Generate code
Mikhail Glushenkov945522f2008-09-22 20:49:34 +00001494 O << "namespace {\n\n";
1495 O << "void PopulateLanguageMapLocal(LanguageMap& langMap) {\n";
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001496
Mikhail Glushenkovfa990682008-11-17 17:29:18 +00001497 // Get the relevant field out of RecordKeeper
Mikhail Glushenkov973b3a32008-11-17 17:29:42 +00001498 const Record* LangMapRecord = Records.getDef("LanguageMap");
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001499
Mikhail Glushenkovfa990682008-11-17 17:29:18 +00001500 // It is allowed for a plugin to have no language map.
1501 if (LangMapRecord) {
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001502
Mikhail Glushenkovfa990682008-11-17 17:29:18 +00001503 ListInit* LangsToSuffixesList = LangMapRecord->getValueAsListInit("map");
1504 if (!LangsToSuffixesList)
1505 throw std::string("Error in the language map definition!");
1506
1507 for (unsigned i = 0; i < LangsToSuffixesList->size(); ++i) {
Mikhail Glushenkov973b3a32008-11-17 17:29:42 +00001508 const Record* LangToSuffixes = LangsToSuffixesList->getElementAsRecord(i);
Mikhail Glushenkovfa990682008-11-17 17:29:18 +00001509
1510 const std::string& Lang = LangToSuffixes->getValueAsString("lang");
1511 const ListInit* Suffixes = LangToSuffixes->getValueAsListInit("suffixes");
1512
1513 for (unsigned i = 0; i < Suffixes->size(); ++i)
1514 O << Indent1 << "langMap[\""
1515 << InitPtrToString(Suffixes->getElement(i))
1516 << "\"] = \"" << Lang << "\";\n";
1517 }
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001518 }
1519
Mikhail Glushenkov945522f2008-09-22 20:49:34 +00001520 O << "}\n\n}\n\n";
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001521}
1522
Mikhail Glushenkovbe46ae12008-05-07 21:50:19 +00001523/// FillInToolToLang - Fills in two tables that map tool names to
1524/// (input, output) languages. Used by the typechecker.
Mikhail Glushenkov46d4e972008-05-06 16:36:06 +00001525void FillInToolToLang (const ToolPropertiesList& TPList,
Mikhail Glushenkov0e92d2f2008-05-30 06:18:16 +00001526 StringMap<StringSet<> >& ToolToInLang,
Mikhail Glushenkov46d4e972008-05-06 16:36:06 +00001527 StringMap<std::string>& ToolToOutLang) {
1528 for (ToolPropertiesList::const_iterator B = TPList.begin(), E = TPList.end();
1529 B != E; ++B) {
1530 const ToolProperties& P = *(*B);
Mikhail Glushenkov0e92d2f2008-05-30 06:18:16 +00001531 for (StrVector::const_iterator B = P.InLanguage.begin(),
1532 E = P.InLanguage.end(); B != E; ++B)
1533 ToolToInLang[P.Name].insert(*B);
Mikhail Glushenkov46d4e972008-05-06 16:36:06 +00001534 ToolToOutLang[P.Name] = P.OutLanguage;
1535 }
1536}
1537
Mikhail Glushenkovbe46ae12008-05-07 21:50:19 +00001538/// TypecheckGraph - Check that names for output and input languages
Mikhail Glushenkovfa990682008-11-17 17:29:18 +00001539/// on all edges do match. This doesn't do much when the information
1540/// about the whole graph is not available (i.e. when compiling most
1541/// plugins).
Mikhail Glushenkovd24c1292008-11-28 00:13:47 +00001542void TypecheckGraph (const RecordVector& EdgeVector,
Mikhail Glushenkov46d4e972008-05-06 16:36:06 +00001543 const ToolPropertiesList& TPList) {
Mikhail Glushenkov0e92d2f2008-05-30 06:18:16 +00001544 StringMap<StringSet<> > ToolToInLang;
Mikhail Glushenkov46d4e972008-05-06 16:36:06 +00001545 StringMap<std::string> ToolToOutLang;
1546
1547 FillInToolToLang(TPList, ToolToInLang, ToolToOutLang);
Mikhail Glushenkov0e92d2f2008-05-30 06:18:16 +00001548 StringMap<std::string>::iterator IAE = ToolToOutLang.end();
1549 StringMap<StringSet<> >::iterator IBE = ToolToInLang.end();
Mikhail Glushenkov46d4e972008-05-06 16:36:06 +00001550
Cédric Venet397dcfa2008-12-05 13:37:30 +00001551 for (RecordVector::const_iterator Beg = EdgeVector.begin(),
1552 E = EdgeVector.end(); Beg != E; ++Beg) {
1553 const Record* Edge = *Beg;
Mikhail Glushenkovfa990682008-11-17 17:29:18 +00001554 const std::string& A = Edge->getValueAsString("a");
1555 const std::string& B = Edge->getValueAsString("b");
1556 StringMap<std::string>::iterator IA = ToolToOutLang.find(A);
1557 StringMap<StringSet<> >::iterator IB = ToolToInLang.find(B);
1558
1559 if (A != "root") {
1560 if (IA != IAE && IB != IBE && IB->second.count(IA->second) == 0)
1561 throw "Edge " + A + "->" + B
1562 + ": output->input language mismatch";
1563 }
1564
1565 if (B == "root")
Mikhail Glushenkov761958d2008-05-06 16:36:50 +00001566 throw std::string("Edges back to the root are not allowed!");
Mikhail Glushenkov46d4e972008-05-06 16:36:06 +00001567 }
1568}
1569
Mikhail Glushenkov793f63d2008-05-30 06:12:24 +00001570/// IncDecWeight - Helper function passed to EmitCaseConstructHandler()
1571/// by EmitEdgeClass().
Mikhail Glushenkov35576b02008-05-30 06:10:19 +00001572void IncDecWeight (const Init* i, const char* IndentLevel,
1573 std::ostream& O) {
Mikhail Glushenkov0e92d2f2008-05-30 06:18:16 +00001574 const DagInit& d = InitPtrToDag(i);
Mikhail Glushenkovdedba642008-05-30 06:08:50 +00001575 const std::string& OpName = d.getOperator()->getAsString();
1576
1577 if (OpName == "inc_weight")
1578 O << IndentLevel << Indent1 << "ret += ";
1579 else if (OpName == "dec_weight")
1580 O << IndentLevel << Indent1 << "ret -= ";
1581 else
1582 throw "Unknown operator in edge properties list: " + OpName + '!';
1583
1584 if (d.getNumArgs() > 0)
1585 O << InitPtrToInt(d.getArg(0)) << ";\n";
1586 else
1587 O << "2;\n";
1588
Mikhail Glushenkovdfcad6c2008-05-06 18:18:20 +00001589}
1590
Mikhail Glushenkovbe46ae12008-05-07 21:50:19 +00001591/// EmitEdgeClass - Emit a single Edge# class.
Mikhail Glushenkov35576b02008-05-30 06:10:19 +00001592void EmitEdgeClass (unsigned N, const std::string& Target,
1593 DagInit* Case, const GlobalOptionDescriptions& OptDescs,
1594 std::ostream& O) {
Mikhail Glushenkov8d0d5d22008-05-06 17:23:14 +00001595
1596 // Class constructor.
1597 O << "class Edge" << N << ": public Edge {\n"
1598 << "public:\n"
1599 << Indent1 << "Edge" << N << "() : Edge(\"" << Target
1600 << "\") {}\n\n"
1601
Mikhail Glushenkov7dbc0ab2008-05-06 18:14:24 +00001602 // Function Weight().
Mikhail Glushenkovd6228882008-05-06 18:15:12 +00001603 << Indent1 << "unsigned Weight(const InputLanguagesSet& InLangs) const {\n"
Mikhail Glushenkov7dbc0ab2008-05-06 18:14:24 +00001604 << Indent2 << "unsigned ret = 0;\n";
Mikhail Glushenkov8d0d5d22008-05-06 17:23:14 +00001605
Mikhail Glushenkovdedba642008-05-30 06:08:50 +00001606 // Handle the 'case' construct.
Mikhail Glushenkovb24c8b22008-05-30 06:22:15 +00001607 EmitCaseConstructHandler(Case, Indent2, IncDecWeight, false, OptDescs, O);
Mikhail Glushenkov7dbc0ab2008-05-06 18:14:24 +00001608
1609 O << Indent2 << "return ret;\n"
1610 << Indent1 << "};\n\n};\n\n";
Mikhail Glushenkov8d0d5d22008-05-06 17:23:14 +00001611}
1612
Mikhail Glushenkov793f63d2008-05-30 06:12:24 +00001613/// EmitEdgeClasses - Emit Edge* classes that represent graph edges.
Mikhail Glushenkovd24c1292008-11-28 00:13:47 +00001614void EmitEdgeClasses (const RecordVector& EdgeVector,
Mikhail Glushenkov46d4e972008-05-06 16:36:06 +00001615 const GlobalOptionDescriptions& OptDescs,
1616 std::ostream& O) {
Mikhail Glushenkovd24c1292008-11-28 00:13:47 +00001617 int i = 0;
Cédric Venet397dcfa2008-12-05 13:37:30 +00001618 for (RecordVector::const_iterator Beg = EdgeVector.begin(),
1619 E = EdgeVector.end(); Beg != E; ++Beg) {
1620 const Record* Edge = *Beg;
Mikhail Glushenkovfa990682008-11-17 17:29:18 +00001621 const std::string& B = Edge->getValueAsString("b");
Mikhail Glushenkovdedba642008-05-30 06:08:50 +00001622 DagInit* Weight = Edge->getValueAsDag("weight");
Mikhail Glushenkov46d4e972008-05-06 16:36:06 +00001623
Mikhail Glushenkovd24c1292008-11-28 00:13:47 +00001624 if (!isDagEmpty(Weight))
1625 EmitEdgeClass(i, B, Weight, OptDescs, O);
1626 ++i;
Mikhail Glushenkov46d4e972008-05-06 16:36:06 +00001627 }
1628}
1629
Mikhail Glushenkovbe46ae12008-05-07 21:50:19 +00001630/// EmitPopulateCompilationGraph - Emit the PopulateCompilationGraph()
1631/// function.
Mikhail Glushenkovd24c1292008-11-28 00:13:47 +00001632void EmitPopulateCompilationGraph (const RecordVector& EdgeVector,
Mikhail Glushenkov973b3a32008-11-17 17:29:42 +00001633 const ToolPropertiesList& ToolProps,
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001634 std::ostream& O)
1635{
Mikhail Glushenkov945522f2008-09-22 20:49:34 +00001636 O << "namespace {\n\n";
1637 O << "void PopulateCompilationGraphLocal(CompilationGraph& G) {\n";
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001638
Mikhail Glushenkov973b3a32008-11-17 17:29:42 +00001639 for (ToolPropertiesList::const_iterator B = ToolProps.begin(),
1640 E = ToolProps.end(); B != E; ++B)
1641 O << Indent1 << "G.insertNode(new " << (*B)->Name << "());\n";
Mikhail Glushenkov719c25812008-11-12 00:05:17 +00001642
Mikhail Glushenkov2cfd2232008-05-06 16:35:25 +00001643 O << '\n';
1644
Mikhail Glushenkov719c25812008-11-12 00:05:17 +00001645 // Insert edges.
1646
Mikhail Glushenkovd24c1292008-11-28 00:13:47 +00001647 int i = 0;
Cédric Venet397dcfa2008-12-05 13:37:30 +00001648 for (RecordVector::const_iterator Beg = EdgeVector.begin(),
1649 E = EdgeVector.end(); Beg != E; ++Beg) {
1650 const Record* Edge = *Beg;
Mikhail Glushenkovfa990682008-11-17 17:29:18 +00001651 const std::string& A = Edge->getValueAsString("a");
1652 const std::string& B = Edge->getValueAsString("b");
Mikhail Glushenkovdedba642008-05-30 06:08:50 +00001653 DagInit* Weight = Edge->getValueAsDag("weight");
Mikhail Glushenkov761958d2008-05-06 16:36:50 +00001654
Mikhail Glushenkovfa990682008-11-17 17:29:18 +00001655 O << Indent1 << "G.insertEdge(\"" << A << "\", ";
Mikhail Glushenkov761958d2008-05-06 16:36:50 +00001656
Mikhail Glushenkovdedba642008-05-30 06:08:50 +00001657 if (isDagEmpty(Weight))
Mikhail Glushenkovfa990682008-11-17 17:29:18 +00001658 O << "new SimpleEdge(\"" << B << "\")";
Mikhail Glushenkov761958d2008-05-06 16:36:50 +00001659 else
1660 O << "new Edge" << i << "()";
1661
1662 O << ");\n";
Mikhail Glushenkovd24c1292008-11-28 00:13:47 +00001663 ++i;
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001664 }
1665
Mikhail Glushenkov945522f2008-09-22 20:49:34 +00001666 O << "}\n\n}\n\n";
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001667}
1668
Mikhail Glushenkov793f63d2008-05-30 06:12:24 +00001669/// ExtractHookNames - Extract the hook names from all instances of
1670/// $CALL(HookName) in the provided command line string. Helper
1671/// function used by FillInHookNames().
1672void ExtractHookNames(const Init* CmdLine, StrVector& HookNames) {
1673 StrVector cmds;
Mikhail Glushenkov1e453b02008-05-30 06:13:29 +00001674 llvm::SplitString(InitPtrToString(CmdLine), cmds);
Mikhail Glushenkov793f63d2008-05-30 06:12:24 +00001675 for (StrVector::const_iterator B = cmds.begin(), E = cmds.end();
1676 B != E; ++B) {
1677 const std::string& cmd = *B;
1678 if (cmd.find("$CALL(") == 0) {
1679 if (cmd.size() == 6)
1680 throw std::string("$CALL invocation: empty argument list!");
Mikhail Glushenkov1e453b02008-05-30 06:13:29 +00001681 HookNames.push_back(std::string(cmd.begin() + 6,
1682 cmd.begin() + cmd.find(")")));
Mikhail Glushenkov793f63d2008-05-30 06:12:24 +00001683 }
1684 }
1685}
1686
Mikhail Glushenkovb24c8b22008-05-30 06:22:15 +00001687/// ExtractHookNamesFromCaseConstruct - Extract hook names from the
1688/// 'case' expression, handle nesting. Helper function used by
1689/// FillInHookNames().
1690void ExtractHookNamesFromCaseConstruct(Init* Case, StrVector& HookNames) {
1691 const DagInit& d = InitPtrToDag(Case);
1692 bool even = false;
1693 for (DagInit::const_arg_iterator B = d.arg_begin(), E = d.arg_end();
1694 B != E; ++B) {
1695 Init* arg = *B;
1696 if (even && dynamic_cast<DagInit*>(arg)
1697 && static_cast<DagInit*>(arg)->getOperator()->getAsString() == "case")
1698 ExtractHookNamesFromCaseConstruct(arg, HookNames);
1699 else if (even)
1700 ExtractHookNames(arg, HookNames);
1701 even = !even;
1702 }
1703}
1704
Mikhail Glushenkov793f63d2008-05-30 06:12:24 +00001705/// FillInHookNames - Actually extract the hook names from all command
1706/// line strings. Helper function used by EmitHookDeclarations().
1707void FillInHookNames(const ToolPropertiesList& TPList,
1708 StrVector& HookNames) {
Mikhail Glushenkovb24c8b22008-05-30 06:22:15 +00001709 // For all command lines:
Mikhail Glushenkov793f63d2008-05-30 06:12:24 +00001710 for (ToolPropertiesList::const_iterator B = TPList.begin(),
1711 E = TPList.end(); B != E; ++B) {
1712 const ToolProperties& P = *(*B);
1713 if (!P.CmdLine)
1714 continue;
Mikhail Glushenkovb24c8b22008-05-30 06:22:15 +00001715 if (dynamic_cast<StringInit*>(P.CmdLine))
Mikhail Glushenkov793f63d2008-05-30 06:12:24 +00001716 // This is a string.
1717 ExtractHookNames(P.CmdLine, HookNames);
Mikhail Glushenkovb24c8b22008-05-30 06:22:15 +00001718 else
Mikhail Glushenkov793f63d2008-05-30 06:12:24 +00001719 // This is a 'case' construct.
Mikhail Glushenkovb24c8b22008-05-30 06:22:15 +00001720 ExtractHookNamesFromCaseConstruct(P.CmdLine, HookNames);
Mikhail Glushenkov793f63d2008-05-30 06:12:24 +00001721 }
1722}
1723
1724/// EmitHookDeclarations - Parse CmdLine fields of all the tool
1725/// property records and emit hook function declaration for each
1726/// instance of $CALL(HookName).
1727void EmitHookDeclarations(const ToolPropertiesList& ToolProps,
1728 std::ostream& O) {
1729 StrVector HookNames;
1730 FillInHookNames(ToolProps, HookNames);
1731 if (HookNames.empty())
1732 return;
1733 std::sort(HookNames.begin(), HookNames.end());
1734 StrVector::const_iterator E = std::unique(HookNames.begin(), HookNames.end());
1735
1736 O << "namespace hooks {\n";
1737 for (StrVector::const_iterator B = HookNames.begin(); B != E; ++B)
1738 O << Indent1 << "std::string " << *B << "();\n";
1739
1740 O << "}\n\n";
1741}
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001742
Mikhail Glushenkov945522f2008-09-22 20:49:34 +00001743/// EmitRegisterPlugin - Emit code to register this plugin.
Mikhail Glushenkoveb71ecf2008-11-17 17:30:25 +00001744void EmitRegisterPlugin(int Priority, std::ostream& O) {
Mikhail Glushenkov945522f2008-09-22 20:49:34 +00001745 O << "namespace {\n\n"
Mikhail Glushenkoveb71ecf2008-11-17 17:30:25 +00001746 << "struct Plugin : public llvmc::BasePlugin {\n\n"
1747 << Indent1 << "int Priority() const { return " << Priority << "; }\n\n"
Mikhail Glushenkov945522f2008-09-22 20:49:34 +00001748 << Indent1 << "void PopulateLanguageMap(LanguageMap& langMap) const\n"
1749 << Indent1 << "{ PopulateLanguageMapLocal(langMap); }\n\n"
1750 << Indent1
1751 << "void PopulateCompilationGraph(CompilationGraph& graph) const\n"
1752 << Indent1 << "{ PopulateCompilationGraphLocal(graph); }\n"
1753 << "};\n\n"
1754
1755 << "static llvmc::RegisterPlugin<Plugin> RP;\n\n}\n\n";
1756}
1757
Mikhail Glushenkovb4890702008-11-12 12:41:18 +00001758/// EmitIncludes - Emit necessary #include directives and some
1759/// additional declarations.
Mikhail Glushenkov945522f2008-09-22 20:49:34 +00001760void EmitIncludes(std::ostream& O) {
Mikhail Glushenkov62ab3112008-09-22 20:50:40 +00001761 O << "#include \"llvm/CompilerDriver/CompilationGraph.h\"\n"
1762 << "#include \"llvm/CompilerDriver/Plugin.h\"\n"
1763 << "#include \"llvm/CompilerDriver/Tool.h\"\n\n"
Mikhail Glushenkov945522f2008-09-22 20:49:34 +00001764
1765 << "#include \"llvm/ADT/StringExtras.h\"\n"
1766 << "#include \"llvm/Support/CommandLine.h\"\n\n"
1767
1768 << "#include <cstdlib>\n"
1769 << "#include <stdexcept>\n\n"
1770
1771 << "using namespace llvm;\n"
1772 << "using namespace llvmc;\n\n"
1773
Mikhail Glushenkovb4890702008-11-12 12:41:18 +00001774 << "extern cl::opt<std::string> OutputFilename;\n\n"
1775
1776 << "inline const char* checkCString(const char* s)\n"
1777 << "{ return s == NULL ? \"\" : s; }\n\n";
Mikhail Glushenkov945522f2008-09-22 20:49:34 +00001778}
1779
Mikhail Glushenkov973b3a32008-11-17 17:29:42 +00001780/// NotInGraph - Helper function object for FilterNotInGraph.
1781struct NotInGraph {
1782private:
1783 const llvm::StringSet<>& ToolsInGraph_;
1784
1785public:
1786 NotInGraph(const llvm::StringSet<>& ToolsInGraph)
1787 : ToolsInGraph_(ToolsInGraph)
1788 {}
1789
1790 bool operator()(const IntrusiveRefCntPtr<ToolProperties>& x) {
1791 return (ToolsInGraph_.count(x->Name) == 0);
1792 }
1793};
1794
1795/// FilterNotInGraph - Filter out from ToolProps all Tools not
1796/// mentioned in the compilation graph definition.
Mikhail Glushenkovd24c1292008-11-28 00:13:47 +00001797void FilterNotInGraph (const RecordVector& EdgeVector,
Mikhail Glushenkov973b3a32008-11-17 17:29:42 +00001798 ToolPropertiesList& ToolProps) {
1799
1800 // List all tools mentioned in the graph.
1801 llvm::StringSet<> ToolsInGraph;
Mikhail Glushenkov973b3a32008-11-17 17:29:42 +00001802
Cédric Venet397dcfa2008-12-05 13:37:30 +00001803 for (RecordVector::const_iterator Beg = EdgeVector.begin(),
1804 E = EdgeVector.end(); Beg != E; ++Beg) {
Mikhail Glushenkovd24c1292008-11-28 00:13:47 +00001805
Cédric Venet397dcfa2008-12-05 13:37:30 +00001806 const Record* Edge = *Beg;
Mikhail Glushenkov973b3a32008-11-17 17:29:42 +00001807 const std::string& A = Edge->getValueAsString("a");
1808 const std::string& B = Edge->getValueAsString("b");
1809
1810 if (A != "root")
1811 ToolsInGraph.insert(A);
1812 ToolsInGraph.insert(B);
1813 }
1814
1815 // Filter ToolPropertiesList.
1816 ToolPropertiesList::iterator new_end =
1817 std::remove_if(ToolProps.begin(), ToolProps.end(),
1818 NotInGraph(ToolsInGraph));
1819 ToolProps.erase(new_end, ToolProps.end());
1820}
1821
Mikhail Glushenkovd24c1292008-11-28 00:13:47 +00001822/// CalculatePriority - Calculate the priority of this plugin.
Mikhail Glushenkoveb71ecf2008-11-17 17:30:25 +00001823int CalculatePriority(RecordVector::const_iterator B,
1824 RecordVector::const_iterator E) {
1825 int total = 0;
1826 for (; B!=E; ++B) {
1827 total += static_cast<int>((*B)->getValueAsInt("priority"));
1828 }
1829 return total;
1830}
1831
Mikhail Glushenkovd24c1292008-11-28 00:13:47 +00001832/// FillInEdgeVector - Merge all compilation graph definitions into
1833/// one single edge list.
1834void FillInEdgeVector(RecordVector::const_iterator B,
1835 RecordVector::const_iterator E, RecordVector& Out) {
1836 for (; B != E; ++B) {
1837 const ListInit* edges = (*B)->getValueAsListInit("edges");
1838
1839 for (unsigned i = 0; i < edges->size(); ++i)
1840 Out.push_back(edges->getElementAsRecord(i));
1841 }
1842}
1843
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001844// End of anonymous namespace
Mikhail Glushenkovc1f738d2008-05-06 18:12:03 +00001845}
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001846
Mikhail Glushenkovbe46ae12008-05-07 21:50:19 +00001847/// run - The back-end entry point.
Mikhail Glushenkovc1f738d2008-05-06 18:12:03 +00001848void LLVMCConfigurationEmitter::run (std::ostream &O) {
Mikhail Glushenkovffe736e2008-05-30 06:21:48 +00001849 try {
Mikhail Glushenkovbe46ae12008-05-07 21:50:19 +00001850
1851 // Emit file header.
Mikhail Glushenkov34307a92008-05-06 18:08:59 +00001852 EmitSourceFileHeader("LLVMC Configuration Library", O);
Mikhail Glushenkov945522f2008-09-22 20:49:34 +00001853 EmitIncludes(O);
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001854
Mikhail Glushenkovd24c1292008-11-28 00:13:47 +00001855 // Collect tool properties.
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001856 RecordVector Tools = Records.getAllDerivedDefinitions("Tool");
Mikhail Glushenkov973b3a32008-11-17 17:29:42 +00001857 ToolPropertiesList ToolProps;
1858 GlobalOptionDescriptions OptDescs;
1859 CollectToolProperties(Tools.begin(), Tools.end(), ToolProps, OptDescs);
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001860
Mikhail Glushenkovd24c1292008-11-28 00:13:47 +00001861 // Collect option properties.
Mikhail Glushenkoveb71ecf2008-11-17 17:30:25 +00001862 const RecordVector& OptionLists =
1863 Records.getAllDerivedDefinitions("OptionList");
Mikhail Glushenkovfa990682008-11-17 17:29:18 +00001864 CollectPropertiesFromOptionLists(OptionLists.begin(), OptionLists.end(),
Mikhail Glushenkov973b3a32008-11-17 17:29:42 +00001865 OptDescs);
1866
Mikhail Glushenkovd24c1292008-11-28 00:13:47 +00001867 // Collect compilation graph edges.
1868 const RecordVector& CompilationGraphs =
1869 Records.getAllDerivedDefinitions("CompilationGraph");
1870 RecordVector EdgeVector;
1871 FillInEdgeVector(CompilationGraphs.begin(), CompilationGraphs.end(),
1872 EdgeVector);
Mikhail Glushenkov973b3a32008-11-17 17:29:42 +00001873
Mikhail Glushenkovd24c1292008-11-28 00:13:47 +00001874 // Filter out all tools not mentioned in the compilation graph.
1875 FilterNotInGraph(EdgeVector, ToolProps);
Mikhail Glushenkov973b3a32008-11-17 17:29:42 +00001876
1877 // Typecheck the compilation graph.
Mikhail Glushenkovd24c1292008-11-28 00:13:47 +00001878 TypecheckGraph(EdgeVector, ToolProps);
Mikhail Glushenkovd638e852008-05-30 06:26:08 +00001879
Mikhail Glushenkove5fcb552008-05-30 06:28:37 +00001880 // Check that there are no options without side effects (specified
1881 // only in the OptionList).
Mikhail Glushenkov973b3a32008-11-17 17:29:42 +00001882 CheckForSuperfluousOptions(ToolProps, OptDescs);
Mikhail Glushenkove5fcb552008-05-30 06:28:37 +00001883
Mikhail Glushenkovbe46ae12008-05-07 21:50:19 +00001884 // Emit global option registration code.
Mikhail Glushenkov973b3a32008-11-17 17:29:42 +00001885 EmitOptionDescriptions(OptDescs, O);
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001886
Mikhail Glushenkov793f63d2008-05-30 06:12:24 +00001887 // Emit hook declarations.
Mikhail Glushenkov973b3a32008-11-17 17:29:42 +00001888 EmitHookDeclarations(ToolProps, O);
Mikhail Glushenkov793f63d2008-05-30 06:12:24 +00001889
Mikhail Glushenkovbe46ae12008-05-07 21:50:19 +00001890 // Emit PopulateLanguageMap() function
1891 // (a language map maps from file extensions to language names).
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001892 EmitPopulateLanguageMap(Records, O);
1893
Mikhail Glushenkovbe46ae12008-05-07 21:50:19 +00001894 // Emit Tool classes.
Mikhail Glushenkov973b3a32008-11-17 17:29:42 +00001895 for (ToolPropertiesList::const_iterator B = ToolProps.begin(),
1896 E = ToolProps.end(); B!=E; ++B)
1897 EmitToolClassDefinition(*(*B), OptDescs, O);
Mikhail Glushenkov46d4e972008-05-06 16:36:06 +00001898
Mikhail Glushenkovbe46ae12008-05-07 21:50:19 +00001899 // Emit Edge# classes.
Mikhail Glushenkovd24c1292008-11-28 00:13:47 +00001900 EmitEdgeClasses(EdgeVector, OptDescs, O);
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001901
Mikhail Glushenkovbe46ae12008-05-07 21:50:19 +00001902 // Emit PopulateCompilationGraph() function.
Mikhail Glushenkovd24c1292008-11-28 00:13:47 +00001903 EmitPopulateCompilationGraph(EdgeVector, ToolProps, O);
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001904
Mikhail Glushenkov945522f2008-09-22 20:49:34 +00001905 // Emit code for plugin registration.
Mikhail Glushenkoveb71ecf2008-11-17 17:30:25 +00001906 const RecordVector& Priorities =
1907 Records.getAllDerivedDefinitions("PluginPriority");
Mikhail Glushenkovd24c1292008-11-28 00:13:47 +00001908 EmitRegisterPlugin(CalculatePriority(Priorities.begin(),
1909 Priorities.end()), O);
Mikhail Glushenkov945522f2008-09-22 20:49:34 +00001910
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001911 // EOF
Mikhail Glushenkovffe736e2008-05-30 06:21:48 +00001912 } catch (std::exception& Error) {
1913 throw Error.what() + std::string(" - usually this means a syntax error.");
1914 }
Anton Korobeynikove9ffb5b2008-03-23 08:57:20 +00001915}