1//===- JITEventListenerTestCommon.h - Helper for JITEventListener tests ------------===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===-------------------------------------------------------------------------------===//
9
10#ifndef JIT_EVENT_LISTENER_TEST_COMMON_H
11#define JIT_EVENT_LISTENER_TEST_COMMON_H
12
13#include "llvm/DIBuilder.h"
14#include "llvm/DebugInfo.h"
15#include "llvm/IRBuilder.h"
16#include "llvm/Instructions.h"
17#include "llvm/Module.h"
18#include "llvm/TypeBuilder.h"
19#include "llvm/CodeGen/MachineCodeInfo.h"
20#include "llvm/ExecutionEngine/JIT.h"
21#include "llvm/ExecutionEngine/JITEventListener.h"
22#include "llvm/Support/Dwarf.h"
23#include "llvm/Support/TargetSelect.h"
24#include "llvm/Config/config.h"
25
26#include "gtest/gtest.h"
27
28#include <vector>
29#include <string>
30#include <utility>
31
32typedef std::vector<std::pair<std::string, unsigned int> > SourceLocations;
33typedef std::map<uint64_t, SourceLocations> NativeCodeMap;
34
35class JITEnvironment : public testing::Environment {
36  virtual void SetUp() {
37    // Required to create a JIT.
38    llvm::InitializeNativeTarget();
39  }
40};
41
42inline unsigned int getLine() {
43  return 12;
44}
45
46inline unsigned int getCol() {
47  return 0;
48}
49
50inline const char* getFilename() {
51  return "mock_source_file.cpp";
52}
53
54// Test fixture shared by tests for listener implementations
55template<typename WrapperT>
56class JITEventListenerTestBase : public testing::Test {
57protected:
58  llvm::OwningPtr<WrapperT> MockWrapper;
59  llvm::OwningPtr<llvm::JITEventListener> Listener;
60
61public:
62  llvm::Module* M;
63  llvm::MDNode* Scope;
64  llvm::ExecutionEngine* EE;
65  llvm::DIBuilder* DebugBuilder;
66  llvm::IRBuilder<> Builder;
67
68  JITEventListenerTestBase(WrapperT* w)
69  : MockWrapper(w)
70  , M(new llvm::Module("module", llvm::getGlobalContext()))
71  , EE(llvm::EngineBuilder(M)
72    .setEngineKind(llvm::EngineKind::JIT)
73    .setOptLevel(llvm::CodeGenOpt::None)
74    .create())
75  , DebugBuilder(new llvm::DIBuilder(*M))
76  , Builder(llvm::getGlobalContext())
77  {
78    DebugBuilder->createCompileUnit(llvm::dwarf::DW_LANG_C_plus_plus,
79                                    "JIT",
80                                    "JIT",
81                                    "JIT",
82                                    true,
83                                    "",
84                                    1);
85
86    Scope = DebugBuilder->createFile(getFilename(), ".");
87  }
88
89  llvm::Function *buildFunction(const SourceLocations& DebugLocations) {
90    using namespace llvm;
91
92    LLVMContext& GlobalContext = getGlobalContext();
93
94    SourceLocations::const_iterator CurrentDebugLocation
95      = DebugLocations.begin();
96
97    if (CurrentDebugLocation != DebugLocations.end()) {
98      DebugLoc DebugLocation = DebugLoc::get(getLine(), getCol(),
99          DebugBuilder->createFile(CurrentDebugLocation->first, "."));
100      Builder.SetCurrentDebugLocation(DebugLocation);
101      CurrentDebugLocation++;
102    }
103
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, ".")));
117    }
118    Builder.CreateRet(Arg);
119    return Result;
120  }
121
122  void TestNoDebugInfo(NativeCodeMap& ReportedDebugFuncs) {
123    SourceLocations DebugLocations;
124    llvm::Function* f = buildFunction(DebugLocations);
125    EXPECT_TRUE(0 != f);
126
127    //Cause JITting and callbacks to our listener
128    EXPECT_TRUE(0 != EE->getPointerToFunction(f));
129    EXPECT_TRUE(1 == ReportedDebugFuncs.size());
130
131    EE->freeMachineCodeForFunction(f);
132    EXPECT_TRUE(ReportedDebugFuncs.size() == 0);
133  }
134
135  void TestSingleLine(NativeCodeMap& ReportedDebugFuncs) {
136    SourceLocations DebugLocations;
137    DebugLocations.push_back(std::make_pair(std::string(getFilename()),
138                                            getLine()));
139    llvm::Function* f = buildFunction(DebugLocations);
140    EXPECT_TRUE(0 != f);
141
142    EXPECT_TRUE(0 != EE->getPointerToFunction(f));
143    EXPECT_TRUE(1 == ReportedDebugFuncs.size());
144    EXPECT_STREQ(ReportedDebugFuncs.begin()->second.begin()->first.c_str(),
145                 getFilename());
146    EXPECT_EQ(ReportedDebugFuncs.begin()->second.begin()->second, getLine());
147
148    EE->freeMachineCodeForFunction(f);
149    EXPECT_TRUE(ReportedDebugFuncs.size() == 0);
150  }
151
152  void TestMultipleLines(NativeCodeMap& ReportedDebugFuncs) {
153    using namespace std;
154
155    SourceLocations DebugLocations;
156    unsigned int c = 5;
157    for(unsigned int i = 0; i < c; ++i) {
158      DebugLocations.push_back(make_pair(string(getFilename()), getLine() + i));
159    }
160
161    llvm::Function* f = buildFunction(DebugLocations);
162    EXPECT_TRUE(0 != f);
163
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());
168
169    int VerifyCount = 0;
170    for(SourceLocations::iterator i = FunctionInfo.begin();
171        i != FunctionInfo.end();
172        ++i) {
173      EXPECT_STREQ(i->first.c_str(), getFilename());
174      EXPECT_EQ(i->second, getLine() + VerifyCount);
175      VerifyCount++;
176    }
177
178    EE->freeMachineCodeForFunction(f);
179    EXPECT_TRUE(ReportedDebugFuncs.size() == 0);
180  }
181
182  void TestMultipleFiles(NativeCodeMap& ReportedDebugFuncs) {
183
184    std::string secondFilename("another_file.cpp");
185
186    SourceLocations DebugLocations;
187    DebugLocations.push_back(std::make_pair(std::string(getFilename()),
188                                            getLine()));
189    DebugLocations.push_back(std::make_pair(secondFilename, getLine()));
190    llvm::Function* f = buildFunction(DebugLocations);
191    EXPECT_TRUE(0 != f);
192
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());
197
198    EXPECT_STREQ(FunctionInfo.at(0).first.c_str(), getFilename());
199    EXPECT_STREQ(FunctionInfo.at(1).first.c_str(), secondFilename.c_str());
200
201    EXPECT_EQ(FunctionInfo.at(0).second, getLine());
202    EXPECT_EQ(FunctionInfo.at(1).second, getLine());
203
204    EE->freeMachineCodeForFunction(f);
205    EXPECT_TRUE(ReportedDebugFuncs.size() == 0);
206  }
207};
208
209#endif //JIT_EVENT_LISTENER_TEST_COMMON_H
210