Home | History | Annotate | Download | only in JIT
      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 
     32 typedef std::vector<std::pair<std::string, unsigned int> > SourceLocations;
     33 typedef std::map<uint64_t, SourceLocations> NativeCodeMap;
     34 
     35 class JITEnvironment : public testing::Environment {
     36   virtual void SetUp() {
     37     // Required to create a JIT.
     38     llvm::InitializeNativeTarget();
     39   }
     40 };
     41 
     42 inline unsigned int getLine() {
     43   return 12;
     44 }
     45 
     46 inline unsigned int getCol() {
     47   return 0;
     48 }
     49 
     50 inline const char* getFilename() {
     51   return "mock_source_file.cpp";
     52 }
     53 
     54 // Test fixture shared by tests for listener implementations
     55 template<typename WrapperT>
     56 class JITEventListenerTestBase : public testing::Test {
     57 protected:
     58   llvm::OwningPtr<WrapperT> MockWrapper;
     59   llvm::OwningPtr<llvm::JITEventListener> Listener;
     60 
     61 public:
     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