Commit 732e0aa9 authored by Chris Bieneman's avatar Chris Bieneman
Browse files

Defining a new API for debug options that doesn't rely on static global cl::opts.

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

llvm-svn: 219854
parent de4de39c
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -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;
+9 −0
Original line number Diff line number Diff line
@@ -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(); }

+115 −0
Original line number Diff line number Diff line
//===- 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
+1 −0
Original line number Diff line number Diff line
@@ -40,6 +40,7 @@ add_llvm_library(LLVMSupport
  MemoryBuffer.cpp
  MemoryObject.cpp
  MD5.cpp
  Options.cpp
  PluginLoader.cpp
  PrettyStackTrace.cpp
  RandomNumberGenerator.cpp
+9 −3
Original line number Diff line number Diff line
@@ -113,10 +113,16 @@ void Option::addArgument() {
}

void Option::removeArgument() {
  assert(NextRegistered && "argument never registered");
  assert(RegisteredOptionList == this && "argument is not the last registered");
  if (RegisteredOptionList == this) {
    RegisteredOptionList = NextRegistered;
    MarkOptionsChanged();
    return;
  }
  Option *O = RegisteredOptionList;
  for (; O->NextRegistered != this; O = O->NextRegistered)
    ;
  O->NextRegistered = NextRegistered;
  MarkOptionsChanged();
}

// This collects the different option categories that have been registered.
Loading