//===-- 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 "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 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; bool mChanged; SmallVector 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(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(op); if (GEPinst) { GlobalVariable *GVar = dyn_cast(GEPinst->getOperand(0)); std::string str = "unknown"; if (GVar && GVar->hasInitializer()) { ConstantDataArray *CA = dyn_cast(GVar->getInitializer()); str = (CA->isString() ? CA->getAsString() : "unknown"); } uint64_t id = (uint64_t)mMFI->addPrintfString(str, getAnalysis().getMF() .getMMI().getObjFileInfo().get_printf_offset()); std::string name = "___dumpStringID"; Function *nF = NULL; std::vector 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::getInt32Ty(oType->getContext())); } else { iType = dyn_cast( 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::getInt64Ty(oType->getContext())); break; case 8: if (eleCount >= 8) { eleCount = totalSize / 64; iType = dyn_cast( Type::getInt64Ty(oType->getContext())); } else if (eleCount >= 4) { eleCount = 1; iType = dyn_cast( Type::getInt32Ty(oType->getContext())); } else { eleCount = 1; iType = dyn_cast( Type::getInt16Ty(oType->getContext())); } break; case 16: if (eleCount >= 4) { eleCount = totalSize / 64; iType = dyn_cast( Type::getInt64Ty(oType->getContext())); } else { eleCount = 1; iType = dyn_cast( Type::getInt32Ty(oType->getContext())); } break; } if (eleCount > 1) { iType = dyn_cast( 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(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 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; mMFI = getAnalysis().getMF() .getInfo(); 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(); FunctionPass::getAnalysisUsage(AU); AU.setPreservesAll(); }