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 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> 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 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 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. 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 159 flagInitOrStorageTypeDefault(T &&, A &&... Other) { 160 return flagInitOrStorageTypeDefault<Ty>(std::forward<A>(Other)...); 161 } 162 163 } // end of anonymous namespace 164 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> 191 typename ToSetterParam<T>::ReturnType toSetterParam(const T &Param) { 192 return Param; 193 } 194 195 template <> 196 ToSetterParam<cl::list<Ice::VerboseItem>>::ReturnType 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 210 toSetterParam(const cl::list<std::string> &Param) { 211 return *&Param; 212 } 213 214 } // end of anonymous namespace 215 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