//===- JITEventListenerTestCommon.h - Helper for JITEventListener tests ------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===-------------------------------------------------------------------------------===// #ifndef JIT_EVENT_LISTENER_TEST_COMMON_H #define JIT_EVENT_LISTENER_TEST_COMMON_H #include "llvm/CodeGen/MachineCodeInfo.h" #include "llvm/Config/config.h" #include "llvm/DIBuilder.h" #include "llvm/DebugInfo.h" #include "llvm/ExecutionEngine/JIT.h" #include "llvm/ExecutionEngine/JITEventListener.h" #include "llvm/IR/IRBuilder.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/Module.h" #include "llvm/IR/TypeBuilder.h" #include "llvm/Support/Dwarf.h" #include "llvm/Support/TargetSelect.h" #include "gtest/gtest.h" #include #include #include typedef std::vector > SourceLocations; typedef std::map NativeCodeMap; class JITEnvironment : public testing::Environment { virtual void SetUp() { // Required to create a JIT. llvm::InitializeNativeTarget(); } }; inline unsigned int getLine() { return 12; } inline unsigned int getCol() { return 0; } inline const char* getFilename() { return "mock_source_file.cpp"; } // Test fixture shared by tests for listener implementations template class JITEventListenerTestBase : public testing::Test { protected: llvm::OwningPtr MockWrapper; llvm::OwningPtr Listener; public: llvm::Module* M; llvm::MDNode* Scope; llvm::ExecutionEngine* EE; llvm::DIBuilder* DebugBuilder; llvm::IRBuilder<> Builder; JITEventListenerTestBase(WrapperT* w) : MockWrapper(w) , M(new llvm::Module("module", llvm::getGlobalContext())) , EE(llvm::EngineBuilder(M) .setEngineKind(llvm::EngineKind::JIT) .setOptLevel(llvm::CodeGenOpt::None) .create()) , DebugBuilder(new llvm::DIBuilder(*M)) , Builder(llvm::getGlobalContext()) { DebugBuilder->createCompileUnit(llvm::dwarf::DW_LANG_C_plus_plus, "JIT", "JIT", "JIT", true, "", 1); Scope = DebugBuilder->createFile(getFilename(), "."); } llvm::Function *buildFunction(const SourceLocations& DebugLocations) { using namespace llvm; LLVMContext& GlobalContext = getGlobalContext(); SourceLocations::const_iterator CurrentDebugLocation = DebugLocations.begin(); if (CurrentDebugLocation != DebugLocations.end()) { DebugLoc DebugLocation = DebugLoc::get(getLine(), getCol(), DebugBuilder->createFile(CurrentDebugLocation->first, ".")); Builder.SetCurrentDebugLocation(DebugLocation); CurrentDebugLocation++; } Function *Result = Function::Create( TypeBuilder::get(GlobalContext), GlobalValue::ExternalLinkage, "id", M); Value *Arg = Result->arg_begin(); BasicBlock *BB = BasicBlock::Create(M->getContext(), "entry", Result); Builder.SetInsertPoint(BB); Value* one = ConstantInt::get(GlobalContext, APInt(32, 1)); for(; CurrentDebugLocation != DebugLocations.end(); ++CurrentDebugLocation) { Arg = Builder.CreateMul(Arg, Builder.CreateAdd(Arg, one)); Builder.SetCurrentDebugLocation( DebugLoc::get(CurrentDebugLocation->second, 0, DebugBuilder->createFile(CurrentDebugLocation->first, "."))); } Builder.CreateRet(Arg); return Result; } void TestNoDebugInfo(NativeCodeMap& ReportedDebugFuncs) { SourceLocations DebugLocations; llvm::Function* f = buildFunction(DebugLocations); EXPECT_TRUE(0 != f); //Cause JITting and callbacks to our listener EXPECT_TRUE(0 != EE->getPointerToFunction(f)); EXPECT_TRUE(1 == ReportedDebugFuncs.size()); EE->freeMachineCodeForFunction(f); EXPECT_TRUE(ReportedDebugFuncs.size() == 0); } void TestSingleLine(NativeCodeMap& ReportedDebugFuncs) { SourceLocations DebugLocations; DebugLocations.push_back(std::make_pair(std::string(getFilename()), getLine())); llvm::Function* f = buildFunction(DebugLocations); EXPECT_TRUE(0 != f); EXPECT_TRUE(0 != EE->getPointerToFunction(f)); EXPECT_TRUE(1 == ReportedDebugFuncs.size()); EXPECT_STREQ(ReportedDebugFuncs.begin()->second.begin()->first.c_str(), getFilename()); EXPECT_EQ(ReportedDebugFuncs.begin()->second.begin()->second, getLine()); EE->freeMachineCodeForFunction(f); EXPECT_TRUE(ReportedDebugFuncs.size() == 0); } void TestMultipleLines(NativeCodeMap& ReportedDebugFuncs) { using namespace std; SourceLocations DebugLocations; unsigned int c = 5; for(unsigned int i = 0; i < c; ++i) { DebugLocations.push_back(make_pair(string(getFilename()), getLine() + i)); } llvm::Function* f = buildFunction(DebugLocations); EXPECT_TRUE(0 != f); EXPECT_TRUE(0 != EE->getPointerToFunction(f)); EXPECT_TRUE(1 == ReportedDebugFuncs.size()); SourceLocations& FunctionInfo = ReportedDebugFuncs.begin()->second; EXPECT_EQ(c, FunctionInfo.size()); int VerifyCount = 0; for(SourceLocations::iterator i = FunctionInfo.begin(); i != FunctionInfo.end(); ++i) { EXPECT_STREQ(i->first.c_str(), getFilename()); EXPECT_EQ(i->second, getLine() + VerifyCount); VerifyCount++; } EE->freeMachineCodeForFunction(f); EXPECT_TRUE(ReportedDebugFuncs.size() == 0); } void TestMultipleFiles(NativeCodeMap& ReportedDebugFuncs) { std::string secondFilename("another_file.cpp"); SourceLocations DebugLocations; DebugLocations.push_back(std::make_pair(std::string(getFilename()), getLine())); DebugLocations.push_back(std::make_pair(secondFilename, getLine())); llvm::Function* f = buildFunction(DebugLocations); EXPECT_TRUE(0 != f); EXPECT_TRUE(0 != EE->getPointerToFunction(f)); EXPECT_TRUE(1 == ReportedDebugFuncs.size()); SourceLocations& FunctionInfo = ReportedDebugFuncs.begin()->second; EXPECT_TRUE(2 == FunctionInfo.size()); EXPECT_STREQ(FunctionInfo.at(0).first.c_str(), getFilename()); EXPECT_STREQ(FunctionInfo.at(1).first.c_str(), secondFilename.c_str()); EXPECT_EQ(FunctionInfo.at(0).second, getLine()); EXPECT_EQ(FunctionInfo.at(1).second, getLine()); EE->freeMachineCodeForFunction(f); EXPECT_TRUE(ReportedDebugFuncs.size() == 0); } }; #endif //JIT_EVENT_LISTENER_TEST_COMMON_H