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