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/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