Skip to content

Commit 732e0aa

Browse files
author
Chris Bieneman
committed
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
1 parent de4de39 commit 732e0aa

File tree

7 files changed

+193
-12
lines changed

7 files changed

+193
-12
lines changed

llvm/include/llvm/IR/LLVMContext.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "llvm-c/Core.h"
1919
#include "llvm/Support/CBindingWrapping.h"
2020
#include "llvm/Support/Compiler.h"
21+
#include "llvm/Support/Options.h"
2122

2223
namespace llvm {
2324

@@ -163,6 +164,14 @@ class LLVMContext {
163164
void emitError(const Instruction *I, const Twine &ErrorStr);
164165
void emitError(const Twine &ErrorStr);
165166

167+
/// \brief Query for a debug option's value.
168+
///
169+
/// This function returns typed data populated from command line parsing.
170+
template <typename ValT, typename Base, ValT(Base::*Mem)>
171+
ValT getOption() const {
172+
return OptionRegistry::instance().template get<ValT, Base, Mem>();
173+
}
174+
166175
private:
167176
LLVMContext(LLVMContext&) LLVM_DELETED_FUNCTION;
168177
void operator=(LLVMContext&) LLVM_DELETED_FUNCTION;

llvm/include/llvm/PassSupport.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,15 @@ class TargetMachine;
8282
CALL_ONCE_INITIALIZATION(initialize##passName##PassOnce) \
8383
}
8484

85+
#define INITIALIZE_PASS_WITH_OPTIONS(PassName, Arg, Name, Cfg, Analysis) \
86+
INITIALIZE_PASS_BEGIN(PassName, Arg, Name, Cfg, Analysis) \
87+
PassName::registerOptions(); \
88+
INITIALIZE_PASS_END(PassName, Arg, Name, Cfg, Analysis)
89+
90+
#define INITIALIZE_PASS_WITH_OPTIONS_BEGIN(PassName, Arg, Name, Cfg, Analysis) \
91+
INITIALIZE_PASS_BEGIN(PassName, Arg, Name, Cfg, Analysis) \
92+
PassName::registerOptions(); \
93+
8594
template<typename PassName>
8695
Pass *callDefaultCtor() { return new PassName(); }
8796

llvm/include/llvm/Support/Options.h

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
//===- llvm/Support/Options.h - Debug options support -----------*- C++ -*-===//
2+
//
3+
// The LLVM Compiler Infrastructure
4+
//
5+
// This file is distributed under the University of Illinois Open Source
6+
// License. See LICENSE.TXT for details.
7+
//
8+
//===----------------------------------------------------------------------===//
9+
/// \file
10+
/// This file declares helper objects for defining debug options that can be
11+
/// configured via the command line. The new API currently builds on the cl::opt
12+
/// API, but does not require the use of static globals.
13+
///
14+
/// With this API options are registered during initialization. For passes, this
15+
/// happens during pass initialization. Passes with options will call a static
16+
/// registerOptions method during initialization that registers options with the
17+
/// OptionRegistry. An example implementation of registerOptions is:
18+
///
19+
/// static void registerOptions() {
20+
/// OptionRegistry::registerOption<bool, Scalarizer,
21+
/// &Scalarizer::ScalarizeLoadStore>(
22+
/// "scalarize-load-store",
23+
/// "Allow the scalarizer pass to scalarize loads and store", false);
24+
/// }
25+
///
26+
/// When reading data for options the interface is via the LLVMContext. Option
27+
/// data for passes should be read from the context during doInitialization. An
28+
/// example of reading the above option would be:
29+
///
30+
/// ScalarizeLoadStore =
31+
/// M.getContext().template getOption<bool,
32+
/// Scalarizer,
33+
/// &Scalarizer::ScalarizeLoadStore>();
34+
///
35+
//===----------------------------------------------------------------------===//
36+
37+
#include "llvm/ADT/DenseMap.h"
38+
#include "llvm/Support/CommandLine.h"
39+
40+
namespace llvm {
41+
42+
namespace detail {
43+
44+
// Options are keyed of the unique address of a static character synthesized
45+
// based on template arguments.
46+
template <typename ValT, typename Base, ValT(Base::*Mem)> class OptionKey {
47+
public:
48+
static char ID;
49+
};
50+
51+
template <typename ValT, typename Base, ValT(Base::*Mem)>
52+
char OptionKey<ValT, Base, Mem>::ID = 0;
53+
54+
} // namespace detail
55+
56+
/// \brief Singleton class used to register debug options.
57+
///
58+
/// The OptionRegistry is responsible for managing lifetimes of the options and
59+
/// provides interfaces for option registration and reading values from options.
60+
/// This object is a singleton, only one instance should ever exist so that all
61+
/// options are registered in teh same place.
62+
class OptionRegistry {
63+
private:
64+
DenseMap<void *, cl::Option *> Options;
65+
66+
/// \brief Adds a cl::Option to the registry.
67+
///
68+
/// \param Key unique key for option
69+
/// \param O option to map to \p Key
70+
///
71+
/// Allocated cl::Options are owened by the OptionRegistry and are deallocated
72+
/// on destruction or removal
73+
void addOption(void *Key, cl::Option *O);
74+
75+
public:
76+
~OptionRegistry();
77+
OptionRegistry() {}
78+
79+
/// \brief Returns a reference to the singleton instance.
80+
static OptionRegistry &instance();
81+
82+
/// \brief Registers an option with the OptionRegistry singleton.
83+
///
84+
/// \param ValT type of the option's data
85+
/// \param Base class used to key the option
86+
/// \param Mem member of \p Base used for keying the option
87+
///
88+
/// Options are keyed off the template parameters to generate unique static
89+
/// characters. The template parameters are (1) the type of the data the
90+
/// option stores (\p ValT), the class that will read the option (\p Base),
91+
/// and the memeber that the class will store the data into (\p Mem).
92+
template <typename ValT, typename Base, ValT(Base::*Mem)>
93+
static void registerOption(const char *ArgStr, const char *Desc,
94+
const ValT &InitValue) {
95+
cl::opt<ValT> *Option = new cl::opt<ValT>(ArgStr, cl::desc(Desc),
96+
cl::Hidden, cl::init(InitValue));
97+
instance().addOption(&detail::OptionKey<ValT, Base, Mem>::ID, Option);
98+
}
99+
100+
/// \brief Returns the value of the option.
101+
///
102+
/// \param ValT type of the option's data
103+
/// \param Base class used to key the option
104+
/// \param Mem member of \p Base used for keying the option
105+
///
106+
/// Reads option values based on the key generated by the template parameters.
107+
/// Keying for get() is the same as keying for registerOption.
108+
template <typename ValT, typename Base, ValT(Base::*Mem)> ValT get() const {
109+
auto It = Options.find(&detail::OptionKey<ValT, Base, Mem>::ID);
110+
assert(It != Options.end() && "Option not in OptionRegistry");
111+
return *(cl::opt<ValT> *)It->second;
112+
}
113+
};
114+
115+
} // namespace llvm

llvm/lib/Support/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ add_llvm_library(LLVMSupport
4040
MemoryBuffer.cpp
4141
MemoryObject.cpp
4242
MD5.cpp
43+
Options.cpp
4344
PluginLoader.cpp
4445
PrettyStackTrace.cpp
4546
RandomNumberGenerator.cpp

llvm/lib/Support/CommandLine.cpp

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -113,9 +113,15 @@ void Option::addArgument() {
113113
}
114114

115115
void Option::removeArgument() {
116-
assert(NextRegistered && "argument never registered");
117-
assert(RegisteredOptionList == this && "argument is not the last registered");
118-
RegisteredOptionList = NextRegistered;
116+
if (RegisteredOptionList == this) {
117+
RegisteredOptionList = NextRegistered;
118+
MarkOptionsChanged();
119+
return;
120+
}
121+
Option *O = RegisteredOptionList;
122+
for (; O->NextRegistered != this; O = O->NextRegistered)
123+
;
124+
O->NextRegistered = NextRegistered;
119125
MarkOptionsChanged();
120126
}
121127

llvm/lib/Support/Options.cpp

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
//===- llvm/Support/Options.cpp - Debug options support ---------*- C++ -*-===//
2+
//
3+
// The LLVM Compiler Infrastructure
4+
//
5+
// This file is distributed under the University of Illinois Open Source
6+
// License. See LICENSE.TXT for details.
7+
//
8+
//===----------------------------------------------------------------------===//
9+
//
10+
// This file implements the helper objects for defining debug options using the
11+
// new API built on cl::opt, but not requiring the use of static globals.
12+
//
13+
//===----------------------------------------------------------------------===//
14+
15+
#include "llvm/Support/Options.h"
16+
#include "llvm/Support/ManagedStatic.h"
17+
18+
using namespace llvm;
19+
20+
OptionRegistry::~OptionRegistry() {
21+
for (auto IT = Options.begin(); IT != Options.end(); ++IT)
22+
delete IT->second;
23+
}
24+
25+
void OptionRegistry::addOption(void *Key, cl::Option *O) {
26+
assert(Options.find(Key) == Options.end() &&
27+
"Argument with this key already registerd");
28+
Options.insert(std::make_pair(Key, O));
29+
}
30+
31+
static ManagedStatic<OptionRegistry> OR;
32+
33+
OptionRegistry &OptionRegistry::instance() { return *OR; }

llvm/lib/Transforms/Scalar/Scalarizer.cpp

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,16 @@ class Scalarizer : public FunctionPass,
150150
bool visitLoadInst(LoadInst &);
151151
bool visitStoreInst(StoreInst &);
152152

153+
static void registerOptions() {
154+
// This is disabled by default because having separate loads and stores
155+
// makes it more likely that the -combiner-alias-analysis limits will be
156+
// reached.
157+
OptionRegistry::registerOption<bool, Scalarizer,
158+
&Scalarizer::ScalarizeLoadStore>(
159+
"scalarize-load-store",
160+
"Allow the scalarizer pass to scalarize loads and store", false);
161+
}
162+
153163
private:
154164
Scatterer scatter(Instruction *, Value *);
155165
void gather(Instruction *, const ValueVector &);
@@ -164,19 +174,14 @@ class Scalarizer : public FunctionPass,
164174
GatherList Gathered;
165175
unsigned ParallelLoopAccessMDKind;
166176
const DataLayout *DL;
177+
bool ScalarizeLoadStore;
167178
};
168179

169180
char Scalarizer::ID = 0;
170181
} // end anonymous namespace
171182

172-
// This is disabled by default because having separate loads and stores makes
173-
// it more likely that the -combiner-alias-analysis limits will be reached.
174-
static cl::opt<bool> ScalarizeLoadStore
175-
("scalarize-load-store", cl::Hidden, cl::init(false),
176-
cl::desc("Allow the scalarizer pass to scalarize loads and store"));
177-
178-
INITIALIZE_PASS(Scalarizer, "scalarizer", "Scalarize vector operations",
179-
false, false)
183+
INITIALIZE_PASS_WITH_OPTIONS(Scalarizer, "scalarizer",
184+
"Scalarize vector operations", false, false);
180185

181186
Scatterer::Scatterer(BasicBlock *bb, BasicBlock::iterator bbi, Value *v,
182187
ValueVector *cachePtr)
@@ -236,7 +241,10 @@ Value *Scatterer::operator[](unsigned I) {
236241

237242
bool Scalarizer::doInitialization(Module &M) {
238243
ParallelLoopAccessMDKind =
239-
M.getContext().getMDKindID("llvm.mem.parallel_loop_access");
244+
M.getContext().getMDKindID("llvm.mem.parallel_loop_access");
245+
ScalarizeLoadStore =
246+
M.getContext()
247+
.template getOption<bool, Scalarizer, &Scalarizer::ScalarizeLoadStore>();
240248
return false;
241249
}
242250

0 commit comments

Comments
 (0)