blob: 5de8a5b46502482789fb12fe58e567ddfaf86f98 [file] [log] [blame]
Jan Voung44c3a802015-03-27 16:29:08 -07001//===- subzero/src/IceClFlags.cpp - Command line flags and parsing --------===//
2//
3// The Subzero Code Generator
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
Andrew Scull9612d322015-07-06 14:53:25 -07009///
10/// \file
Reed Kotler22339872015-12-27 23:57:10 -080011/// \brief Defines commandline flags parsing of class Ice::ClFlags.
Jim Stichnoth92a6e5b2015-12-02 16:52:44 -080012///
13/// This currently relies on llvm::cl to parse. In the future, the minimal build
14/// can have a simpler parser.
Andrew Scull9612d322015-07-06 14:53:25 -070015///
Jan Voung44c3a802015-03-27 16:29:08 -070016//===----------------------------------------------------------------------===//
17
Jan Voung44c3a802015-03-27 16:29:08 -070018#include "IceClFlags.h"
John Porto67f8de92015-06-25 10:14:17 -070019
John Portoc5bc5cb2016-03-21 11:18:02 -070020#include "IceClFlags.def"
Jim Stichnoth98da9662015-06-27 06:38:08 -070021
Jim Stichnothb0051df2016-01-13 11:39:15 -080022#ifdef __clang__
Jim Stichnoth98da9662015-06-27 06:38:08 -070023#pragma clang diagnostic push
24#pragma clang diagnostic ignored "-Wunused-parameter"
Jim Stichnothb0051df2016-01-13 11:39:15 -080025#endif // __clang__
26
John Porto67f8de92015-06-25 10:14:17 -070027#include "llvm/Support/CommandLine.h"
Jim Stichnothb0051df2016-01-13 11:39:15 -080028
29#ifdef __clang__
Jim Stichnoth98da9662015-06-27 06:38:08 -070030#pragma clang diagnostic pop
Jim Stichnothb0051df2016-01-13 11:39:15 -080031#endif // __clang__
Jan Voung44c3a802015-03-27 16:29:08 -070032
John Portoc5bc5cb2016-03-21 11:18:02 -070033#include <utility>
Jan Voung44c3a802015-03-27 16:29:08 -070034
35namespace {
John Portoc5bc5cb2016-03-21 11:18:02 -070036// cl is used to alias the llvm::cl types and functions that we need.
37namespace cl {
Jan Voung44c3a802015-03-27 16:29:08 -070038
John Portoc5bc5cb2016-03-21 11:18:02 -070039using alias = llvm::cl::alias;
Jan Voung44c3a802015-03-27 16:29:08 -070040
John Portoc5bc5cb2016-03-21 11:18:02 -070041using aliasopt = llvm::cl::aliasopt;
Karl Schimpf57d31ac2015-10-07 09:53:12 -070042
John Portoc5bc5cb2016-03-21 11:18:02 -070043using llvm::cl::CommaSeparated;
44
45using desc = llvm::cl::desc;
46
47template <typename T> using initializer = llvm::cl::initializer<T>;
48
49template <typename T> initializer<T> init(const T &Val) {
50 return initializer<T>(Val);
51}
52
53template <typename T> using list = llvm::cl::list<T>;
54
55using llvm::cl::NotHidden;
56
57template <typename T> using opt = llvm::cl::opt<T>;
58
59using llvm::cl::ParseCommandLineOptions;
60
61using llvm::cl::Positional;
62
Jim Stichnoth79810752016-12-26 14:16:00 -080063// LLVM commit 3ffe113e11168abcd809ec5ac539538ade5db0cb changed the internals of
64// llvm::cl that need to be mirrored here. That commit removed the clEnumValEnd
65// macro, so we can use that to determine which version of LLVM we're compiling
66// against.
67#if defined(clEnumValEnd)
68
69#define CLENUMVALEND , clEnumValEnd
70
John Portoc5bc5cb2016-03-21 11:18:02 -070071template <typename T> using ValuesClass = llvm::cl::ValuesClass<T>;
72
73template <typename T, typename... A>
74ValuesClass<T> values(const char *Arg, T Val, const char *Desc, A &&... Args) {
75 return llvm::cl::values(Arg, Val, Desc, std::forward<A>(Args)..., nullptr);
76}
77
Jim Stichnoth79810752016-12-26 14:16:00 -080078#else // !defined(clEnumValEnd)
79
80#define CLENUMVALEND
81
82using llvm::cl::OptionEnumValue;
83
84template <typename... A> llvm::cl::ValuesClass values(A &&... Args) {
85 return llvm::cl::values(std::forward<A>(Args)...);
86}
87
88#endif // !defined(clEnumValEnd)
89
John Portoc5bc5cb2016-03-21 11:18:02 -070090using llvm::cl::value_desc;
91} // end of namespace cl
92
93// cl_type_traits is used to convert between a tuple of <T, cl_detail::*flag> to
94// the appropriate (llvm::)cl object.
95template <typename B, typename CL> struct cl_type_traits {};
96
97template <typename T>
98struct cl_type_traits<T, ::Ice::cl_detail::dev_list_flag> {
99 using cl_type = cl::list<T>;
100};
101
102template <typename T> struct cl_type_traits<T, ::Ice::cl_detail::dev_opt_flag> {
103 using cl_type = cl::opt<T>;
104};
105
106template <typename T>
107struct cl_type_traits<T, ::Ice::cl_detail::release_opt_flag> {
108 using cl_type = cl::opt<T>;
109};
110
111#define X(Name, Type, ClType, ...) \
112 cl_type_traits<Type, Ice::cl_detail::ClType>::cl_type Name##Obj(__VA_ARGS__);
113COMMAND_LINE_FLAGS
114#undef X
115
116// Add declarations that do not need to add members to ClFlags below.
Jim Stichnoth4e10aa22015-10-16 13:13:11 -0700117cl::alias AllowExternDefinedSymbolsA(
118 "allow-extern", cl::desc("Alias for --allow-externally-defined-symbols"),
John Portoc5bc5cb2016-03-21 11:18:02 -0700119 cl::NotHidden, cl::aliasopt(AllowExternDefinedSymbolsObj));
Jim Stichnoth4e10aa22015-10-16 13:13:11 -0700120
John Portoc5bc5cb2016-03-21 11:18:02 -0700121std::string AppNameObj;
Andrew Scull2c862522015-08-06 08:41:53 -0700122
Jan Voung44c3a802015-03-27 16:29:08 -0700123} // end of anonymous namespace
124
125namespace Ice {
126
Karl Schimpfd4699942016-04-02 09:55:31 -0700127ClFlags ClFlags::Flags;
128
Jim Stichnothfd07ad02016-04-20 10:12:46 -0700129void ClFlags::parseFlags(int argc, const char *const *argv) {
Jan Voung44c3a802015-03-27 16:29:08 -0700130 cl::ParseCommandLineOptions(argc, argv);
Jim Stichnoth467ffe52016-03-29 15:01:06 -0700131 AppNameObj = argv[0];
Jan Voung44c3a802015-03-27 16:29:08 -0700132}
133
John Portoc5bc5cb2016-03-21 11:18:02 -0700134namespace {
135// flagInitOrStorageTypeDefault is some template voodoo for peeling off the
136// llvm::cl modifiers from a flag's declaration, until its initial value is
137// found. If none is found, then the default value for the storage type is
138// returned.
139template <typename Ty> Ty flagInitOrStorageTypeDefault() { return Ty(); }
140
141template <typename Ty, typename T, typename... A>
142Ty flagInitOrStorageTypeDefault(cl::initializer<T> &&Value, A &&...) {
143 return Value.Init;
Karl Schimpfd8b32892015-04-16 15:47:25 -0700144}
145
John Portoc5bc5cb2016-03-21 11:18:02 -0700146// is_cl_initializer is used to prevent an ambiguous call between the previous
147// version of flagInitOrStorageTypeDefault, and the next, which is flagged by
148// g++.
149template <typename T> struct is_cl_initializer {
150 static constexpr bool value = false;
151};
152
153template <typename T> struct is_cl_initializer<cl::initializer<T>> {
154 static constexpr bool value = true;
155};
156
157template <typename Ty, typename T, typename... A>
158typename std::enable_if<!is_cl_initializer<T>::value, Ty>::type
159flagInitOrStorageTypeDefault(T &&, A &&... Other) {
160 return flagInitOrStorageTypeDefault<Ty>(std::forward<A>(Other)...);
161}
162
163} // end of anonymous namespace
164
165void ClFlags::resetClFlags() {
166#define X(Name, Type, ClType, ...) \
167 Name = flagInitOrStorageTypeDefault< \
168 detail::cl_type_traits<Type, cl_detail::ClType>::storage_type>( \
169 __VA_ARGS__);
170 COMMAND_LINE_FLAGS
171#undef X
172}
173
174namespace {
175
176// toSetterParam is template magic that is needed to convert between (llvm::)cl
177// objects and the arguments to ClFlags' setters. ToSetterParam is a traits
178// object that we need in order for the multiple specializations to
179// toSetterParam to agree on their return type.
180template <typename T> struct ToSetterParam { using ReturnType = const T &; };
181
182template <> struct ToSetterParam<cl::list<Ice::VerboseItem>> {
183 using ReturnType = Ice::VerboseMask;
184};
185
Jim Stichnothf5fdd232016-05-09 12:24:36 -0700186template <> struct ToSetterParam<cl::list<std::string>> {
187 using ReturnType = std::vector<std::string>;
188};
189
John Portoc5bc5cb2016-03-21 11:18:02 -0700190template <typename T>
191typename ToSetterParam<T>::ReturnType toSetterParam(const T &Param) {
192 return Param;
193}
194
195template <>
196ToSetterParam<cl::list<Ice::VerboseItem>>::ReturnType
197toSetterParam(const cl::list<Ice::VerboseItem> &Param) {
Jan Voung44c3a802015-03-27 16:29:08 -0700198 Ice::VerboseMask VMask = Ice::IceV_None;
Andrew Scull57e12682015-09-16 11:30:19 -0700199 // Don't generate verbose messages if routines to dump messages are not
200 // available.
Jim Stichnoth20b71f52015-06-24 15:52:24 -0700201 if (BuildDefs::dump()) {
John Portoc5bc5cb2016-03-21 11:18:02 -0700202 for (unsigned i = 0; i != Param.size(); ++i)
203 VMask |= Param[i];
Jan Voung44c3a802015-03-27 16:29:08 -0700204 }
John Portoc5bc5cb2016-03-21 11:18:02 -0700205 return VMask;
Jan Voung44c3a802015-03-27 16:29:08 -0700206}
207
Jim Stichnothf5fdd232016-05-09 12:24:36 -0700208template <>
209ToSetterParam<cl::list<std::string>>::ReturnType
210toSetterParam(const cl::list<std::string> &Param) {
211 return *&Param;
212}
213
John Portoc5bc5cb2016-03-21 11:18:02 -0700214} // end of anonymous namespace
215
216void ClFlags::getParsedClFlags(ClFlags &OutFlags) {
217#define X(Name, Type, ClType, ...) OutFlags.set##Name(toSetterParam(Name##Obj));
218 COMMAND_LINE_FLAGS
219#undef X
220
221 // If any value needs a non-trivial parsed value, set it below.
222 OutFlags.setAllowExternDefinedSymbols(AllowExternDefinedSymbolsObj ||
223 DisableInternalObj);
224 OutFlags.setDisableHybridAssembly(DisableHybridAssemblyObj ||
225 (OutFileTypeObj != Ice::FT_Iasm));
Jim Stichnothdd6dcfa2016-04-18 12:52:09 -0700226 OutFlags.ForceO2.init(OutFlags.getForceO2String());
Jim Stichnothb9a84722016-08-01 13:18:36 -0700227 OutFlags.SplitInsts.init(OutFlags.getSplitInstString());
Jim Stichnothdd6dcfa2016-04-18 12:52:09 -0700228 OutFlags.TestStatus.init(OutFlags.getTestStatusString());
229 OutFlags.TimingFocus.init(OutFlags.getTimingFocusOnString());
230 OutFlags.TranslateOnly.init(OutFlags.getTranslateOnlyString());
231 OutFlags.VerboseFocus.init(OutFlags.getVerboseFocusOnString());
Jan Voung44c3a802015-03-27 16:29:08 -0700232}
233
234} // end of namespace Ice