summaryrefslogtreecommitdiff
path: root/unittests/ExecutionEngine
diff options
context:
space:
mode:
authorJeffrey Yasskin <jyasskin@google.com>2009-06-25 02:04:04 +0000
committerJeffrey Yasskin <jyasskin@google.com>2009-06-25 02:04:04 +0000
commitdf5a7daff9c7664bff8b713e8ed5155319bc6041 (patch)
treed0a7b2a265916b1e0e36ef6423b56749d3429c9a /unittests/ExecutionEngine
parentb6c29d55123f6b8c3f9e4d56e4be653a1fd2a472 (diff)
downloadllvm-df5a7daff9c7664bff8b713e8ed5155319bc6041.tar.gz
llvm-df5a7daff9c7664bff8b713e8ed5155319bc6041.tar.bz2
llvm-df5a7daff9c7664bff8b713e8ed5155319bc6041.tar.xz
Add a JITEventListener interface that gets called back when a new function is
emitted or the machine code for a function is freed. Chris mentioned that we may also want a notification when a stub is emitted, but that'll be a future change. I intend to use this to tell oprofile where functions are emitted and what lines correspond to what addresses. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@74157 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'unittests/ExecutionEngine')
-rw-r--r--unittests/ExecutionEngine/JIT/JITEventListenerTest.cpp241
-rw-r--r--unittests/ExecutionEngine/JIT/Makefile15
-rw-r--r--unittests/ExecutionEngine/Makefile19
3 files changed, 275 insertions, 0 deletions
diff --git a/unittests/ExecutionEngine/JIT/JITEventListenerTest.cpp b/unittests/ExecutionEngine/JIT/JITEventListenerTest.cpp
new file mode 100644
index 0000000000..3c9beebba6
--- /dev/null
+++ b/unittests/ExecutionEngine/JIT/JITEventListenerTest.cpp
@@ -0,0 +1,241 @@
+//===- JITEventListenerTest.cpp - Unit tests for JITEventListeners --------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ExecutionEngine/JITEventListener.h"
+
+#include "llvm/Instructions.h"
+#include "llvm/Module.h"
+#include "llvm/ModuleProvider.h"
+#include "llvm/ADT/OwningPtr.h"
+#include "llvm/CodeGen/MachineCodeInfo.h"
+#include "llvm/ExecutionEngine/JIT.h"
+#include "llvm/Support/TypeBuilder.h"
+#include "llvm/Target/TargetSelect.h"
+#include "gtest/gtest.h"
+#include <vector>
+
+using namespace llvm;
+
+namespace {
+
+struct FunctionEmittedEvent {
+ // Indices are local to the RecordingJITEventListener, since the
+ // JITEventListener interface makes no guarantees about the order of
+ // calls between Listeners.
+ unsigned Index;
+ const Function *F;
+ void *Code;
+ size_t Size;
+ JITEvent_EmittedFunctionDetails Details;
+};
+struct FunctionFreedEvent {
+ unsigned Index;
+ const Function *F;
+ void *Code;
+};
+
+struct RecordingJITEventListener : public JITEventListener {
+ std::vector<FunctionEmittedEvent> EmittedEvents;
+ std::vector<FunctionFreedEvent> FreedEvents;
+
+ int NextIndex;
+
+ RecordingJITEventListener() : NextIndex(0) {}
+
+ virtual void NotifyFunctionEmitted(const Function &F,
+ void *Code, size_t Size,
+ const EmittedFunctionDetails &Details) {
+ FunctionEmittedEvent Event = {NextIndex++, &F, Code, Size, Details};
+ EmittedEvents.push_back(Event);
+ }
+
+ virtual void NotifyFreeingMachineCode(const Function &F, void *OldPtr) {
+ FunctionFreedEvent Event = {NextIndex++, &F, OldPtr};
+ FreedEvents.push_back(Event);
+ }
+};
+
+class JITEventListenerTest : public testing::Test {
+ protected:
+ JITEventListenerTest()
+ : M(new Module("module")),
+ EE(ExecutionEngine::createJIT(new ExistingModuleProvider(M))) {
+ }
+
+ Module *M;
+ const OwningPtr<ExecutionEngine> EE;
+};
+
+Function *buildFunction(Module *M) {
+ Function *Result = Function::Create(
+ TypeBuilder<int32_t(int32_t), false>::get(),
+ GlobalValue::ExternalLinkage, "id", M);
+ Value *Arg = Result->arg_begin();
+ BasicBlock *BB = BasicBlock::Create("entry", Result);
+ ReturnInst::Create(Arg, BB);
+ return Result;
+}
+
+// Tests that a single JITEventListener follows JIT events accurately.
+TEST_F(JITEventListenerTest, Simple) {
+ RecordingJITEventListener Listener;
+ EE->RegisterJITEventListener(&Listener);
+ Function *F1 = buildFunction(M);
+ Function *F2 = buildFunction(M);
+
+ void *F1_addr = EE->getPointerToFunction(F1);
+ void *F2_addr = EE->getPointerToFunction(F2);
+ EE->getPointerToFunction(F1); // Should do nothing.
+ EE->freeMachineCodeForFunction(F1);
+ EE->freeMachineCodeForFunction(F2);
+
+ ASSERT_EQ(2U, Listener.EmittedEvents.size());
+ ASSERT_EQ(2U, Listener.FreedEvents.size());
+
+ EXPECT_EQ(0U, Listener.EmittedEvents[0].Index);
+ EXPECT_EQ(F1, Listener.EmittedEvents[0].F);
+ EXPECT_EQ(F1_addr, Listener.EmittedEvents[0].Code);
+ EXPECT_LT(0U, Listener.EmittedEvents[0].Size)
+ << "We don't know how big the function will be, but it had better"
+ << " contain some bytes.";
+
+ EXPECT_EQ(1U, Listener.EmittedEvents[1].Index);
+ EXPECT_EQ(F2, Listener.EmittedEvents[1].F);
+ EXPECT_EQ(F2_addr, Listener.EmittedEvents[1].Code);
+ EXPECT_LT(0U, Listener.EmittedEvents[1].Size)
+ << "We don't know how big the function will be, but it had better"
+ << " contain some bytes.";
+
+ EXPECT_EQ(2U, Listener.FreedEvents[0].Index);
+ EXPECT_EQ(F1, Listener.FreedEvents[0].F);
+ EXPECT_EQ(F1_addr, Listener.FreedEvents[0].Code);
+
+ EXPECT_EQ(3U, Listener.FreedEvents[1].Index);
+ EXPECT_EQ(F2, Listener.FreedEvents[1].F);
+ EXPECT_EQ(F2_addr, Listener.FreedEvents[1].Code);
+
+ F1->eraseFromParent();
+ F2->eraseFromParent();
+}
+
+// Tests that a single JITEventListener follows JIT events accurately.
+TEST_F(JITEventListenerTest, MultipleListenersDontInterfere) {
+ RecordingJITEventListener Listener1;
+ RecordingJITEventListener Listener2;
+ RecordingJITEventListener Listener3;
+ Function *F1 = buildFunction(M);
+ Function *F2 = buildFunction(M);
+
+ EE->RegisterJITEventListener(&Listener1);
+ EE->RegisterJITEventListener(&Listener2);
+ void *F1_addr = EE->getPointerToFunction(F1);
+ EE->RegisterJITEventListener(&Listener3);
+ EE->UnregisterJITEventListener(&Listener1);
+ void *F2_addr = EE->getPointerToFunction(F2);
+ EE->UnregisterJITEventListener(&Listener2);
+ EE->UnregisterJITEventListener(&Listener3);
+ EE->freeMachineCodeForFunction(F1);
+ EE->RegisterJITEventListener(&Listener2);
+ EE->RegisterJITEventListener(&Listener3);
+ EE->RegisterJITEventListener(&Listener1);
+ EE->freeMachineCodeForFunction(F2);
+ EE->UnregisterJITEventListener(&Listener1);
+ EE->UnregisterJITEventListener(&Listener2);
+ EE->UnregisterJITEventListener(&Listener3);
+
+ // Listener 1.
+ ASSERT_EQ(1U, Listener1.EmittedEvents.size());
+ ASSERT_EQ(1U, Listener1.FreedEvents.size());
+
+ EXPECT_EQ(0U, Listener1.EmittedEvents[0].Index);
+ EXPECT_EQ(F1, Listener1.EmittedEvents[0].F);
+ EXPECT_EQ(F1_addr, Listener1.EmittedEvents[0].Code);
+ EXPECT_LT(0U, Listener1.EmittedEvents[0].Size)
+ << "We don't know how big the function will be, but it had better"
+ << " contain some bytes.";
+
+ EXPECT_EQ(1U, Listener1.FreedEvents[0].Index);
+ EXPECT_EQ(F2, Listener1.FreedEvents[0].F);
+ EXPECT_EQ(F2_addr, Listener1.FreedEvents[0].Code);
+
+ // Listener 2.
+ ASSERT_EQ(2U, Listener2.EmittedEvents.size());
+ ASSERT_EQ(1U, Listener2.FreedEvents.size());
+
+ EXPECT_EQ(0U, Listener2.EmittedEvents[0].Index);
+ EXPECT_EQ(F1, Listener2.EmittedEvents[0].F);
+ EXPECT_EQ(F1_addr, Listener2.EmittedEvents[0].Code);
+ EXPECT_LT(0U, Listener2.EmittedEvents[0].Size)
+ << "We don't know how big the function will be, but it had better"
+ << " contain some bytes.";
+
+ EXPECT_EQ(1U, Listener2.EmittedEvents[1].Index);
+ EXPECT_EQ(F2, Listener2.EmittedEvents[1].F);
+ EXPECT_EQ(F2_addr, Listener2.EmittedEvents[1].Code);
+ EXPECT_LT(0U, Listener2.EmittedEvents[1].Size)
+ << "We don't know how big the function will be, but it had better"
+ << " contain some bytes.";
+
+ EXPECT_EQ(2U, Listener2.FreedEvents[0].Index);
+ EXPECT_EQ(F2, Listener2.FreedEvents[0].F);
+ EXPECT_EQ(F2_addr, Listener2.FreedEvents[0].Code);
+
+ // Listener 3.
+ ASSERT_EQ(1U, Listener3.EmittedEvents.size());
+ ASSERT_EQ(1U, Listener3.FreedEvents.size());
+
+ EXPECT_EQ(0U, Listener3.EmittedEvents[0].Index);
+ EXPECT_EQ(F2, Listener3.EmittedEvents[0].F);
+ EXPECT_EQ(F2_addr, Listener3.EmittedEvents[0].Code);
+ EXPECT_LT(0U, Listener3.EmittedEvents[0].Size)
+ << "We don't know how big the function will be, but it had better"
+ << " contain some bytes.";
+
+ EXPECT_EQ(1U, Listener3.FreedEvents[0].Index);
+ EXPECT_EQ(F2, Listener3.FreedEvents[0].F);
+ EXPECT_EQ(F2_addr, Listener3.FreedEvents[0].Code);
+
+ F1->eraseFromParent();
+ F2->eraseFromParent();
+}
+
+TEST_F(JITEventListenerTest, MatchesMachineCodeInfo) {
+ RecordingJITEventListener Listener;
+ MachineCodeInfo MCI;
+ Function *F = buildFunction(M);
+
+ EE->RegisterJITEventListener(&Listener);
+ EE->runJITOnFunction(F, &MCI);
+ void *F_addr = EE->getPointerToFunction(F);
+ EE->freeMachineCodeForFunction(F);
+
+ ASSERT_EQ(1U, Listener.EmittedEvents.size());
+ ASSERT_EQ(1U, Listener.FreedEvents.size());
+
+ EXPECT_EQ(0U, Listener.EmittedEvents[0].Index);
+ EXPECT_EQ(F, Listener.EmittedEvents[0].F);
+ EXPECT_EQ(F_addr, Listener.EmittedEvents[0].Code);
+ EXPECT_EQ(MCI.address(), Listener.EmittedEvents[0].Code);
+ EXPECT_EQ(MCI.size(), Listener.EmittedEvents[0].Size);
+
+ EXPECT_EQ(1U, Listener.FreedEvents[0].Index);
+ EXPECT_EQ(F, Listener.FreedEvents[0].F);
+ EXPECT_EQ(F_addr, Listener.FreedEvents[0].Code);
+}
+
+class JITEnvironment : public testing::Environment {
+ virtual void SetUp() {
+ // Required for ExecutionEngine::createJIT to create a JIT.
+ InitializeNativeTarget();
+ }
+};
+testing::Environment* const jit_env =
+ testing::AddGlobalTestEnvironment(new JITEnvironment);
+
+} // anonymous namespace
diff --git a/unittests/ExecutionEngine/JIT/Makefile b/unittests/ExecutionEngine/JIT/Makefile
new file mode 100644
index 0000000000..0069c7687a
--- /dev/null
+++ b/unittests/ExecutionEngine/JIT/Makefile
@@ -0,0 +1,15 @@
+##===- unittests/ExecutionEngine/JIT/Makefile --------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LEVEL = ../../..
+TESTNAME = JIT
+LINK_COMPONENTS := core support jit native
+
+include $(LEVEL)/Makefile.config
+include $(LLVM_SRC_ROOT)/unittests/Makefile.unittest
diff --git a/unittests/ExecutionEngine/Makefile b/unittests/ExecutionEngine/Makefile
new file mode 100644
index 0000000000..e837a7d4fd
--- /dev/null
+++ b/unittests/ExecutionEngine/Makefile
@@ -0,0 +1,19 @@
+##===- unittests/ExecutionEngine/Makefile ------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LEVEL = ../..
+
+include $(LEVEL)/Makefile.config
+
+PARALLEL_DIRS = JIT
+
+include $(LEVEL)/Makefile.common
+
+clean::
+ $(Verb) $(RM) -f *Tests