| //===- 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 <string> |
| #include <utility> |
| #include <vector> |
| |
| typedef std::vector<std::pair<std::string, unsigned int> > SourceLocations; |
| typedef std::map<uint64_t, SourceLocations> 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<typename WrapperT> |
| class JITEventListenerTestBase : public testing::Test { |
| protected: |
| llvm::OwningPtr<WrapperT> MockWrapper; |
| llvm::OwningPtr<llvm::JITEventListener> 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<int32_t(int32_t), false>::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 |