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