/*
* Copyright © 2012 Intel Corporation
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see .
*
*/
/**
* \file llvm_profiling.cpp
* This file will insert some instructions for each profiling point.
*
*/
#include
#include
#include "llvm/Config/llvm-config.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/InstrTypes.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/Module.h"
#include "llvm/Pass.h"
#include "llvm/IR/IRBuilder.h"
#if LLVM_VERSION_MAJOR * 10 + LLVM_VERSION_MINOR >= 35
#include "llvm/IR/CallSite.h"
#include "llvm/IR/CFG.h"
#else
#include "llvm/Support/CallSite.h"
#include "llvm/Support/CFG.h"
#endif
#include "llvm/Support/raw_ostream.h"
#include "llvm/IR/Attributes.h"
#include "llvm/llvm_gen_backend.hpp"
#include "sys/map.hpp"
#include "ir/unit.hpp"
#include
#include
using namespace llvm;
using std::vector;
namespace gbe
{
using namespace ir;
class ProfilingInserter : public FunctionPass
{
public:
static char ID;
Module* module;
IRBuilder<>* builder;
Type* intTy;
Type *ptrTy;
int profilingType;
ProfilingInserter(int profiling) : FunctionPass(ID), profilingType(profiling)
{
module = NULL;
builder = NULL;
intTy = NULL;
ptrTy = NULL;
}
~ProfilingInserter(void)
{
}
#if LLVM_VERSION_MAJOR * 10 + LLVM_VERSION_MINOR >= 40
virtual StringRef getPassName() const
#else
virtual const char *getPassName() const
#endif
{
return "Timestamp Parser";
}
virtual bool runOnFunction(llvm::Function &F);
};
bool ProfilingInserter::runOnFunction(llvm::Function &F)
{
bool changed = false;
int pointNum = 0;
switch (F.getCallingConv()) {
case CallingConv::C:
case CallingConv::Fast:
case CallingConv::SPIR_KERNEL:
break;
default:
GBE_ASSERTM(false, "Unsupported calling convention");
}
// As we inline all function calls, so skip non-kernel functions
bool bKernel = isKernelFunction(F);
if (!bKernel) return changed;
module = F.getParent();
intTy = IntegerType::get(module->getContext(), 32);
ptrTy = Type::getInt32PtrTy(module->getContext(), 1);
builder = new IRBuilder<>(module->getContext());
/* alloc a new buffer ptr to collect the timestamps. */
builder->SetInsertPoint(&*F.begin()->begin());
llvm::Constant *profilingBuf = module->getGlobalVariable("__gen_ocl_profiling_buf");
if (!profilingBuf) {
profilingBuf = new GlobalVariable(*module, intTy, false,
GlobalVariable::ExternalLinkage, nullptr, StringRef("__gen_ocl_profiling_buf"),
nullptr, GlobalVariable::NotThreadLocal, 1);
}
changed = true;
for (llvm::Function::iterator B = F.begin(), BE = F.end(); B != BE; B++) {
/* Skip the empty blocks. */
if (B->empty())
continue;
BasicBlock::iterator instI = B->begin();
for ( ; instI != B->end(); instI++) {
if (dyn_cast(instI))
continue;
if (dyn_cast(instI)) {
instI++;
GBE_ASSERT(instI == B->end());
break;
}
if (dyn_cast(instI)) {
instI++;
GBE_ASSERT(instI == B->end());
break;
}
break;
}
if (instI == B->end())
continue;
if (pointNum >= 20) // To many timestamp.
continue;
// Insert the first one at beginning of not PHI.
builder->SetInsertPoint(&*instI);
/* Add the timestamp store function call. */
// __gen_ocl_store_timestamp(int nth, int type);
Value *Args[2] = {ConstantInt::get(intTy, pointNum++), ConstantInt::get(intTy, profilingType)};
#if LLVM_VERSION_MAJOR * 10 + LLVM_VERSION_MINOR >= 50
builder->CreateCall(cast(module->getOrInsertFunction(
"__gen_ocl_calc_timestamp", Type::getVoidTy(module->getContext()),
IntegerType::getInt32Ty(module->getContext()),
IntegerType::getInt32Ty(module->getContext()))),
ArrayRef(Args));
#else
builder->CreateCall(cast(module->getOrInsertFunction(
"__gen_ocl_calc_timestamp", Type::getVoidTy(module->getContext()),
IntegerType::getInt32Ty(module->getContext()),
IntegerType::getInt32Ty(module->getContext()), nullptr)),
ArrayRef(Args));
#endif
}
/* We insert one store_profiling at the end of the last block to hold the place. */
llvm::Function::iterator BE = F.end();
BE--;
BasicBlock::iterator retInst = BE->end();
retInst--;
builder->SetInsertPoint(&*retInst);
Value *Args2[2] = {profilingBuf, ConstantInt::get(intTy, profilingType)};
#if LLVM_VERSION_MAJOR * 10 + LLVM_VERSION_MINOR >= 50
builder->CreateCall(cast(module->getOrInsertFunction(
"__gen_ocl_store_profiling", Type::getVoidTy(module->getContext()),
ptrTy,
IntegerType::getInt32Ty(module->getContext()))),
ArrayRef(Args2));
#else
builder->CreateCall(cast(module->getOrInsertFunction(
"__gen_ocl_store_profiling", Type::getVoidTy(module->getContext()),
ptrTy,
IntegerType::getInt32Ty(module->getContext()), nullptr)),
ArrayRef(Args2));
#endif
delete builder;
return changed;
}
FunctionPass* createProfilingInserterPass(int profilingType, ir::Unit &unit)
{
unit.setInProfilingMode(true);
return new ProfilingInserter(profilingType);
}
char ProfilingInserter::ID = 0;
} // end namespace