1 //===- 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 //===----------------------------------------------------------------------===//
9 ///
10 /// \file
11 /// \brief Defines commandline flags parsing of class Ice::ClFlags.
12 ///
13 /// This currently relies on llvm::cl to parse. In the future, the minimal build
14 /// can have a simpler parser.
15 ///
16 //===----------------------------------------------------------------------===//
17 
18 #include "IceClFlags.h"
19 
20 #include "IceClFlags.def"
21 
22 #ifdef __clang__
23 #pragma clang diagnostic push
24 #pragma clang diagnostic ignored "-Wunused-parameter"
25 #endif // __clang__
26 
27 #include "llvm/Support/CommandLine.h"
28 
29 #ifdef __clang__
30 #pragma clang diagnostic pop
31 #endif // __clang__
32 
33 #include <utility>
34 
35 namespace {
36 // cl is used to alias the llvm::cl types and functions that we need.
37 namespace cl {
38 
39 using alias = llvm::cl::alias;
40 
41 using aliasopt = llvm::cl::aliasopt;
42 
43 using llvm::cl::CommaSeparated;
44 
45 using desc = llvm::cl::desc;
46 
47 template <typename T> using initializer = llvm::cl::initializer<T>;
48 
init(const T & Val)49 template <typename T> initializer<T> init(const T &Val) {
50   return initializer<T>(Val);
51 }
52 
53 template <typename T> using list = llvm::cl::list<T>;
54 
55 using llvm::cl::NotHidden;
56 
57 template <typename T> using opt = llvm::cl::opt<T>;
58 
59 using llvm::cl::ParseCommandLineOptions;
60 
61 using llvm::cl::Positional;
62 
63 // 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 
71 template <typename T> using ValuesClass = llvm::cl::ValuesClass<T>;
72 
73 template <typename T, typename... A>
values(const char * Arg,T Val,const char * Desc,A &&...Args)74 ValuesClass<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 
78 #else // !defined(clEnumValEnd)
79 
80 #define CLENUMVALEND
81 
82 using llvm::cl::OptionEnumValue;
83 
values(A &&...Args)84 template <typename... A> llvm::cl::ValuesClass values(A &&... Args) {
85   return llvm::cl::values(std::forward<A>(Args)...);
86 }
87 
88 #endif // !defined(clEnumValEnd)
89 
90 using 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.
95 template <typename B, typename CL> struct cl_type_traits {};
96 
97 template <typename T>
98 struct cl_type_traits<T, ::Ice::cl_detail::dev_list_flag> {
99   using cl_type = cl::list<T>;
100 };
101 
102 template <typename T> struct cl_type_traits<T, ::Ice::cl_detail::dev_opt_flag> {
103   using cl_type = cl::opt<T>;
104 };
105 
106 template <typename T>
107 struct 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__);
113 COMMAND_LINE_FLAGS
114 #undef X
115 
116 // Add declarations that do not need to add members to ClFlags below.
117 cl::alias AllowExternDefinedSymbolsA(
118     "allow-extern", cl::desc("Alias for --allow-externally-defined-symbols"),
119     cl::NotHidden, cl::aliasopt(AllowExternDefinedSymbolsObj));
120 
121 std::string AppNameObj;
122 
123 } // end of anonymous namespace
124 
125 namespace Ice {
126 
127 ClFlags ClFlags::Flags;
128 
parseFlags(int argc,const char * const * argv)129 void ClFlags::parseFlags(int argc, const char *const *argv) {
130   cl::ParseCommandLineOptions(argc, argv);
131   AppNameObj = argv[0];
132 }
133 
134 namespace {
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.
flagInitOrStorageTypeDefault()139 template <typename Ty> Ty flagInitOrStorageTypeDefault() { return Ty(); }
140 
141 template <typename Ty, typename T, typename... A>
142 Ty flagInitOrStorageTypeDefault(cl::initializer<T> &&Value, A &&...) {
143   return Value.Init;
144 }
145 
146 // 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++.
149 template <typename T> struct is_cl_initializer {
150   static constexpr bool value = false;
151 };
152 
153 template <typename T> struct is_cl_initializer<cl::initializer<T>> {
154   static constexpr bool value = true;
155 };
156 
157 template <typename Ty, typename T, typename... A>
158 typename std::enable_if<!is_cl_initializer<T>::value, Ty>::type
flagInitOrStorageTypeDefault(T &&,A &&...Other)159 flagInitOrStorageTypeDefault(T &&, A &&... Other) {
160   return flagInitOrStorageTypeDefault<Ty>(std::forward<A>(Other)...);
161 }
162 
163 } // end of anonymous namespace
164 
resetClFlags()165 void 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 
174 namespace {
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.
180 template <typename T> struct ToSetterParam { using ReturnType = const T &; };
181 
182 template <> struct ToSetterParam<cl::list<Ice::VerboseItem>> {
183   using ReturnType = Ice::VerboseMask;
184 };
185 
186 template <> struct ToSetterParam<cl::list<std::string>> {
187   using ReturnType = std::vector<std::string>;
188 };
189 
190 template <typename T>
toSetterParam(const T & Param)191 typename ToSetterParam<T>::ReturnType toSetterParam(const T &Param) {
192   return Param;
193 }
194 
195 template <>
196 ToSetterParam<cl::list<Ice::VerboseItem>>::ReturnType
toSetterParam(const cl::list<Ice::VerboseItem> & Param)197 toSetterParam(const cl::list<Ice::VerboseItem> &Param) {
198   Ice::VerboseMask VMask = Ice::IceV_None;
199   // Don't generate verbose messages if routines to dump messages are not
200   // available.
201   if (BuildDefs::dump()) {
202     for (unsigned i = 0; i != Param.size(); ++i)
203       VMask |= Param[i];
204   }
205   return VMask;
206 }
207 
208 template <>
209 ToSetterParam<cl::list<std::string>>::ReturnType
toSetterParam(const cl::list<std::string> & Param)210 toSetterParam(const cl::list<std::string> &Param) {
211   return *&Param;
212 }
213 
214 } // end of anonymous namespace
215 
getParsedClFlags(ClFlags & OutFlags)216 void 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));
226   OutFlags.ForceO2.init(OutFlags.getForceO2String());
227   OutFlags.SplitInsts.init(OutFlags.getSplitInstString());
228   OutFlags.TestStatus.init(OutFlags.getTestStatusString());
229   OutFlags.TimingFocus.init(OutFlags.getTimingFocusOnString());
230   OutFlags.TranslateOnly.init(OutFlags.getTranslateOnlyString());
231   OutFlags.VerboseFocus.init(OutFlags.getVerboseFocusOnString());
232 }
233 
234 } // end of namespace Ice
235