Adding tests for the Intel JIT event listener's MCJIT support.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@168459 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt
index d444473e..144e8ec 100644
--- a/tools/CMakeLists.txt
+++ b/tools/CMakeLists.txt
@@ -31,6 +31,9 @@
 add_subdirectory(llvm-readobj)
 add_subdirectory(llvm-rtdyld)
 add_subdirectory(llvm-dwarfdump)
+if( LLVM_USE_INTEL_JITEVENTS )
+  add_subdirectory(llvm-jitlistener)
+endif( LLVM_USE_INTEL_JITEVENTS )
 
 add_subdirectory(bugpoint)
 add_subdirectory(bugpoint-passes)
diff --git a/tools/LLVMBuild.txt b/tools/LLVMBuild.txt
index 6416479..25aa177 100644
--- a/tools/LLVMBuild.txt
+++ b/tools/LLVMBuild.txt
@@ -16,7 +16,7 @@
 ;===------------------------------------------------------------------------===;
 
 [common]
-subdirectories = bugpoint llc lli llvm-ar llvm-as llvm-bcanalyzer llvm-cov llvm-diff llvm-dis llvm-dwarfdump llvm-extract llvm-link llvm-mc llvm-nm llvm-objdump llvm-prof llvm-ranlib llvm-rtdyld llvm-size macho-dump opt llvm-mcmarkup
+subdirectories = bugpoint llc lli llvm-ar llvm-as llvm-bcanalyzer llvm-cov llvm-diff llvm-dis llvm-dwarfdump llvm-extract llvm-jitlistener llvm-link llvm-mc llvm-nm llvm-objdump llvm-prof llvm-ranlib llvm-rtdyld llvm-size macho-dump opt llvm-mcmarkup
 
 [component_0]
 type = Group
diff --git a/tools/Makefile b/tools/Makefile
index 7c273a2..7872267 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -33,7 +33,7 @@
                  lli llvm-extract llvm-mc \
                  bugpoint llvm-bcanalyzer \
                  llvm-diff macho-dump llvm-objdump llvm-readobj \
-	         llvm-rtdyld llvm-dwarfdump llvm-cov \
+	         llvm-rtdyld llvm-dwarfdump llvm-cov llvm-jitlistener \
 	         llvm-size llvm-stress llvm-mcmarkup \
 	         llvm-symbolizer
 
diff --git a/tools/llvm-jitlistener/CMakeLists.txt b/tools/llvm-jitlistener/CMakeLists.txt
new file mode 100644
index 0000000..57a4a0c
--- /dev/null
+++ b/tools/llvm-jitlistener/CMakeLists.txt
@@ -0,0 +1,20 @@
+# This tool is excluded from the CMake build if Intel JIT events are disabled.

+

+link_directories( ${LLVM_INTEL_JITEVENTS_LIBDIR} )

+include_directories( ${LLVM_INTEL_JITEVENTS_INCDIR} )

+

+set(LLVM_LINK_COMPONENTS

+  asmparser

+  bitreader

+  inteljitevents

+  interpreter

+  jit

+  mcjit

+  nativecodegen

+  object

+  selectiondag

+  )

+

+add_llvm_tool(llvm-jitlistener

+  llvm-jitlistener.cpp

+  )

diff --git a/tools/llvm-jitlistener/LLVMBuild.txt b/tools/llvm-jitlistener/LLVMBuild.txt
new file mode 100644
index 0000000..c436dd9
--- /dev/null
+++ b/tools/llvm-jitlistener/LLVMBuild.txt
@@ -0,0 +1,22 @@
+;===- ./tools/llvm-jitlistener/LLVMBuild.txt -------------------*- Conf -*--===;
+;
+;                     The LLVM Compiler Infrastructure
+;
+; This file is distributed under the University of Illinois Open Source
+; License. See LICENSE.TXT for details.
+;
+;===------------------------------------------------------------------------===;
+;
+; This is an LLVMBuild description file for the components in this subdirectory.
+;
+; For more information on the LLVMBuild system, please see:
+;
+;   http://llvm.org/docs/LLVMBuild.html
+;
+;===------------------------------------------------------------------------===;
+
+[component_0]
+type = Tool
+name = llvm-jitlistener
+parent = Tools
+required_libraries = AsmParser BitReader Interpreter JIT MCJIT NativeCodeGen Object SelectionDAG Native
diff --git a/tools/llvm-jitlistener/Makefile b/tools/llvm-jitlistener/Makefile
new file mode 100644
index 0000000..0971e6a
--- /dev/null
+++ b/tools/llvm-jitlistener/Makefile
@@ -0,0 +1,27 @@
+##===- tools/llvm-jitlistener/Makefile ---------------------*- Makefile -*-===##

