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/ExecutionEngine/JIT.h" 16 #include "llvm/ExecutionEngine/JITEventListener.h" 17 #include "llvm/IR/DIBuilder.h" 18 #include "llvm/IR/DebugInfo.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 { 34 virtual void SetUp() { 35 // Required to create a JIT. 36 llvm::InitializeNativeTarget(); 37 } 38 }; 39 40 inline unsigned int getLine() { 41 return 12; 42 } 43 44 inline unsigned int getCol() { 45 return 0; 46 } 47 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 std::unique_ptr<WrapperT> MockWrapper; 57 std::unique_ptr<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 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 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 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 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 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 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