Created Ice::Instrumentation base class and accompanying hooks.
Also added a command line flag for AddressSanitizer
BUG=None
R=kschimpf@google.com
Review URL: https://codereview.chromium.org/2042063002 .
diff --git a/Makefile.standalone b/Makefile.standalone
index 38a7bd4..6c40903 100644
--- a/Makefile.standalone
+++ b/Makefile.standalone
@@ -283,6 +283,7 @@
# compile, in the hope of improving parallel build time.
SRCS = \
IceAssemblerARM32.cpp \
+ IceInstrumentation.cpp \
IceInstARM32.cpp \
IceInstMIPS32.cpp \
IceInstX8632.cpp \
diff --git a/src/IceCfg.cpp b/src/IceCfg.cpp
index 8f6a2ff..a113b95 100644
--- a/src/IceCfg.cpp
+++ b/src/IceCfg.cpp
@@ -22,6 +22,7 @@
#include "IceELFObjectWriter.h"
#include "IceGlobalInits.h"
#include "IceInst.h"
+#include "IceInstrumentation.h"
#include "IceInstVarIter.h"
#include "IceLiveness.h"
#include "IceLoopAnalyzer.h"
@@ -238,6 +239,12 @@
if (auto *Var64On32 = llvm::dyn_cast<Variable64On32>(Var))
Var64On32->initHiLo(this);
+ // Instrument the Cfg, e.g. with AddressSanitizer
+ if (!BuildDefs::minimal() && getFlags().getSanitizeAddresses()) {
+ getContext()->instrumentFunc(this);
+ dump("Instrumented CFG");
+ }
+
// The set of translation passes and their order are determined by the
// target.
getTarget()->translate();
diff --git a/src/IceClFlags.def b/src/IceClFlags.def
index 0706e03..7488698 100644
--- a/src/IceClFlags.def
+++ b/src/IceClFlags.def
@@ -257,6 +257,11 @@
X(RepeatRegAlloc, bool, dev_opt_flag, "regalloc-repeat", \
cl::desc("Repeat register allocation until convergence"), cl::init(true)) \
\
+ /* TODO(tlively): Generalize this to handle more sanitizers */ \
+ X(SanitizeAddresses, bool, dev_opt_flag, "fsanitize-address", \
+ cl::desc("Instrument compiled code with Address Sanitizer"), \
+ cl::init(false)) \
+ \
X(ShouldDoNopInsertion, bool, dev_opt_flag, "nop-insertion", \
cl::desc("Randomly insert NOPs"), cl::init(false)) \
\
@@ -357,6 +362,7 @@
X(WasmBoundsCheck, bool, dev_opt_flag, "wasm-bounds-check", \
cl::desc("Add bounds checking code in WASM frontend"), \
cl::init(true))
+
//#define X(Name, Type, ClType, ...)
} // end of namespace Ice
diff --git a/src/IceCompileServer.cpp b/src/IceCompileServer.cpp
index adb4102..19b19f8 100644
--- a/src/IceCompileServer.cpp
+++ b/src/IceCompileServer.cpp
@@ -241,6 +241,13 @@
}
Ctx.reset(new GlobalContext(Ls.get(), Os.get(), Ls.get(), ELFStr.get()));
+
+ // TODO(tlively): Make this instantiate an instrumentation subclass
+ if (!BuildDefs::minimal() && getFlags().getSanitizeAddresses()) {
+ std::unique_ptr<Instrumentation> Instr(new Instrumentation(Ctx.get()));
+ Ctx->setInstrumentation(std::move(Instr));
+ }
+
if (getFlags().getNumTranslationThreads() != 0) {
std::thread CompileThread([this, &Flags, &InputStream]() {
Ctx->initParserThread();
diff --git a/src/IceGlobalContext.cpp b/src/IceGlobalContext.cpp
index 058825b..0d53127 100644
--- a/src/IceGlobalContext.cpp
+++ b/src/IceGlobalContext.cpp
@@ -486,6 +486,10 @@
RandomShuffle(Globals.begin(), Globals.end(),
[&RNG](int N) { return (uint32_t)RNG.next(N); });
}
+
+ if (!BuildDefs::minimal() && Instrumentor)
+ Instrumentor->instrumentGlobals();
+
DataLowering->lowerGlobals(Globals, SectionSuffix);
if (ProfileBlockInfos.empty() && DisposeGlobalVariablesAfterLowering) {
Globals.clearAndPurge();
diff --git a/src/IceGlobalContext.h b/src/IceGlobalContext.h
index c216f82..2d60f48 100644
--- a/src/IceGlobalContext.h
+++ b/src/IceGlobalContext.h
@@ -18,6 +18,7 @@
#include "IceDefs.h"
#include "IceClFlags.h"
+#include "IceInstrumentation.h"
#include "IceIntrinsics.h"
#include "IceRNG.h"
#include "IceStringPool.h"
@@ -44,6 +45,7 @@
class ConstantPool;
class EmitterWorkItem;
class FuncSigType;
+class Instrumentation;
// Runtime helper function IDs
@@ -426,6 +428,17 @@
void waitForWorkerThreads();
+ /// sets the instrumentation object to use.
+ void setInstrumentation(std::unique_ptr<Instrumentation> Instr) {
+ if (!BuildDefs::minimal())
+ Instrumentor = std::move(Instr);
+ }
+
+ void instrumentFunc(Cfg *Func) {
+ if (!BuildDefs::minimal() && Instrumentor)
+ Instrumentor->instrumentFunc(Func);
+ }
+
/// Translation thread startup routine.
void translateFunctionsWrapper(ThreadContext *MyTLS) {
ICE_TLS_SET_FIELD(TLS, MyTLS);
@@ -552,6 +565,9 @@
/// program global variables) until the first code WorkItem is seen.
// TODO(jpp): move to EmitterContext.
bool HasSeenCode = false;
+ // If Instrumentor is not empty then it will be used to instrument globals and
+ // CFGs.
+ std::unique_ptr<Instrumentation> Instrumentor = nullptr;
// TODO(jpp): move to EmitterContext.
VariableDeclaration *ProfileBlockInfoVarDecl = nullptr;
std::vector<VariableDeclaration *> ProfileBlockInfos;
diff --git a/src/IceInstrumentation.cpp b/src/IceInstrumentation.cpp
new file mode 100644
index 0000000..383e151
--- /dev/null
+++ b/src/IceInstrumentation.cpp
@@ -0,0 +1,108 @@
+//===- subzero/src/IceInstrumentation.cpp - ICE instrumentation framework -===//
+//
+// The Subzero Code Generator
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Implements the Ice::Instrumentation class.
+///
+/// Subclasses can override particular instrumentation methods to specify how
+/// the the target program should be instrumented.
+///
+//===----------------------------------------------------------------------===//
+
+#include "IceInstrumentation.h"
+
+#include "IceCfg.h"
+#include "IceInst.h"
+#include "IceTargetLowering.h"
+
+namespace Ice {
+
+// Iterate through the instructions in the given CFG and instrument each one.
+// Also instrument the beginning of the function.
+void Instrumentation::instrumentFunc(Cfg *Func) {
+ assert(Func);
+ assert(!Func->getNodes().empty());
+
+ LoweringContext Context;
+ Context.init(Func->getNodes().front());
+ instrumentFuncStart(Context);
+ for (CfgNode *Node : Func->getNodes()) {
+ Context.init(Node);
+ while (!Context.atEnd()) {
+ instrumentInst(Context);
+ // go to next undeleted instruction
+ Context.advanceCur();
+ Context.advanceNext();
+ }
+ }
+}
+
+void Instrumentation::instrumentInst(LoweringContext &Context) {
+ assert(!Context.atEnd());
+ Inst *Instr = iteratorToInst(Context.getCur());
+ switch (Instr->getKind()) {
+ case Inst::Alloca:
+ instrumentAlloca(Context, llvm::cast<InstAlloca>(Instr));
+ break;
+ case Inst::Arithmetic:
+ instrumentArithmetic(Context, llvm::cast<InstArithmetic>(Instr));
+ break;
+ case Inst::Br:
+ instrumentBr(Context, llvm::cast<InstBr>(Instr));
+ break;
+ case Inst::Call:
+ instrumentCall(Context, llvm::cast<InstCall>(Instr));
+ break;
+ case Inst::Cast:
+ instrumentCast(Context, llvm::cast<InstCast>(Instr));
+ break;
+ case Inst::ExtractElement:
+ instrumentExtractElement(Context, llvm::cast<InstExtractElement>(Instr));
+ break;
+ case Inst::Fcmp:
+ instrumentFcmp(Context, llvm::cast<InstFcmp>(Instr));
+ break;
+ case Inst::Icmp:
+ instrumentIcmp(Context, llvm::cast<InstIcmp>(Instr));
+ break;
+ case Inst::InsertElement:
+ instrumentInsertElement(Context, llvm::cast<InstInsertElement>(Instr));
+ break;
+ case Inst::IntrinsicCall:
+ instrumentIntrinsicCall(Context, llvm::cast<InstIntrinsicCall>(Instr));
+ break;
+ case Inst::Load:
+ instrumentLoad(Context, llvm::cast<InstLoad>(Instr));
+ break;
+ case Inst::Phi:
+ instrumentPhi(Context, llvm::cast<InstPhi>(Instr));
+ break;
+ case Inst::Ret:
+ instrumentRet(Context, llvm::cast<InstRet>(Instr));
+ break;
+ case Inst::Select:
+ instrumentSelect(Context, llvm::cast<InstSelect>(Instr));
+ break;
+ case Inst::Store:
+ instrumentStore(Context, llvm::cast<InstStore>(Instr));
+ break;
+ case Inst::Switch:
+ instrumentSwitch(Context, llvm::cast<InstSwitch>(Instr));
+ break;
+ case Inst::Unreachable:
+ instrumentUnreachable(Context, llvm::cast<InstUnreachable>(Instr));
+ break;
+ default:
+ // Only instrument high-level ICE instructions
+ assert(false && "Instrumentation encountered an unexpected instruction");
+ break;
+ }
+}
+
+} // end of namespace Ice
diff --git a/src/IceInstrumentation.h b/src/IceInstrumentation.h
new file mode 100644
index 0000000..abd5d08
--- /dev/null
+++ b/src/IceInstrumentation.h
@@ -0,0 +1,147 @@
+//===- subzero/src/IceInstrumentation.h - ICE instrumentation ---*- C++ -*-===//
+//
+// The Subzero Code Generator
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Declares the Ice::Instrumentation class.
+///
+/// Instrumentation is an abstract class used to drive the instrumentation
+/// process for tools such as AddressSanitizer and MemorySanitizer. It uses a
+/// LoweringContext to enable the insertion of new instructions into a given
+/// Cfg. Although Instrumentation is an abstract class, each of its virtual
+/// functions has a trivial default implementation to make subclasses more
+/// succinct.
+///
+/// If instrumentation is required by the command line arguments, a single
+/// Instrumentation subclass is instantiated and installed in the
+/// GlobalContext. If multiple types of instrumentation are requested, a single
+/// subclass is still responsible for driving the instrumentation, but it can
+/// use other Instrumentation subclasses however it needs to.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef SUBZERO_SRC_ICEINSTRUMENTATION_H
+#define SUBZERO_SRC_ICEINSTRUMENTATION_H
+
+#include "IceDefs.h"
+
+namespace Ice {
+
+class LoweringContext;
+
+class Instrumentation {
+ Instrumentation() = delete;
+ Instrumentation(const Instrumentation &) = delete;
+ Instrumentation &operator=(const Instrumentation &) = delete;
+
+public:
+ Instrumentation(GlobalContext *Ctx) : Ctx(Ctx) {}
+ virtual void instrumentGlobals() {};
+ void instrumentFunc(Cfg *Func);
+
+private:
+ void instrumentInst(LoweringContext &Context);
+ virtual void instrumentFuncStart(LoweringContext &Context) {
+ (void) Context;
+ }
+ virtual void instrumentAlloca(LoweringContext &Context,
+ const class InstAlloca *Instr) {
+ (void) Context;
+ (void) Instr;
+ }
+ virtual void instrumentArithmetic(LoweringContext &Context,
+ const class InstArithmetic *Instr) {
+ (void) Context;
+ (void) Instr;
+ }
+ virtual void instrumentBr(LoweringContext &Context,
+ const class InstBr *Instr) {
+ (void) Context;
+ (void) Instr;
+ }
+ virtual void instrumentCall(LoweringContext &Context,
+ const class InstCall *Instr) {
+ (void) Context;
+ (void) Instr;
+ }
+ virtual void instrumentCast(LoweringContext &Context,
+ const class InstCast *Instr) {
+ (void) Context;
+ (void) Instr;
+ }
+ virtual void instrumentExtractElement(LoweringContext &Context,
+ const class InstExtractElement *Instr) {
+ (void) Context;
+ (void) Instr;
+ }
+ virtual void instrumentFcmp(LoweringContext &Context,
+ const class InstFcmp *Instr) {
+ (void) Context;
+ (void) Instr;
+ }
+ virtual void instrumentIcmp(LoweringContext &Context,
+ const class InstIcmp *Instr) {
+ (void) Context;
+ (void) Instr;
+ }
+ virtual void instrumentInsertElement(LoweringContext &Context,
+ const class InstInsertElement *Instr) {
+ (void) Context;
+ (void) Instr;
+ }
+ virtual void instrumentIntrinsicCall(LoweringContext &Context,
+ const class InstIntrinsicCall *Instr) {
+ (void) Context;
+ (void) Instr;
+ }
+ virtual void instrumentLoad(LoweringContext &Context,
+ const class InstLoad *Instr) {
+ (void) Context;
+ (void) Instr;
+ }
+ virtual void instrumentPhi(LoweringContext &Context,
+ const class InstPhi *Instr) {
+ (void) Context;
+ (void) Instr;
+ }
+ virtual void instrumentRet(LoweringContext &Context,
+ const class InstRet *Instr) {
+ (void) Context;
+ (void) Instr;
+ }
+ virtual void instrumentSelect(LoweringContext &Context,
+ const class InstSelect *Instr) {
+ (void) Context;
+ (void) Instr;
+ }
+ virtual void instrumentStore(LoweringContext &Context,
+ const class InstStore *Instr) {
+ (void) Context;
+ (void) Instr;
+ }
+ virtual void instrumentSwitch(LoweringContext &Context,
+ const class InstSwitch *Instr) {
+ (void) Context;
+ (void) Instr;
+ }
+ virtual void instrumentUnreachable(LoweringContext &Context,
+ const class InstUnreachable *Instr) {
+ (void) Context;
+ (void) Instr;
+ }
+ virtual void instrumentLocalVars(Cfg *Func) {
+ (void) Func;
+ }
+
+protected:
+ GlobalContext *Ctx;
+};
+
+} // end of namespace Ice
+
+#endif // SUBZERO_SRC_ICEINSTRUMENTATION_H