Skip to content

Commit

Permalink
Defining a new API for debug options that doesn't rely on static glob…
Browse files Browse the repository at this point in the history
…al 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
  • Loading branch information
Chris Bieneman committed Oct 15, 2014
1 parent de4de39 commit 732e0aa
Show file tree
Hide file tree
Showing 7 changed files with 193 additions and 12 deletions.
9 changes: 9 additions & 0 deletions llvm/include/llvm/IR/LLVMContext.h
Expand Up @@ -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 {

Expand Down Expand Up @@ -163,6 +164,14 @@ class LLVMContext {
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;
Expand Down
9 changes: 9 additions & 0 deletions llvm/include/llvm/PassSupport.h
Expand Up @@ -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(); }

Expand Down
115 changes: 115 additions & 0 deletions llvm/include/llvm/Support/Options.h
@@ -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
1 change: 1 addition & 0 deletions llvm/lib/Support/CMakeLists.txt
Expand Up @@ -40,6 +40,7 @@ add_llvm_library(LLVMSupport
MemoryBuffer.cpp
MemoryObject.cpp
MD5.cpp
Options.cpp
PluginLoader.cpp
PrettyStackTrace.cpp
RandomNumberGenerator.cpp
Expand Down
12 changes: 9 additions & 3 deletions llvm/lib/Support/CommandLine.cpp
Expand Up @@ -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();
}

Expand Down
33 changes: 33 additions & 0 deletions llvm/lib/Support/Options.cpp
@@ -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; }
26 changes: 17 additions & 9 deletions llvm/lib/Transforms/Scalar/Scalarizer.cpp
Expand Up @@ -150,6 +150,16 @@ class Scalarizer : public FunctionPass,
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 &);
Expand All @@ -164,19 +174,14 @@ class Scalarizer : public FunctionPass,
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)
Expand Down Expand Up @@ -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;
}

Expand Down

0 comments on commit 732e0aa

Please sign in to comment.