Home | History | Annotate | Download | only in src
      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