blob: 95614f477c0eab3e25f03ebbf15091ea6345f8f9 [file] [log] [blame]
//===-- AMDILPrintfConvert.cpp - Printf Conversion pass --===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//==-----------------------------------------------------------------------===//
#define DEBUG_TYPE "PrintfConvert"
#ifdef DEBUG
#define DEBUGME (DebugFlag && isCurrentDebugType(DEBUG_TYPE))
#else
#define DEBUGME 0
#endif
#include "AMDILAlgorithms.tpp"
#include "AMDILKernelManager.h"
#include "AMDILMachineFunctionInfo.h"
#include "AMDILModuleInfo.h"
#include "AMDILTargetMachine.h"
#include "AMDILUtilityFunctions.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineFunctionAnalysis.h"
#include "llvm/CodeGen/Passes.h"
#include "llvm/GlobalVariable.h"
#include "llvm/Instructions.h"
#include "llvm/Module.h"
#include "llvm/Type.h"
#include <cstdio>
using namespace llvm;
namespace
{
class LLVM_LIBRARY_VISIBILITY AMDILPrintfConvert : public FunctionPass
{
public:
TargetMachine &TM;
static char ID;
AMDILPrintfConvert(TargetMachine &tm AMDIL_OPT_LEVEL_DECL);
~AMDILPrintfConvert();
const char* getPassName() const;
bool runOnFunction(Function &F);
bool doInitialization(Module &M);
bool doFinalization(Module &M);
void getAnalysisUsage(AnalysisUsage &AU) const;
private:
bool expandPrintf(BasicBlock::iterator *bbb);
AMDILMachineFunctionInfo *mMFI;
AMDILKernelManager *mKM;
bool mChanged;
SmallVector<int64_t, DEFAULT_VEC_SLOTS> bVecMap;
};
char AMDILPrintfConvert::ID = 0;
} // anonymouse namespace
namespace llvm
{
FunctionPass*
createAMDILPrintfConvert(TargetMachine &tm AMDIL_OPT_LEVEL_DECL)
{
return new AMDILPrintfConvert(tm AMDIL_OPT_LEVEL_VAR);
}
} // llvm namespace
AMDILPrintfConvert::AMDILPrintfConvert(TargetMachine &tm AMDIL_OPT_LEVEL_DECL)
: FunctionPass(ID), TM(tm)
{
}
AMDILPrintfConvert::~AMDILPrintfConvert()
{
}
bool
AMDILPrintfConvert::expandPrintf(BasicBlock::iterator *bbb)
{
Instruction *inst = (*bbb);
CallInst *CI = dyn_cast<CallInst>(inst);
if (!CI) {
return false;
}
int num_ops = CI->getNumOperands();
if (!num_ops) {
return false;
}
if (CI->getOperand(num_ops - 1)->getName() != "printf") {
return false;
}
Function *mF = inst->getParent()->getParent();
uint64_t bytes = 0;
mChanged = true;
if (num_ops == 1) {
++(*bbb);
Constant *newConst = ConstantInt::getSigned(CI->getType(), bytes);
CI->replaceAllUsesWith(newConst);
CI->eraseFromParent();
return mChanged;
}
// Deal with the string here
Value *op = CI->getOperand(0);
ConstantExpr *GEPinst = dyn_cast<ConstantExpr>(op);
if (GEPinst) {
GlobalVariable *GVar
= dyn_cast<GlobalVariable>(GEPinst->getOperand(0));
std::string str = "unknown";
if (GVar && GVar->hasInitializer()) {
ConstantDataArray *CA
= dyn_cast<ConstantDataArray>(GVar->getInitializer());
str = (CA->isString() ? CA->getAsString() : "unknown");
}
uint64_t id = (uint64_t)mMFI->addPrintfString(str,
getAnalysis<MachineFunctionAnalysis>().getMF()
.getMMI().getObjFileInfo<AMDILModuleInfo>().get_printf_offset());
std::string name = "___dumpStringID";
Function *nF = NULL;
std::vector<Type*> types;
types.push_back(Type::getInt32Ty(mF->getContext()));
nF = mF->getParent()->getFunction(name);
if (!nF) {
nF = Function::Create(
FunctionType::get(
Type::getVoidTy(mF->getContext()), types, false),
GlobalValue::ExternalLinkage,
name, mF->getParent());
}
Constant *C = ConstantInt::get(
Type::getInt32Ty(mF->getContext()), id, false);
CallInst *nCI = CallInst::Create(nF, C);
nCI->insertBefore(CI);
bytes = strlen(str.data());
for (uint32_t x = 1, y = num_ops - 1; x < y; ++x) {
op = CI->getOperand(x);
Type *oType = op->getType();
uint32_t eleCount = getNumElements(oType);
uint32_t eleSize = (uint32_t)GET_SCALAR_SIZE(oType);
if (!eleSize) {
// Default size is 32bits.
eleSize = 32;
}
if (!eleCount) {
// Default num elements is 1.
eleCount = 1;
}
uint32_t totalSize = eleCount * eleSize;
mMFI->addPrintfOperand(str, (x - 1),
(uint32_t)totalSize);
}
}
for (uint32_t x = 1, y = num_ops - 1; x < y; ++x) {
op = CI->getOperand(x);
Type *oType = op->getType();
if (oType->isFPOrFPVectorTy()
&& (oType->getTypeID() != Type::VectorTyID)) {
Type *iType = NULL;
if (oType->isFloatTy()) {
iType = dyn_cast<Type>(
Type::getInt32Ty(oType->getContext()));
} else {
iType = dyn_cast<Type>(
Type::getInt64Ty(oType->getContext()));
}
op = new BitCastInst(op, iType, "printfBitCast", CI);
} else if (oType->getTypeID() == Type::VectorTyID) {
Type *iType = NULL;
uint32_t eleCount = getNumElements(oType);
uint32_t eleSize = (uint32_t)GET_SCALAR_SIZE(oType);
uint32_t totalSize = eleCount * eleSize;
switch (eleSize) {
default:
eleCount = totalSize / 64;
iType = dyn_cast<Type>(
Type::getInt64Ty(oType->getContext()));
break;
case 8:
if (eleCount >= 8) {
eleCount = totalSize / 64;
iType = dyn_cast<Type>(
Type::getInt64Ty(oType->getContext()));
} else if (eleCount >= 4) {
eleCount = 1;
iType = dyn_cast<Type>(
Type::getInt32Ty(oType->getContext()));
} else {
eleCount = 1;
iType = dyn_cast<Type>(
Type::getInt16Ty(oType->getContext()));
}
break;
case 16:
if (eleCount >= 4) {
eleCount = totalSize / 64;
iType = dyn_cast<Type>(
Type::getInt64Ty(oType->getContext()));
} else {
eleCount = 1;
iType = dyn_cast<Type>(
Type::getInt32Ty(oType->getContext()));
}
break;
}
if (eleCount > 1) {
iType = dyn_cast<Type>(
VectorType::get(iType, eleCount));
}
op = new BitCastInst(op, iType, "printfBitCast", CI);
}
char buffer[256];
uint32_t size = (uint32_t)GET_SCALAR_SIZE(oType);
if (size) {
sprintf(buffer, "___dumpBytes_v%db%u",
1,
(uint32_t)getNumElements(oType) * (uint32_t)size);
} else {
const PointerType *PT = dyn_cast<PointerType>(oType);
if (PT->getAddressSpace() == 0 &&
GET_SCALAR_SIZE(PT->getContainedType(0)) == 8
&& getNumElements(PT->getContainedType(0)) == 1) {
op = new BitCastInst(op,
Type::getInt8PtrTy(oType->getContext(),
AMDILAS::CONSTANT_ADDRESS),
"printfPtrCast", CI);
sprintf(buffer, "___dumpBytes_v%dbs", 1);
} else {
op = new PtrToIntInst(op,
Type::getInt32Ty(oType->getContext()),
"printfPtrCast", CI);
sprintf(buffer, "___dumpBytes_v1b32");
}
}
std::vector<Type*> types;
types.push_back(op->getType());
std::string name = buffer;
Function *nF = NULL;
nF = mF->getParent()->getFunction(name);
if (!nF) {
nF = Function::Create(
FunctionType::get(
Type::getVoidTy(mF->getContext()), types, false),
GlobalValue::ExternalLinkage,
name, mF->getParent());
}
CallInst *nCI = CallInst::Create(nF, op);
nCI->insertBefore(CI);
bytes += (size - 4);
}
++(*bbb);
Constant *newConst = ConstantInt::getSigned(CI->getType(), bytes);
CI->replaceAllUsesWith(newConst);
CI->eraseFromParent();
return mChanged;
}
bool
AMDILPrintfConvert::runOnFunction(Function &MF)
{
mChanged = false;
mKM = TM.getSubtarget<AMDILSubtarget>().getKernelManager();
mMFI = getAnalysis<MachineFunctionAnalysis>().getMF()
.getInfo<AMDILMachineFunctionInfo>();
bVecMap.clear();
safeNestedForEach(MF.begin(), MF.end(), MF.begin()->begin(),
std::bind1st(
std::mem_fun(
&AMDILPrintfConvert::expandPrintf), this));
return mChanged;
}
const char*
AMDILPrintfConvert::getPassName() const
{
return "AMDIL Printf Conversion Pass";
}
bool
AMDILPrintfConvert::doInitialization(Module &M)
{
return false;
}
bool
AMDILPrintfConvert::doFinalization(Module &M)
{
return false;
}
void
AMDILPrintfConvert::getAnalysisUsage(AnalysisUsage &AU) const
{
AU.addRequired<MachineFunctionAnalysis>();
FunctionPass::getAnalysisUsage(AU);
AU.setPreservesAll();
}