1 //===- JITEventListenerTestCommon.h - Helper for JITEventListener tests ------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===-------------------------------------------------------------------------------===//
10 #ifndef JIT_EVENT_LISTENER_TEST_COMMON_H
11 #define JIT_EVENT_LISTENER_TEST_COMMON_H
13 #include "llvm/DebugInfo.h"
14 #include "llvm/Instructions.h"
15 #include "llvm/Module.h"
16 #include "llvm/Analysis/DIBuilder.h"
17 #include "llvm/CodeGen/MachineCodeInfo.h"
18 #include "llvm/Config/config.h"
19 #include "llvm/ExecutionEngine/JIT.h"
20 #include "llvm/ExecutionEngine/JITEventListener.h"
21 #include "llvm/Support/IRBuilder.h"
22 #include "llvm/Support/Dwarf.h"
23 #include "llvm/Support/TypeBuilder.h"
24 #include "llvm/Support/TargetSelect.h"
26 #include "gtest/gtest.h"
32 typedef std::vector<std::pair<std::string, unsigned int> > SourceLocations;
33 typedef std::map<uint64_t, SourceLocations> NativeCodeMap;
35 class JITEnvironment : public testing::Environment {
36 virtual void SetUp() {
37 // Required to create a JIT.
38 llvm::InitializeNativeTarget();
42 inline unsigned int getLine() {
46 inline unsigned int getCol() {
50 inline const char* getFilename() {
51 return "mock_source_file.cpp";
54 // Test fixture shared by tests for listener implementations
55 template<typename WrapperT>
56 class JITEventListenerTestBase : public testing::Test {
58 llvm::OwningPtr<WrapperT> MockWrapper;
59 llvm::OwningPtr<llvm::JITEventListener> Listener;
64 llvm::ExecutionEngine* EE;
65 llvm::DIBuilder* DebugBuilder;
66 llvm::IRBuilder<> Builder;
68 JITEventListenerTestBase(WrapperT* w)
70 , M(new llvm::Module("module", llvm::getGlobalContext()))
71 , EE(llvm::EngineBuilder(M)
72 .setEngineKind(llvm::EngineKind::JIT)
73 .setOptLevel(llvm::CodeGenOpt::None)
75 , DebugBuilder(new llvm::DIBuilder(*M))
76 , Builder(llvm::getGlobalContext())
78 DebugBuilder->createCompileUnit(llvm::dwarf::DW_LANG_C_plus_plus,
86 Scope = DebugBuilder->createFile(getFilename(), ".");
89 llvm::Function *buildFunction(const SourceLocations& DebugLocations) {
92 LLVMContext& GlobalContext = getGlobalContext();
94 SourceLocations::const_iterator CurrentDebugLocation
95 = DebugLocations.begin();
97 if (CurrentDebugLocation != DebugLocations.end()) {
98 DebugLoc DebugLocation = DebugLoc::get(getLine(), getCol(),
99 DebugBuilder->createFile(CurrentDebugLocation->first, "."));
100 Builder.SetCurrentDebugLocation(DebugLocation);
101 CurrentDebugLocation++;
104 Function *Result = Function::Create(
105 TypeBuilder<int32_t(int32_t), false>::get(GlobalContext),
106 GlobalValue::ExternalLinkage, "id", M);
107 Value *Arg = Result->arg_begin();
108 BasicBlock *BB = BasicBlock::Create(M->getContext(), "entry", Result);
109 Builder.SetInsertPoint(BB);
110 Value* one = ConstantInt::get(GlobalContext, APInt(32, 1));
111 for(; CurrentDebugLocation != DebugLocations.end();
112 ++CurrentDebugLocation) {
113 Arg = Builder.CreateMul(Arg, Builder.CreateAdd(Arg, one));
114 Builder.SetCurrentDebugLocation(
115 DebugLoc::get(CurrentDebugLocation->second, 0,
116 DebugBuilder->createFile(CurrentDebugLocation->first, ".")));
118 Builder.CreateRet(Arg);
122 void TestNoDebugInfo(NativeCodeMap& ReportedDebugFuncs) {
123 SourceLocations DebugLocations;
124 llvm::Function* f = buildFunction(DebugLocations);
127 //Cause JITting and callbacks to our listener
128 EXPECT_TRUE(0 != EE->getPointerToFunction(f));
129 EXPECT_TRUE(1 == ReportedDebugFuncs.size());
131 EE->freeMachineCodeForFunction(f);
132 EXPECT_TRUE(ReportedDebugFuncs.size() == 0);
135 void TestSingleLine(NativeCodeMap& ReportedDebugFuncs) {
136 SourceLocations DebugLocations;
137 DebugLocations.push_back(std::make_pair(std::string(getFilename()),
139 llvm::Function* f = buildFunction(DebugLocations);
142 EXPECT_TRUE(0 != EE->getPointerToFunction(f));
143 EXPECT_TRUE(1 == ReportedDebugFuncs.size());
144 EXPECT_STREQ(ReportedDebugFuncs.begin()->second.begin()->first.c_str(),
146 EXPECT_EQ(ReportedDebugFuncs.begin()->second.begin()->second, getLine());
148 EE->freeMachineCodeForFunction(f);
149 EXPECT_TRUE(ReportedDebugFuncs.size() == 0);
152 void TestMultipleLines(NativeCodeMap& ReportedDebugFuncs) {
155 SourceLocations DebugLocations;
157 for(unsigned int i = 0; i < c; ++i) {
158 DebugLocations.push_back(make_pair(string(getFilename()), getLine() + i));
161 llvm::Function* f = buildFunction(DebugLocations);
164 EXPECT_TRUE(0 != EE->getPointerToFunction(f));
165 EXPECT_TRUE(1 == ReportedDebugFuncs.size());
166 SourceLocations& FunctionInfo = ReportedDebugFuncs.begin()->second;
167 EXPECT_EQ(c, FunctionInfo.size());
170 for(SourceLocations::iterator i = FunctionInfo.begin();
171 i != FunctionInfo.end();
173 EXPECT_STREQ(i->first.c_str(), getFilename());
174 EXPECT_EQ(i->second, getLine() + VerifyCount);
178 EE->freeMachineCodeForFunction(f);
179 EXPECT_TRUE(ReportedDebugFuncs.size() == 0);
182 void TestMultipleFiles(NativeCodeMap& ReportedDebugFuncs) {
184 std::string secondFilename("another_file.cpp");
186 SourceLocations DebugLocations;
187 DebugLocations.push_back(std::make_pair(std::string(getFilename()),
189 DebugLocations.push_back(std::make_pair(secondFilename, getLine()));
190 llvm::Function* f = buildFunction(DebugLocations);
193 EXPECT_TRUE(0 != EE->getPointerToFunction(f));
194 EXPECT_TRUE(1 == ReportedDebugFuncs.size());
195 SourceLocations& FunctionInfo = ReportedDebugFuncs.begin()->second;
196 EXPECT_TRUE(2 == FunctionInfo.size());
198 EXPECT_STREQ(FunctionInfo.at(0).first.c_str(), getFilename());
199 EXPECT_STREQ(FunctionInfo.at(1).first.c_str(), secondFilename.c_str());
201 EXPECT_EQ(FunctionInfo.at(0).second, getLine());
202 EXPECT_EQ(FunctionInfo.at(1).second, getLine());
204 EE->freeMachineCodeForFunction(f);
205 EXPECT_TRUE(ReportedDebugFuncs.size() == 0);
209 #endif //JIT_EVENT_LISTENER_TEST_COMMON_H