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