|  | //===- 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 |