Defining a new API for debug options that doesn't rely on static global cl::opts.
authorChris Bieneman <beanz@apple.com>
Wed, 15 Oct 2014 21:54:35 +0000 (21:54 +0000)
committerChris Bieneman <beanz@apple.com>
Wed, 15 Oct 2014 21:54:35 +0000 (21:54 +0000)
Summary:
This is based on the discussions from the LLVMDev thread:
http://lists.cs.uiuc.edu/pipermail/llvmdev/2014-August/075886.html

Reviewers: chandlerc

Reviewed By: chandlerc

Subscribers: llvm-commits

Differential Revision: http://reviews.llvm.org/D5389

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@219854 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm/IR/LLVMContext.h
include/llvm/PassSupport.h
include/llvm/Support/Options.h [new file with mode: 0644]
lib/Support/CMakeLists.txt
lib/Support/CommandLine.cpp
lib/Support/Options.cpp [new file with mode: 0644]
lib/Transforms/Scalar/Scalarizer.cpp

index cdd2150..672bf15 100644 (file)
@@ -18,6 +18,7 @@
 #include "llvm-c/Core.h"
 #include "llvm/Support/CBindingWrapping.h"
 #include "llvm/Support/Compiler.h"
+#include "llvm/Support/Options.h"
 
 namespace llvm {
 
@@ -163,6 +164,14 @@ public:
   void emitError(const Instruction *I, const Twine &ErrorStr);
   void emitError(const Twine &ErrorStr);
 
+  /// \brief Query for a debug option's value.
+  ///
+  /// This function returns typed data populated from command line parsing.
+  template <typename ValT, typename Base, ValT(Base::*Mem)>
+  ValT getOption() const {
+    return OptionRegistry::instance().template get<ValT, Base, Mem>();
+  }
+
 private:
   LLVMContext(LLVMContext&) LLVM_DELETED_FUNCTION;
   void operator=(LLVMContext&) LLVM_DELETED_FUNCTION;
index 449bc92..6cb6516 100644 (file)
@@ -82,6 +82,15 @@ class TargetMachine;
     CALL_ONCE_INITIALIZATION(initialize##passName##PassOnce) \
   }
 
+#define INITIALIZE_PASS_WITH_OPTIONS(PassName, Arg, Name, Cfg, Analysis) \
+  INITIALIZE_PASS_BEGIN(PassName, Arg, Name, Cfg, Analysis) \
+  PassName::registerOptions(); \
+  INITIALIZE_PASS_END(PassName, Arg, Name, Cfg, Analysis)
+
+#define INITIALIZE_PASS_WITH_OPTIONS_BEGIN(PassName, Arg, Name, Cfg, Analysis) \
+  INITIALIZE_PASS_BEGIN(PassName, Arg, Name, Cfg, Analysis) \
+  PassName::registerOptions(); \
+
 template<typename PassName>
 Pass *callDefaultCtor() { return new PassName(); }
 
diff --git a/include/llvm/Support/Options.h b/include/llvm/Support/Options.h
new file mode 100644 (file)
index 0000000..047d840
--- /dev/null
@@ -0,0 +1,115 @@
+//===- llvm/Support/Options.h - Debug options support -----------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+/// \file
+/// This file declares helper objects for defining debug options that can be
+/// configured via the command line. The new API currently builds on the cl::opt
+/// API, but does not require the use of static globals.
+///
+/// With this API options are registered during initialization. For passes, this
+/// happens during pass initialization. Passes with options will call a static
+/// registerOptions method during initialization that registers options with the
+/// OptionRegistry. An example implementation of registerOptions is:
+///
+/// static void registerOptions() {
+///   OptionRegistry::registerOption<bool, Scalarizer,
+///                                &Scalarizer::ScalarizeLoadStore>(
+///       "scalarize-load-store",
+///       "Allow the scalarizer pass to scalarize loads and store", false);
+/// }
+///
+/// When reading data for options the interface is via the LLVMContext. Option
+/// data for passes should be read from the context during doInitialization. An
+/// example of reading the above option would be:
+///
+/// ScalarizeLoadStore =
+///   M.getContext().template getOption<bool,
+///                                     Scalarizer,
+///                                     &Scalarizer::ScalarizeLoadStore>();
+///
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/Support/CommandLine.h"
+
+namespace llvm {
+
+namespace detail {
+
+// Options are keyed of the unique address of a static character synthesized
+// based on template arguments.
+template <typename ValT, typename Base, ValT(Base::*Mem)> class OptionKey {
+public:
+  static char ID;
+};
+
+template <typename ValT, typename Base, ValT(Base::*Mem)>
+char OptionKey<ValT, Base, Mem>::ID = 0;
+
+} // namespace detail
+
+/// \brief Singleton class used to register debug options.
+///
+/// The OptionRegistry is responsible for managing lifetimes of the options and
+/// provides interfaces for option registration and reading values from options.
+/// This object is a singleton, only one instance should ever exist so that all
+/// options are registered in teh same place.
+class OptionRegistry {
+private:
+  DenseMap<void *, cl::Option *> Options;
+
+  /// \brief Adds a cl::Option to the registry.
+  ///
+  /// \param Key unique key for option
+  /// \param O option to map to \p Key
+  ///
+  /// Allocated cl::Options are owened by the OptionRegistry and are deallocated
+  /// on destruction or removal
+  void addOption(void *Key, cl::Option *O);
+
+public:
+  ~OptionRegistry();
+  OptionRegistry() {}
+
+  /// \brief Returns a reference to the singleton instance.
+  static OptionRegistry &instance();
+
+  /// \brief Registers an option with the OptionRegistry singleton.
+  ///
+  /// \param ValT type of the option's data
+  /// \param Base class used to key the option
+  /// \param Mem member of \p Base used for keying the option
+  ///
+  /// Options are keyed off the template parameters to generate unique static
+  /// characters. The template parameters are (1) the type of the data the
+  /// option stores (\p ValT), the class that will read the option (\p Base),
+  /// and the memeber that the class will store the data into (\p Mem).
+  template <typename ValT, typename Base, ValT(Base::*Mem)>
+  static void registerOption(const char *ArgStr, const char *Desc,
+                             const ValT &InitValue) {
+    cl::opt<ValT> *Option = new cl::opt<ValT>(ArgStr, cl::desc(Desc),
+                                              cl::Hidden, cl::init(InitValue));
+    instance().addOption(&detail::OptionKey<ValT, Base, Mem>::ID, Option);
+  }
+
+  /// \brief Returns the value of the option.
+  ///
+  /// \param ValT type of the option's data
+  /// \param Base class used to key the option
+  /// \param Mem member of \p Base used for keying the option
+  ///
+  /// Reads option values based on the key generated by the template parameters.
+  /// Keying for get() is the same as keying for registerOption.
+  template <typename ValT, typename Base, ValT(Base::*Mem)> ValT get() const {
+    auto It = Options.find(&detail::OptionKey<ValT, Base, Mem>::ID);
+    assert(It != Options.end() && "Option not in OptionRegistry");
+    return *(cl::opt<ValT> *)It->second;
+  }
+};
+
+} // namespace llvm
index 8ba992a..daed4f1 100644 (file)
@@ -40,6 +40,7 @@ add_llvm_library(LLVMSupport
   MemoryBuffer.cpp
   MemoryObject.cpp
   MD5.cpp
+  Options.cpp
   PluginLoader.cpp
   PrettyStackTrace.cpp
   RandomNumberGenerator.cpp
index 2c5174d..9d5f158 100644 (file)
@@ -113,9 +113,15 @@ void Option::addArgument() {
 }
 
 void Option::removeArgument() {
-  assert(NextRegistered && "argument never registered");
-  assert(RegisteredOptionList == this && "argument is not the last registered");
-  RegisteredOptionList = NextRegistered;
+  if (RegisteredOptionList == this) {
+    RegisteredOptionList = NextRegistered;
+    MarkOptionsChanged();
+    return;
+  }
+  Option *O = RegisteredOptionList;
+  for (; O->NextRegistered != this; O = O->NextRegistered)
+    ;
+  O->NextRegistered = NextRegistered;
   MarkOptionsChanged();
 }
 
diff --git a/lib/Support/Options.cpp b/lib/Support/Options.cpp
new file mode 100644 (file)
index 0000000..7125845
--- /dev/null
@@ -0,0 +1,33 @@
+//===- llvm/Support/Options.cpp - Debug options support ---------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the helper objects for defining debug options using the
+// new API built on cl::opt, but not requiring the use of static globals.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/Options.h"
+#include "llvm/Support/ManagedStatic.h"
+
+using namespace llvm;
+
+OptionRegistry::~OptionRegistry() {
+  for (auto IT = Options.begin(); IT != Options.end(); ++IT)
+    delete IT->second;
+}
+
+void OptionRegistry::addOption(void *Key, cl::Option *O) {
+  assert(Options.find(Key) == Options.end() &&
+         "Argument with this key already registerd");
+  Options.insert(std::make_pair(Key, O));
+}
+
+static ManagedStatic<OptionRegistry> OR;
+
+OptionRegistry &OptionRegistry::instance() { return *OR; }
index 813041a..867289c 100644 (file)
@@ -150,6 +150,16 @@ public:
   bool visitLoadInst(LoadInst &);
   bool visitStoreInst(StoreInst &);
 
+  static void registerOptions() {
+    // This is disabled by default because having separate loads and stores
+    // makes it more likely that the -combiner-alias-analysis limits will be
+    // reached.
+    OptionRegistry::registerOption<bool, Scalarizer,
+                                 &Scalarizer::ScalarizeLoadStore>(
+        "scalarize-load-store",
+        "Allow the scalarizer pass to scalarize loads and store", false);
+  }
+
 private:
   Scatterer scatter(Instruction *, Value *);
   void gather(Instruction *, const ValueVector &);
@@ -164,19 +174,14 @@ private:
   GatherList Gathered;
   unsigned ParallelLoopAccessMDKind;
   const DataLayout *DL;
+  bool ScalarizeLoadStore;
 };
 
 char Scalarizer::ID = 0;
 } // end anonymous namespace
 
-// This is disabled by default because having separate loads and stores makes
-// it more likely that the -combiner-alias-analysis limits will be reached.
-static cl::opt<bool> ScalarizeLoadStore
-  ("scalarize-load-store", cl::Hidden, cl::init(false),
-   cl::desc("Allow the scalarizer pass to scalarize loads and store"));
-
-INITIALIZE_PASS(Scalarizer, "scalarizer", "Scalarize vector operations",
-                false, false)
+INITIALIZE_PASS_WITH_OPTIONS(Scalarizer, "scalarizer",
+                             "Scalarize vector operations", false, false);
 
 Scatterer::Scatterer(BasicBlock *bb, BasicBlock::iterator bbi, Value *v,
                      ValueVector *cachePtr)
@@ -236,7 +241,10 @@ Value *Scatterer::operator[](unsigned I) {
 
 bool Scalarizer::doInitialization(Module &M) {
   ParallelLoopAccessMDKind =
-    M.getContext().getMDKindID("llvm.mem.parallel_loop_access");
+      M.getContext().getMDKindID("llvm.mem.parallel_loop_access");
+  ScalarizeLoadStore =
+      M.getContext()
+          .template getOption<bool, Scalarizer, &Scalarizer::ScalarizeLoadStore>();
   return false;
 }