Jan Voung | 44c3a80 | 2015-03-27 16:29:08 -0700 | [diff] [blame] | 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 | //===----------------------------------------------------------------------===// |
Andrew Scull | 9612d32 | 2015-07-06 14:53:25 -0700 | [diff] [blame] | 9 | /// |
| 10 | /// \file |
Reed Kotler | 2233987 | 2015-12-27 23:57:10 -0800 | [diff] [blame] | 11 | /// \brief Defines commandline flags parsing of class Ice::ClFlags. |
Jim Stichnoth | 92a6e5b | 2015-12-02 16:52:44 -0800 | [diff] [blame] | 12 | /// |
| 13 | /// This currently relies on llvm::cl to parse. In the future, the minimal build |
| 14 | /// can have a simpler parser. |
Andrew Scull | 9612d32 | 2015-07-06 14:53:25 -0700 | [diff] [blame] | 15 | /// |
Jan Voung | 44c3a80 | 2015-03-27 16:29:08 -0700 | [diff] [blame] | 16 | //===----------------------------------------------------------------------===// |
| 17 | |
Jan Voung | 44c3a80 | 2015-03-27 16:29:08 -0700 | [diff] [blame] | 18 | #include "IceClFlags.h" |
John Porto | 67f8de9 | 2015-06-25 10:14:17 -0700 | [diff] [blame] | 19 | |
John Porto | c5bc5cb | 2016-03-21 11:18:02 -0700 | [diff] [blame] | 20 | #include "IceClFlags.def" |
Jim Stichnoth | 98da966 | 2015-06-27 06:38:08 -0700 | [diff] [blame] | 21 | |
Jim Stichnoth | b0051df | 2016-01-13 11:39:15 -0800 | [diff] [blame] | 22 | #ifdef __clang__ |
Jim Stichnoth | 98da966 | 2015-06-27 06:38:08 -0700 | [diff] [blame] | 23 | #pragma clang diagnostic push |
| 24 | #pragma clang diagnostic ignored "-Wunused-parameter" |
Jim Stichnoth | b0051df | 2016-01-13 11:39:15 -0800 | [diff] [blame] | 25 | #endif // __clang__ |
| 26 | |
John Porto | 67f8de9 | 2015-06-25 10:14:17 -0700 | [diff] [blame] | 27 | #include "llvm/Support/CommandLine.h" |
Jim Stichnoth | b0051df | 2016-01-13 11:39:15 -0800 | [diff] [blame] | 28 | |
| 29 | #ifdef __clang__ |
Jim Stichnoth | 98da966 | 2015-06-27 06:38:08 -0700 | [diff] [blame] | 30 | #pragma clang diagnostic pop |
Jim Stichnoth | b0051df | 2016-01-13 11:39:15 -0800 | [diff] [blame] | 31 | #endif // __clang__ |
Jan Voung | 44c3a80 | 2015-03-27 16:29:08 -0700 | [diff] [blame] | 32 | |
John Porto | c5bc5cb | 2016-03-21 11:18:02 -0700 | [diff] [blame] | 33 | #include <utility> |
Jan Voung | 44c3a80 | 2015-03-27 16:29:08 -0700 | [diff] [blame] | 34 | |
| 35 | namespace { |
John Porto | c5bc5cb | 2016-03-21 11:18:02 -0700 | [diff] [blame] | 36 | // cl is used to alias the llvm::cl types and functions that we need. |
| 37 | namespace cl { |
Jan Voung | 44c3a80 | 2015-03-27 16:29:08 -0700 | [diff] [blame] | 38 | |
John Porto | c5bc5cb | 2016-03-21 11:18:02 -0700 | [diff] [blame] | 39 | using alias = llvm::cl::alias; |
Jan Voung | 44c3a80 | 2015-03-27 16:29:08 -0700 | [diff] [blame] | 40 | |
John Porto | c5bc5cb | 2016-03-21 11:18:02 -0700 | [diff] [blame] | 41 | using aliasopt = llvm::cl::aliasopt; |
Karl Schimpf | 57d31ac | 2015-10-07 09:53:12 -0700 | [diff] [blame] | 42 | |
John Porto | c5bc5cb | 2016-03-21 11:18:02 -0700 | [diff] [blame] | 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 | |
Jim Stichnoth | 7981075 | 2016-12-26 14:16:00 -0800 | [diff] [blame] | 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 | |
John Porto | c5bc5cb | 2016-03-21 11:18:02 -0700 | [diff] [blame] | 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 | |
Jim Stichnoth | 7981075 | 2016-12-26 14:16:00 -0800 | [diff] [blame] | 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 | |
John Porto | c5bc5cb | 2016-03-21 11:18:02 -0700 | [diff] [blame] | 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. |
Jim Stichnoth | 4e10aa2 | 2015-10-16 13:13:11 -0700 | [diff] [blame] | 117 | cl::alias AllowExternDefinedSymbolsA( |
| 118 | "allow-extern", cl::desc("Alias for --allow-externally-defined-symbols"), |
John Porto | c5bc5cb | 2016-03-21 11:18:02 -0700 | [diff] [blame] | 119 | cl::NotHidden, cl::aliasopt(AllowExternDefinedSymbolsObj)); |
Jim Stichnoth | 4e10aa2 | 2015-10-16 13:13:11 -0700 | [diff] [blame] | 120 | |
John Porto | c5bc5cb | 2016-03-21 11:18:02 -0700 | [diff] [blame] | 121 | std::string AppNameObj; |
Andrew Scull | 2c86252 | 2015-08-06 08:41:53 -0700 | [diff] [blame] | 122 | |
Jan Voung | 44c3a80 | 2015-03-27 16:29:08 -0700 | [diff] [blame] | 123 | } // end of anonymous namespace |
| 124 | |
| 125 | namespace Ice { |
| 126 | |
Karl Schimpf | d469994 | 2016-04-02 09:55:31 -0700 | [diff] [blame] | 127 | ClFlags ClFlags::Flags; |
| 128 | |
Jim Stichnoth | fd07ad0 | 2016-04-20 10:12:46 -0700 | [diff] [blame] | 129 | void ClFlags::parseFlags(int argc, const char *const *argv) { |
Jan Voung | 44c3a80 | 2015-03-27 16:29:08 -0700 | [diff] [blame] | 130 | cl::ParseCommandLineOptions(argc, argv); |
Jim Stichnoth | 467ffe5 | 2016-03-29 15:01:06 -0700 | [diff] [blame] | 131 | AppNameObj = argv[0]; |
Jan Voung | 44c3a80 | 2015-03-27 16:29:08 -0700 | [diff] [blame] | 132 | } |
| 133 | |
John Porto | c5bc5cb | 2016-03-21 11:18:02 -0700 | [diff] [blame] | 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; |
Karl Schimpf | d8b3289 | 2015-04-16 15:47:25 -0700 | [diff] [blame] | 144 | } |
| 145 | |
John Porto | c5bc5cb | 2016-03-21 11:18:02 -0700 | [diff] [blame] | 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 | |
Jim Stichnoth | f5fdd23 | 2016-05-09 12:24:36 -0700 | [diff] [blame] | 186 | template <> struct ToSetterParam<cl::list<std::string>> { |
| 187 | using ReturnType = std::vector<std::string>; |
| 188 | }; |
| 189 | |
John Porto | c5bc5cb | 2016-03-21 11:18:02 -0700 | [diff] [blame] | 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) { |
Jan Voung | 44c3a80 | 2015-03-27 16:29:08 -0700 | [diff] [blame] | 198 | Ice::VerboseMask VMask = Ice::IceV_None; |
Andrew Scull | 57e1268 | 2015-09-16 11:30:19 -0700 | [diff] [blame] | 199 | // Don't generate verbose messages if routines to dump messages are not |
| 200 | // available. |
Jim Stichnoth | 20b71f5 | 2015-06-24 15:52:24 -0700 | [diff] [blame] | 201 | if (BuildDefs::dump()) { |
John Porto | c5bc5cb | 2016-03-21 11:18:02 -0700 | [diff] [blame] | 202 | for (unsigned i = 0; i != Param.size(); ++i) |
| 203 | VMask |= Param[i]; |
Jan Voung | 44c3a80 | 2015-03-27 16:29:08 -0700 | [diff] [blame] | 204 | } |
John Porto | c5bc5cb | 2016-03-21 11:18:02 -0700 | [diff] [blame] | 205 | return VMask; |
Jan Voung | 44c3a80 | 2015-03-27 16:29:08 -0700 | [diff] [blame] | 206 | } |
| 207 | |
Jim Stichnoth | f5fdd23 | 2016-05-09 12:24:36 -0700 | [diff] [blame] | 208 | template <> |
| 209 | ToSetterParam<cl::list<std::string>>::ReturnType |
| 210 | toSetterParam(const cl::list<std::string> &Param) { |
| 211 | return *&Param; |
| 212 | } |
| 213 | |
John Porto | c5bc5cb | 2016-03-21 11:18:02 -0700 | [diff] [blame] | 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)); |
Jim Stichnoth | dd6dcfa | 2016-04-18 12:52:09 -0700 | [diff] [blame] | 226 | OutFlags.ForceO2.init(OutFlags.getForceO2String()); |
Jim Stichnoth | b9a8472 | 2016-08-01 13:18:36 -0700 | [diff] [blame] | 227 | OutFlags.SplitInsts.init(OutFlags.getSplitInstString()); |
Jim Stichnoth | dd6dcfa | 2016-04-18 12:52:09 -0700 | [diff] [blame] | 228 | OutFlags.TestStatus.init(OutFlags.getTestStatusString()); |
| 229 | OutFlags.TimingFocus.init(OutFlags.getTimingFocusOnString()); |
| 230 | OutFlags.TranslateOnly.init(OutFlags.getTranslateOnlyString()); |
| 231 | OutFlags.VerboseFocus.init(OutFlags.getVerboseFocusOnString()); |
Jan Voung | 44c3a80 | 2015-03-27 16:29:08 -0700 | [diff] [blame] | 232 | } |
| 233 | |
| 234 | } // end of namespace Ice |