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