+#

+#                     The LLVM Compiler Infrastructure

+#

+# This file is distributed under the University of Illinois Open Source

+# License. See LICENSE.TXT for details.

+#

+##===----------------------------------------------------------------------===##

+

+LEVEL := ../..

+TOOLNAME := llvm-jitlistener

+

+include $(LEVEL)/Makefile.config

+

+LINK_COMPONENTS := mcjit jit interpreter nativecodegen bitreader asmparser selectiondag Object

+

+# If Intel JIT Events support is configured, link against the LLVM Intel JIT

+# Events interface library.  If not, this tool will do nothing useful, but it

+# will build correctly.

+ifeq ($(USE_INTEL_JITEVENTS), 1)

+  LINK_COMPONENTS += inteljitevents

+endif

+

+# This tool has no plugins, optimize startup time.

+TOOL_NO_EXPORTS := 1

+

+include $(LLVM_SRC_ROOT)/Makefile.rules

diff --git a/tools/llvm-jitlistener/llvm-jitlistener.cpp b/tools/llvm-jitlistener/llvm-jitlistener.cpp
new file mode 100644
index 0000000..2b05e66
--- /dev/null
+++ b/tools/llvm-jitlistener/llvm-jitlistener.cpp
@@ -0,0 +1,207 @@
+//===-- llvm-jitlistener.cpp - Utility for testing MCJIT event listener ---===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This program is a used by lit tests to verify the MCJIT JITEventListener
+// interface.  It registers a mock JIT event listener, generates a module from
+// an input IR file and dumps the reported event information to stdout.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/OwningPtr.h"
+#include "llvm/ADT/Triple.h"
+#include "../../lib/ExecutionEngine/IntelJITEvents/IntelJITEventsWrapper.h"
+#include "llvm/ExecutionEngine/JITEventListener.h"
+#include "llvm/ExecutionEngine/JITMemoryManager.h"
+#include "llvm/ExecutionEngine/MCJIT.h"
+#include "llvm/ExecutionEngine/ObjectImage.h"
+#include "llvm/LLVMContext.h"
+#include "llvm/Module.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Host.h"
+#include "llvm/Support/IRReader.h"
+#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/PrettyStackTrace.h"
+#include "llvm/Support/Signals.h"
+#include "llvm/Support/SourceMgr.h"
+#include "llvm/Support/TargetSelect.h"
+#include <string>
+
+using namespace llvm;
+
+namespace {
+
+typedef std::vector<std::pair<std::string, unsigned int> > SourceLocations;
+typedef std::map<uint64_t, SourceLocations> NativeCodeMap;
+
+NativeCodeMap  ReportedDebugFuncs;
+
+int NotifyEvent(iJIT_JVM_EVENT EventType, void *EventSpecificData) {
+  switch (EventType) {
+    case iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED: {
+      if (!EventSpecificData) {
+        errs() <<
+          "Error: The JIT event listener did not provide a event data.";
+        return -1;
+      }
+      iJIT_Method_Load* msg = static_cast<iJIT_Method_Load*>(EventSpecificData);
+
+      ReportedDebugFuncs[msg->method_id];
+
+      outs() << "Method load [" << msg->method_id << "]: " << msg->method_name
+             << ", Size = " << msg->method_size << "\n";
+
+      for(unsigned int i = 0; i < msg->line_number_size; ++i) {
+        if (!msg->line_number_table) {
+          errs() << "A function with a non-zero line count had no line table.";
+          return -1;
+        }
+        std::pair<std::string, unsigned int> loc(
+          std::string(msg->source_file_name),
+          msg->line_number_table[i].LineNumber);
+        ReportedDebugFuncs[msg->method_id].push_back(loc);
+        outs() << "  Line info @ " << msg->line_number_table[i].Offset
+               << ": " << msg->source_file_name
+               << ", line " << msg->line_number_table[i].LineNumber << "\n";
+      }
+      outs() << "\n";
+    }
+    break;
+    case iJVM_EVENT_TYPE_METHOD_UNLOAD_START: {
+      if (!EventSpecificData) {
+        errs() <<
+          "Error: The JIT event listener did not provide a event data.";
+        return -1;
+      }
+      unsigned int UnloadId
+        = *reinterpret_cast<unsigned int*>(EventSpecificData);
+      assert(1 == ReportedDebugFuncs.erase(UnloadId));
+      outs() << "Method unload [" << UnloadId << "]\n";
+    }
+    break;
+    default:
+      break;
+  }
+  return 0;
+}
+
+iJIT_IsProfilingActiveFlags IsProfilingActive(void) {
+  // for testing, pretend we have an Intel Parallel Amplifier XE 2011
+  // instance attached
+  return iJIT_SAMPLING_ON;
+}
+
+unsigned int GetNewMethodID(void) {
+  static unsigned int id = 0;
+  return ++id;
+}
+
+class JitEventListenerTest {
+protected:
+  void InitEE(const std::string &IRFile) {
+    LLVMContext &Context = getGlobalContext();
+
+    // If we have a native target, initialize it to ensure it is linked in and
+    // usable by the JIT.
+    InitializeNativeTarget();
+    InitializeNativeTargetAsmPrinter();
+
+    // Parse the bitcode...
+    SMDiagnostic Err;
+    TheModule = ParseIRFile(IRFile, Err, Context);
+    if (!TheModule) {
+      errs() << Err.getMessage();
+      return;
+    }
+
+    // FIXME: This is using the default legacy JITMemoryManager because it
+    // supports poison memory.  At some point, we'll need to update this to
+    // use an MCJIT-specific memory manager.  It might be nice to have the
+    // poison memory option there too.
+    JITMemoryManager *MemMgr = JITMemoryManager::CreateDefaultMemManager();
+    if (!MemMgr) {
+      errs() << "Unable to create memory manager.";
+      return;
+    }
+
+    // Tell the memory manager to poison freed memory so that accessing freed
+    // memory is more easily tested.
+    MemMgr->setPoisonMemory(true);
+
+    // Override the triple to generate ELF on Windows since that's supported
+    Triple Tuple(TheModule->getTargetTriple());
+    if (Tuple.getTriple().empty())
+      Tuple.setTriple(LLVM_HOSTTRIPLE);
+
+    if (Tuple.isOSWindows() && Triple::ELF != Tuple.getEnvironment()) {
+      Tuple.setEnvironment(Triple::ELF);
+      TheModule->setTargetTriple(Tuple.getTriple());
+    }
+
+    // Compile the IR
+    std::string Error;
+    TheJIT.reset(EngineBuilder(TheModule)
+      .setEngineKind(EngineKind::JIT)
+      .setErrorStr(&Error)
+      .setJITMemoryManager(MemMgr)
+      .setUseMCJIT(true)
+      .create());
+    if (Error.empty() == false)
+      errs() << Error;
+  }
+
+  void DestroyEE() {
+    TheJIT.reset();
+  }
+
+  LLVMContext Context; // Global ownership
+  Module *TheModule; // Owned by ExecutionEngine.
+  JITMemoryManager *JMM; // Owned by ExecutionEngine.
+  OwningPtr<ExecutionEngine> TheJIT;
+
+public:
+  void ProcessInput(const std::string &Filename) {
+    InitEE(Filename);
+
+    llvm::OwningPtr<llvm::JITEventListener> Listener(JITEventListener::createIntelJITEventListener(
+        new IntelJITEventsWrapper(NotifyEvent, 0,
+          IsProfilingActive, 0, 0,
+          GetNewMethodID)));
+
+    TheJIT->RegisterJITEventListener(Listener.get());
+
+    TheJIT->finalizeObject();
+
+    // Destroy the JIT engine instead of unregistering to get unload events.
+    DestroyEE();
+  }
+};
+
+
+
+} // end anonymous namespace
+
+static cl::opt<std::string>
+InputFilename(cl::Positional, cl::desc("<input IR file>"),
+               cl::Required);
+
+int main(int argc, char **argv) {
+  // Print a stack trace if we signal out.
+  sys::PrintStackTraceOnErrorSignal();
+  PrettyStackTraceProgram X(argc, argv);
+  llvm_shutdown_obj Y;  // Call llvm_shutdown() on exit.
+
+  cl::ParseCommandLineOptions(argc, argv, "llvm jit event listener test utility\n");
+
+  JitEventListenerTest Test;
+
+  Test.ProcessInput(InputFilename);
+
+  return 0;
+}