| //===- subzero/src/IceClFlags.cpp - Command line flags and parsing --------===// | |
| // | |
| // The Subzero Code Generator | |
| // | |
| // This file is distributed under the University of Illinois Open Source | |
| // License. See LICENSE.TXT for details. | |
| // | |
| //===----------------------------------------------------------------------===// | |
| /// | |
| /// \file | |
| /// \brief Defines commandline flags parsing of class Ice::ClFlags. | |
| /// | |
| /// This currently relies on llvm::cl to parse. In the future, the minimal build | |
| /// can have a simpler parser. | |
| /// | |
| //===----------------------------------------------------------------------===// | |
| #include "IceClFlags.h" | |
| #include "IceClFlags.def" | |
| #ifdef __clang__ | |
| #pragma clang diagnostic push | |
| #pragma clang diagnostic ignored "-Wunused-parameter" | |
| #endif // __clang__ | |
| #include "llvm/Support/CommandLine.h" | |
| #ifdef __clang__ | |
| #pragma clang diagnostic pop | |
| #endif // __clang__ | |
| #include <utility> | |
| namespace { | |
| // cl is used to alias the llvm::cl types and functions that we need. | |
| namespace cl { | |
| using alias = llvm::cl::alias; | |
| using aliasopt = llvm::cl::aliasopt; | |
| using llvm::cl::CommaSeparated; | |
| using desc = llvm::cl::desc; | |
| template <typename T> using initializer = llvm::cl::initializer<T>; | |
| template <typename T> initializer<T> init(const T &Val) { | |
| return initializer<T>(Val); | |
| } | |
| template <typename T> using list = llvm::cl::list<T>; | |
| using llvm::cl::NotHidden; | |
| template <typename T> using opt = llvm::cl::opt<T>; | |
| using llvm::cl::ParseCommandLineOptions; | |
| using llvm::cl::Positional; | |
| // LLVM commit 3ffe113e11168abcd809ec5ac539538ade5db0cb changed the internals of | |
| // llvm::cl that need to be mirrored here. That commit removed the clEnumValEnd | |
| // macro, so we can use that to determine which version of LLVM we're compiling | |
| // against. | |
| #if defined(clEnumValEnd) | |
| #define CLENUMVALEND , clEnumValEnd | |
| template <typename T> using ValuesClass = llvm::cl::ValuesClass<T>; | |
| template <typename T, typename... A> | |
| ValuesClass<T> values(const char *Arg, T Val, const char *Desc, A &&... Args) { | |
| return llvm::cl::values(Arg, Val, Desc, std::forward<A>(Args)..., nullptr); | |
| } | |
| #else // !defined(clEnumValEnd) | |
| #define CLENUMVALEND | |
| using llvm::cl::OptionEnumValue; | |
| template <typename... A> llvm::cl::ValuesClass values(A &&... Args) { | |
| return llvm::cl::values(std::forward<A>(Args)...); | |
| } | |
| #endif // !defined(clEnumValEnd) | |
| using llvm::cl::value_desc; | |
| } // end of namespace cl | |
| // cl_type_traits is used to convert between a tuple of <T, cl_detail::*flag> to | |
| // the appropriate (llvm::)cl object. | |
| template <typename B, typename CL> struct cl_type_traits {}; | |
| template <typename T> | |
| struct cl_type_traits<T, ::Ice::cl_detail::dev_list_flag> { | |
| using cl_type = cl::list<T>; | |
| }; | |
| template <typename T> struct cl_type_traits<T, ::Ice::cl_detail::dev_opt_flag> { | |
| using cl_type = cl::opt<T>; | |
| }; | |
| template <typename T> | |
| struct cl_type_traits<T, ::Ice::cl_detail::release_opt_flag> { | |
| using cl_type = cl::opt<T>; | |
| }; | |
| #define X(Name, Type, ClType, ...) \ | |
| cl_type_traits<Type, Ice::cl_detail::ClType>::cl_type Name##Obj(__VA_ARGS__); | |
| COMMAND_LINE_FLAGS | |
| #undef X | |
| // Add declarations that do not need to add members to ClFlags below. | |
| cl::alias AllowExternDefinedSymbolsA( | |
| "allow-extern", cl::desc("Alias for --allow-externally-defined-symbols"), | |
| cl::NotHidden, cl::aliasopt(AllowExternDefinedSymbolsObj)); | |
| std::string AppNameObj; | |
| } // end of anonymous namespace | |
| namespace Ice { | |
| ClFlags ClFlags::Flags; | |
| void ClFlags::parseFlags(int argc, const char *const *argv) { | |
| cl::ParseCommandLineOptions(argc, argv); | |
| AppNameObj = argv[0]; | |
| } | |
| namespace { | |
| // flagInitOrStorageTypeDefault is some template voodoo for peeling off the | |
| // llvm::cl modifiers from a flag's declaration, until its initial value is | |
| // found. If none is found, then the default value for the storage type is | |
| // returned. | |
| template <typename Ty> Ty flagInitOrStorageTypeDefault() { return Ty(); } | |
| template <typename Ty, typename T, typename... A> | |
| Ty flagInitOrStorageTypeDefault(cl::initializer<T> &&Value, A &&...) { | |
| return Value.Init; | |
| } | |
| // is_cl_initializer is used to prevent an ambiguous call between the previous | |
| // version of flagInitOrStorageTypeDefault, and the next, which is flagged by | |
| // g++. | |
| template <typename T> struct is_cl_initializer { | |
| static constexpr bool value = false; | |
| }; | |
| template <typename T> struct is_cl_initializer<cl::initializer<T>> { | |
| static constexpr bool value = true; | |
| }; | |
| template <typename Ty, typename T, typename... A> | |
| typename std::enable_if<!is_cl_initializer<T>::value, Ty>::type | |
| flagInitOrStorageTypeDefault(T &&, A &&... Other) { | |
| return flagInitOrStorageTypeDefault<Ty>(std::forward<A>(Other)...); | |
| } | |
| } // end of anonymous namespace | |
| void ClFlags::resetClFlags() { | |
| #define X(Name, Type, ClType, ...) \ | |
| Name = flagInitOrStorageTypeDefault< \ | |
| detail::cl_type_traits<Type, cl_detail::ClType>::storage_type>( \ | |
| __VA_ARGS__); | |
| COMMAND_LINE_FLAGS | |
| #undef X | |
| } | |
| namespace { | |
| // toSetterParam is template magic that is needed to convert between (llvm::)cl | |
| // objects and the arguments to ClFlags' setters. ToSetterParam is a traits | |
| // object that we need in order for the multiple specializations to | |
| // toSetterParam to agree on their return type. | |
| template <typename T> struct ToSetterParam { using ReturnType = const T &; }; | |
| template <> struct ToSetterParam<cl::list<Ice::VerboseItem>> { | |
| using ReturnType = Ice::VerboseMask; | |
| }; | |
| template <> struct ToSetterParam<cl::list<std::string>> { | |
| using ReturnType = std::vector<std::string>; | |
| }; | |
| template <typename T> | |
| typename ToSetterParam<T>::ReturnType toSetterParam(const T &Param) { | |
| return Param; | |
| } | |
| template <> | |
| ToSetterParam<cl::list<Ice::VerboseItem>>::ReturnType | |
| toSetterParam(const cl::list<Ice::VerboseItem> &Param) { | |
| Ice::VerboseMask VMask = Ice::IceV_None; | |
| // Don't generate verbose messages if routines to dump messages are not | |
| // available. | |
| if (BuildDefs::dump()) { | |
| for (unsigned i = 0; i != Param.size(); ++i) | |
| VMask |= Param[i]; | |
| } | |
| return VMask; | |
| } | |
| template <> | |
| ToSetterParam<cl::list<std::string>>::ReturnType | |
| toSetterParam(const cl::list<std::string> &Param) { | |
| return *&Param; | |
| } | |
| } // end of anonymous namespace | |
| void ClFlags::getParsedClFlags(ClFlags &OutFlags) { | |
| #define X(Name, Type, ClType, ...) OutFlags.set##Name(toSetterParam(Name##Obj)); | |
| COMMAND_LINE_FLAGS | |
| #undef X | |
| // If any value needs a non-trivial parsed value, set it below. | |
| OutFlags.setAllowExternDefinedSymbols(AllowExternDefinedSymbolsObj || | |
| DisableInternalObj); | |
| OutFlags.setDisableHybridAssembly(DisableHybridAssemblyObj || | |
| (OutFileTypeObj != Ice::FT_Iasm)); | |
| OutFlags.ForceO2.init(OutFlags.getForceO2String()); | |
| OutFlags.SplitInsts.init(OutFlags.getSplitInstString()); | |
| OutFlags.TestStatus.init(OutFlags.getTestStatusString()); | |
| OutFlags.TimingFocus.init(OutFlags.getTimingFocusOnString()); | |
| OutFlags.TranslateOnly.init(OutFlags.getTranslateOnlyString()); | |
| OutFlags.VerboseFocus.init(OutFlags.getVerboseFocusOnString()); | |
| } | |
| } // end of namespace Ice |