14c9c98f3SStanislav Mekhanoshin //=== AMDGPUPrintfRuntimeBinding.cpp - OpenCL printf implementation -------===//
24c9c98f3SStanislav Mekhanoshin //
34c9c98f3SStanislav Mekhanoshin // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
44c9c98f3SStanislav Mekhanoshin // See https://llvm.org/LICENSE.txt for license information.
54c9c98f3SStanislav Mekhanoshin // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
64c9c98f3SStanislav Mekhanoshin //
74c9c98f3SStanislav Mekhanoshin //===----------------------------------------------------------------------===//
84c9c98f3SStanislav Mekhanoshin // \file
94c9c98f3SStanislav Mekhanoshin //
104c9c98f3SStanislav Mekhanoshin // The pass bind printfs to a kernel arg pointer that will be bound to a buffer
114c9c98f3SStanislav Mekhanoshin // later by the runtime.
124c9c98f3SStanislav Mekhanoshin //
134c9c98f3SStanislav Mekhanoshin // This pass traverses the functions in the module and converts
144c9c98f3SStanislav Mekhanoshin // each call to printf to a sequence of operations that
154c9c98f3SStanislav Mekhanoshin // store the following into the printf buffer:
164c9c98f3SStanislav Mekhanoshin // - format string (passed as a module's metadata unique ID)
174c9c98f3SStanislav Mekhanoshin // - bitwise copies of printf arguments
184c9c98f3SStanislav Mekhanoshin // The backend passes will need to store metadata in the kernel
194c9c98f3SStanislav Mekhanoshin //===----------------------------------------------------------------------===//
204c9c98f3SStanislav Mekhanoshin 
214c9c98f3SStanislav Mekhanoshin #include "AMDGPU.h"
22ffe8720aSserge-sans-paille #include "llvm/ADT/Triple.h"
234c9c98f3SStanislav Mekhanoshin #include "llvm/Analysis/InstructionSimplify.h"
244c9c98f3SStanislav Mekhanoshin #include "llvm/Analysis/TargetLibraryInfo.h"
254c9c98f3SStanislav Mekhanoshin #include "llvm/IR/Dominators.h"
264c9c98f3SStanislav Mekhanoshin #include "llvm/IR/IRBuilder.h"
274c9c98f3SStanislav Mekhanoshin #include "llvm/IR/Instructions.h"
2805da2fe5SReid Kleckner #include "llvm/InitializePasses.h"
294c9c98f3SStanislav Mekhanoshin #include "llvm/Transforms/Utils/BasicBlockUtils.h"
306a87e9b0Sdfukalov 
314c9c98f3SStanislav Mekhanoshin using namespace llvm;
324c9c98f3SStanislav Mekhanoshin 
334c9c98f3SStanislav Mekhanoshin #define DEBUG_TYPE "printfToRuntime"
344c9c98f3SStanislav Mekhanoshin #define DWORD_ALIGN 4
354c9c98f3SStanislav Mekhanoshin 
364c9c98f3SStanislav Mekhanoshin namespace {
37fd323a89SArthur Eubanks class AMDGPUPrintfRuntimeBinding final : public ModulePass {
384c9c98f3SStanislav Mekhanoshin 
394c9c98f3SStanislav Mekhanoshin public:
404c9c98f3SStanislav Mekhanoshin   static char ID;
414c9c98f3SStanislav Mekhanoshin 
424c9c98f3SStanislav Mekhanoshin   explicit AMDGPUPrintfRuntimeBinding();
434c9c98f3SStanislav Mekhanoshin 
444c9c98f3SStanislav Mekhanoshin private:
454c9c98f3SStanislav Mekhanoshin   bool runOnModule(Module &M) override;
464c9c98f3SStanislav Mekhanoshin 
getAnalysisUsage(AnalysisUsage & AU) const474c9c98f3SStanislav Mekhanoshin   void getAnalysisUsage(AnalysisUsage &AU) const override {
484c9c98f3SStanislav Mekhanoshin     AU.addRequired<TargetLibraryInfoWrapperPass>();
494c9c98f3SStanislav Mekhanoshin     AU.addRequired<DominatorTreeWrapperPass>();
504c9c98f3SStanislav Mekhanoshin   }
51fd323a89SArthur Eubanks };
524c9c98f3SStanislav Mekhanoshin 
53fd323a89SArthur Eubanks class AMDGPUPrintfRuntimeBindingImpl {
54fd323a89SArthur Eubanks public:
AMDGPUPrintfRuntimeBindingImpl(function_ref<const DominatorTree & (Function &)> GetDT,function_ref<const TargetLibraryInfo & (Function &)> GetTLI)55fd323a89SArthur Eubanks   AMDGPUPrintfRuntimeBindingImpl(
56fd323a89SArthur Eubanks       function_ref<const DominatorTree &(Function &)> GetDT,
57fd323a89SArthur Eubanks       function_ref<const TargetLibraryInfo &(Function &)> GetTLI)
58fd323a89SArthur Eubanks       : GetDT(GetDT), GetTLI(GetTLI) {}
59fd323a89SArthur Eubanks   bool run(Module &M);
60fd323a89SArthur Eubanks 
61fd323a89SArthur Eubanks private:
62fd323a89SArthur Eubanks   void getConversionSpecifiers(SmallVectorImpl<char> &OpConvSpecifiers,
63fd323a89SArthur Eubanks                                StringRef fmt, size_t num_ops) const;
64fd323a89SArthur Eubanks 
65fd323a89SArthur Eubanks   bool shouldPrintAsStr(char Specifier, Type *OpType) const;
66fd323a89SArthur Eubanks   bool lowerPrintfForGpu(Module &M);
67fd323a89SArthur Eubanks 
simplify(Instruction * I,const TargetLibraryInfo * TLI,const DominatorTree * DT)68fd323a89SArthur Eubanks   Value *simplify(Instruction *I, const TargetLibraryInfo *TLI,
69fd323a89SArthur Eubanks                   const DominatorTree *DT) {
70*b8c2781fSSimon Moll     return simplifyInstruction(I, {*TD, TLI, DT});
714c9c98f3SStanislav Mekhanoshin   }
724c9c98f3SStanislav Mekhanoshin 
734c9c98f3SStanislav Mekhanoshin   const DataLayout *TD;
74fd323a89SArthur Eubanks   function_ref<const DominatorTree &(Function &)> GetDT;
75fd323a89SArthur Eubanks   function_ref<const TargetLibraryInfo &(Function &)> GetTLI;
76dafda610SJay Foad   SmallVector<CallInst *, 32> Printfs;
774c9c98f3SStanislav Mekhanoshin };
784c9c98f3SStanislav Mekhanoshin } // namespace
794c9c98f3SStanislav Mekhanoshin 
804c9c98f3SStanislav Mekhanoshin char AMDGPUPrintfRuntimeBinding::ID = 0;
814c9c98f3SStanislav Mekhanoshin 
824c9c98f3SStanislav Mekhanoshin INITIALIZE_PASS_BEGIN(AMDGPUPrintfRuntimeBinding,
834c9c98f3SStanislav Mekhanoshin                       "amdgpu-printf-runtime-binding", "AMDGPU Printf lowering",
844c9c98f3SStanislav Mekhanoshin                       false, false)
854c9c98f3SStanislav Mekhanoshin INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass)
864c9c98f3SStanislav Mekhanoshin INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
874c9c98f3SStanislav Mekhanoshin INITIALIZE_PASS_END(AMDGPUPrintfRuntimeBinding, "amdgpu-printf-runtime-binding",
884c9c98f3SStanislav Mekhanoshin                     "AMDGPU Printf lowering", false, false)
894c9c98f3SStanislav Mekhanoshin 
904c9c98f3SStanislav Mekhanoshin char &llvm::AMDGPUPrintfRuntimeBindingID = AMDGPUPrintfRuntimeBinding::ID;
914c9c98f3SStanislav Mekhanoshin 
924c9c98f3SStanislav Mekhanoshin namespace llvm {
createAMDGPUPrintfRuntimeBinding()934c9c98f3SStanislav Mekhanoshin ModulePass *createAMDGPUPrintfRuntimeBinding() {
944c9c98f3SStanislav Mekhanoshin   return new AMDGPUPrintfRuntimeBinding();
954c9c98f3SStanislav Mekhanoshin }
964c9c98f3SStanislav Mekhanoshin } // namespace llvm
974c9c98f3SStanislav Mekhanoshin 
AMDGPUPrintfRuntimeBinding()98fd323a89SArthur Eubanks AMDGPUPrintfRuntimeBinding::AMDGPUPrintfRuntimeBinding() : ModulePass(ID) {
994c9c98f3SStanislav Mekhanoshin   initializeAMDGPUPrintfRuntimeBindingPass(*PassRegistry::getPassRegistry());
1004c9c98f3SStanislav Mekhanoshin }
1014c9c98f3SStanislav Mekhanoshin 
getConversionSpecifiers(SmallVectorImpl<char> & OpConvSpecifiers,StringRef Fmt,size_t NumOps) const102fd323a89SArthur Eubanks void AMDGPUPrintfRuntimeBindingImpl::getConversionSpecifiers(
1034c9c98f3SStanislav Mekhanoshin     SmallVectorImpl<char> &OpConvSpecifiers, StringRef Fmt,
1044c9c98f3SStanislav Mekhanoshin     size_t NumOps) const {
1054c9c98f3SStanislav Mekhanoshin   // not all format characters are collected.
1064c9c98f3SStanislav Mekhanoshin   // At this time the format characters of interest
1074c9c98f3SStanislav Mekhanoshin   // are %p and %s, which use to know if we
1084c9c98f3SStanislav Mekhanoshin   // are either storing a literal string or a
1094c9c98f3SStanislav Mekhanoshin   // pointer to the printf buffer.
1104c9c98f3SStanislav Mekhanoshin   static const char ConvSpecifiers[] = "cdieEfgGaosuxXp";
1114c9c98f3SStanislav Mekhanoshin   size_t CurFmtSpecifierIdx = 0;
1124c9c98f3SStanislav Mekhanoshin   size_t PrevFmtSpecifierIdx = 0;
1134c9c98f3SStanislav Mekhanoshin 
1144c9c98f3SStanislav Mekhanoshin   while ((CurFmtSpecifierIdx = Fmt.find_first_of(
1154c9c98f3SStanislav Mekhanoshin               ConvSpecifiers, CurFmtSpecifierIdx)) != StringRef::npos) {
1164c9c98f3SStanislav Mekhanoshin     bool ArgDump = false;
1174c9c98f3SStanislav Mekhanoshin     StringRef CurFmt = Fmt.substr(PrevFmtSpecifierIdx,
1184c9c98f3SStanislav Mekhanoshin                                   CurFmtSpecifierIdx - PrevFmtSpecifierIdx);
1194c9c98f3SStanislav Mekhanoshin     size_t pTag = CurFmt.find_last_of("%");
1204c9c98f3SStanislav Mekhanoshin     if (pTag != StringRef::npos) {
1214c9c98f3SStanislav Mekhanoshin       ArgDump = true;
1224c9c98f3SStanislav Mekhanoshin       while (pTag && CurFmt[--pTag] == '%') {
1234c9c98f3SStanislav Mekhanoshin         ArgDump = !ArgDump;
1244c9c98f3SStanislav Mekhanoshin       }
1254c9c98f3SStanislav Mekhanoshin     }
1264c9c98f3SStanislav Mekhanoshin 
1274c9c98f3SStanislav Mekhanoshin     if (ArgDump)
1284c9c98f3SStanislav Mekhanoshin       OpConvSpecifiers.push_back(Fmt[CurFmtSpecifierIdx]);
1294c9c98f3SStanislav Mekhanoshin 
1304c9c98f3SStanislav Mekhanoshin     PrevFmtSpecifierIdx = ++CurFmtSpecifierIdx;
1314c9c98f3SStanislav Mekhanoshin   }
1324c9c98f3SStanislav Mekhanoshin }
1334c9c98f3SStanislav Mekhanoshin 
shouldPrintAsStr(char Specifier,Type * OpType) const134fd323a89SArthur Eubanks bool AMDGPUPrintfRuntimeBindingImpl::shouldPrintAsStr(char Specifier,
1354c9c98f3SStanislav Mekhanoshin                                                       Type *OpType) const {
1364c9c98f3SStanislav Mekhanoshin   if (Specifier != 's')
1374c9c98f3SStanislav Mekhanoshin     return false;
1384c9c98f3SStanislav Mekhanoshin   const PointerType *PT = dyn_cast<PointerType>(OpType);
1394c9c98f3SStanislav Mekhanoshin   if (!PT || PT->getAddressSpace() != AMDGPUAS::CONSTANT_ADDRESS)
1404c9c98f3SStanislav Mekhanoshin     return false;
1414c9c98f3SStanislav Mekhanoshin   Type *ElemType = PT->getContainedType(0);
1424c9c98f3SStanislav Mekhanoshin   if (ElemType->getTypeID() != Type::IntegerTyID)
1434c9c98f3SStanislav Mekhanoshin     return false;
1444c9c98f3SStanislav Mekhanoshin   IntegerType *ElemIType = cast<IntegerType>(ElemType);
1454c9c98f3SStanislav Mekhanoshin   return ElemIType->getBitWidth() == 8;
1464c9c98f3SStanislav Mekhanoshin }
1474c9c98f3SStanislav Mekhanoshin 
lowerPrintfForGpu(Module & M)148fd323a89SArthur Eubanks bool AMDGPUPrintfRuntimeBindingImpl::lowerPrintfForGpu(Module &M) {
1494c9c98f3SStanislav Mekhanoshin   LLVMContext &Ctx = M.getContext();
1504c9c98f3SStanislav Mekhanoshin   IRBuilder<> Builder(Ctx);
1514c9c98f3SStanislav Mekhanoshin   Type *I32Ty = Type::getInt32Ty(Ctx);
1524c9c98f3SStanislav Mekhanoshin   unsigned UniqID = 0;
153dc6e8dfdSJacob Lambert   // NB: This is important for this string size to be divisible by 4
1544c9c98f3SStanislav Mekhanoshin   const char NonLiteralStr[4] = "???";
1554c9c98f3SStanislav Mekhanoshin 
156dafda610SJay Foad   for (auto CI : Printfs) {
157c1e32b3fSKazu Hirata     unsigned NumOps = CI->arg_size();
1584c9c98f3SStanislav Mekhanoshin 
1594c9c98f3SStanislav Mekhanoshin     SmallString<16> OpConvSpecifiers;
1604c9c98f3SStanislav Mekhanoshin     Value *Op = CI->getArgOperand(0);
1614c9c98f3SStanislav Mekhanoshin 
1624c9c98f3SStanislav Mekhanoshin     if (auto LI = dyn_cast<LoadInst>(Op)) {
1634c9c98f3SStanislav Mekhanoshin       Op = LI->getPointerOperand();
1644c9c98f3SStanislav Mekhanoshin       for (auto Use : Op->users()) {
1654c9c98f3SStanislav Mekhanoshin         if (auto SI = dyn_cast<StoreInst>(Use)) {
1664c9c98f3SStanislav Mekhanoshin           Op = SI->getValueOperand();
1674c9c98f3SStanislav Mekhanoshin           break;
1684c9c98f3SStanislav Mekhanoshin         }
1694c9c98f3SStanislav Mekhanoshin       }
1704c9c98f3SStanislav Mekhanoshin     }
1714c9c98f3SStanislav Mekhanoshin 
1724c9c98f3SStanislav Mekhanoshin     if (auto I = dyn_cast<Instruction>(Op)) {
173fd323a89SArthur Eubanks       Value *Op_simplified =
174fd323a89SArthur Eubanks           simplify(I, &GetTLI(*I->getFunction()), &GetDT(*I->getFunction()));
1754c9c98f3SStanislav Mekhanoshin       if (Op_simplified)
1764c9c98f3SStanislav Mekhanoshin         Op = Op_simplified;
1774c9c98f3SStanislav Mekhanoshin     }
1784c9c98f3SStanislav Mekhanoshin 
1794c9c98f3SStanislav Mekhanoshin     ConstantExpr *ConstExpr = dyn_cast<ConstantExpr>(Op);
1804c9c98f3SStanislav Mekhanoshin 
1814c9c98f3SStanislav Mekhanoshin     if (ConstExpr) {
1824c9c98f3SStanislav Mekhanoshin       GlobalVariable *GVar = dyn_cast<GlobalVariable>(ConstExpr->getOperand(0));
1834c9c98f3SStanislav Mekhanoshin 
1844c9c98f3SStanislav Mekhanoshin       StringRef Str("unknown");
1854c9c98f3SStanislav Mekhanoshin       if (GVar && GVar->hasInitializer()) {
186ee3da895SSimon Pilgrim         auto *Init = GVar->getInitializer();
187ee3da895SSimon Pilgrim         if (auto *CA = dyn_cast<ConstantDataArray>(Init)) {
1884c9c98f3SStanislav Mekhanoshin           if (CA->isString())
1894c9c98f3SStanislav Mekhanoshin             Str = CA->getAsCString();
1904c9c98f3SStanislav Mekhanoshin         } else if (isa<ConstantAggregateZero>(Init)) {
1914c9c98f3SStanislav Mekhanoshin           Str = "";
1924c9c98f3SStanislav Mekhanoshin         }
1934c9c98f3SStanislav Mekhanoshin         //
1944c9c98f3SStanislav Mekhanoshin         // we need this call to ascertain
1954c9c98f3SStanislav Mekhanoshin         // that we are printing a string
1964c9c98f3SStanislav Mekhanoshin         // or a pointer. It takes out the
1974c9c98f3SStanislav Mekhanoshin         // specifiers and fills up the first
1984c9c98f3SStanislav Mekhanoshin         // arg
1994c9c98f3SStanislav Mekhanoshin         getConversionSpecifiers(OpConvSpecifiers, Str, NumOps - 1);
2004c9c98f3SStanislav Mekhanoshin       }
2014c9c98f3SStanislav Mekhanoshin       // Add metadata for the string
2024c9c98f3SStanislav Mekhanoshin       std::string AStreamHolder;
2034c9c98f3SStanislav Mekhanoshin       raw_string_ostream Sizes(AStreamHolder);
2044c9c98f3SStanislav Mekhanoshin       int Sum = DWORD_ALIGN;
205c1e32b3fSKazu Hirata       Sizes << CI->arg_size() - 1;
2064c9c98f3SStanislav Mekhanoshin       Sizes << ':';
207c1e32b3fSKazu Hirata       for (unsigned ArgCount = 1;
208c1e32b3fSKazu Hirata            ArgCount < CI->arg_size() && ArgCount <= OpConvSpecifiers.size();
2094c9c98f3SStanislav Mekhanoshin            ArgCount++) {
2104c9c98f3SStanislav Mekhanoshin         Value *Arg = CI->getArgOperand(ArgCount);
2114c9c98f3SStanislav Mekhanoshin         Type *ArgType = Arg->getType();
2124c9c98f3SStanislav Mekhanoshin         unsigned ArgSize = TD->getTypeAllocSizeInBits(ArgType);
2134c9c98f3SStanislav Mekhanoshin         ArgSize = ArgSize / 8;
2144c9c98f3SStanislav Mekhanoshin         //
2154c9c98f3SStanislav Mekhanoshin         // ArgSize by design should be a multiple of DWORD_ALIGN,
2164c9c98f3SStanislav Mekhanoshin         // expand the arguments that do not follow this rule.
2174c9c98f3SStanislav Mekhanoshin         //
2184c9c98f3SStanislav Mekhanoshin         if (ArgSize % DWORD_ALIGN != 0) {
2194c9c98f3SStanislav Mekhanoshin           llvm::Type *ResType = llvm::Type::getInt32Ty(Ctx);
2203254a001SChristopher Tetreault           auto *LLVMVecType = llvm::dyn_cast<llvm::FixedVectorType>(ArgType);
2214c9c98f3SStanislav Mekhanoshin           int NumElem = LLVMVecType ? LLVMVecType->getNumElements() : 1;
2224c9c98f3SStanislav Mekhanoshin           if (LLVMVecType && NumElem > 1)
2233254a001SChristopher Tetreault             ResType = llvm::FixedVectorType::get(ResType, NumElem);
2244c9c98f3SStanislav Mekhanoshin           Builder.SetInsertPoint(CI);
2254c9c98f3SStanislav Mekhanoshin           Builder.SetCurrentDebugLocation(CI->getDebugLoc());
2264c9c98f3SStanislav Mekhanoshin           if (OpConvSpecifiers[ArgCount - 1] == 'x' ||
2274c9c98f3SStanislav Mekhanoshin               OpConvSpecifiers[ArgCount - 1] == 'X' ||
2284c9c98f3SStanislav Mekhanoshin               OpConvSpecifiers[ArgCount - 1] == 'u' ||
2294c9c98f3SStanislav Mekhanoshin               OpConvSpecifiers[ArgCount - 1] == 'o')
2304c9c98f3SStanislav Mekhanoshin             Arg = Builder.CreateZExt(Arg, ResType);
2314c9c98f3SStanislav Mekhanoshin           else
2324c9c98f3SStanislav Mekhanoshin             Arg = Builder.CreateSExt(Arg, ResType);
2334c9c98f3SStanislav Mekhanoshin           ArgType = Arg->getType();
2344c9c98f3SStanislav Mekhanoshin           ArgSize = TD->getTypeAllocSizeInBits(ArgType);
2354c9c98f3SStanislav Mekhanoshin           ArgSize = ArgSize / 8;
2364c9c98f3SStanislav Mekhanoshin           CI->setOperand(ArgCount, Arg);
2374c9c98f3SStanislav Mekhanoshin         }
2384c9c98f3SStanislav Mekhanoshin         if (OpConvSpecifiers[ArgCount - 1] == 'f') {
2394c9c98f3SStanislav Mekhanoshin           ConstantFP *FpCons = dyn_cast<ConstantFP>(Arg);
2404c9c98f3SStanislav Mekhanoshin           if (FpCons)
2414c9c98f3SStanislav Mekhanoshin             ArgSize = 4;
2424c9c98f3SStanislav Mekhanoshin           else {
2434c9c98f3SStanislav Mekhanoshin             FPExtInst *FpExt = dyn_cast<FPExtInst>(Arg);
2444c9c98f3SStanislav Mekhanoshin             if (FpExt && FpExt->getType()->isDoubleTy() &&
2454c9c98f3SStanislav Mekhanoshin                 FpExt->getOperand(0)->getType()->isFloatTy())
2464c9c98f3SStanislav Mekhanoshin               ArgSize = 4;
2474c9c98f3SStanislav Mekhanoshin           }
2484c9c98f3SStanislav Mekhanoshin         }
2494c9c98f3SStanislav Mekhanoshin         if (shouldPrintAsStr(OpConvSpecifiers[ArgCount - 1], ArgType)) {
250ee3da895SSimon Pilgrim           if (auto *ConstExpr = dyn_cast<ConstantExpr>(Arg)) {
251ee3da895SSimon Pilgrim             auto *GV = dyn_cast<GlobalVariable>(ConstExpr->getOperand(0));
2524c9c98f3SStanislav Mekhanoshin             if (GV && GV->hasInitializer()) {
2534c9c98f3SStanislav Mekhanoshin               Constant *Init = GV->getInitializer();
254ee3da895SSimon Pilgrim               bool IsZeroValue = Init->isZeroValue();
255ee3da895SSimon Pilgrim               auto *CA = dyn_cast<ConstantDataArray>(Init);
256ee3da895SSimon Pilgrim               if (IsZeroValue || (CA && CA->isString())) {
257ee3da895SSimon Pilgrim                 size_t SizeStr =
258ee3da895SSimon Pilgrim                     IsZeroValue ? 1 : (strlen(CA->getAsCString().data()) + 1);
2594c9c98f3SStanislav Mekhanoshin                 size_t Rem = SizeStr % DWORD_ALIGN;
2604c9c98f3SStanislav Mekhanoshin                 size_t NSizeStr = 0;
2614c9c98f3SStanislav Mekhanoshin                 LLVM_DEBUG(dbgs() << "Printf string original size = " << SizeStr
2624c9c98f3SStanislav Mekhanoshin                                   << '\n');
2634c9c98f3SStanislav Mekhanoshin                 if (Rem) {
2644c9c98f3SStanislav Mekhanoshin                   NSizeStr = SizeStr + (DWORD_ALIGN - Rem);
2654c9c98f3SStanislav Mekhanoshin                 } else {
2664c9c98f3SStanislav Mekhanoshin                   NSizeStr = SizeStr;
2674c9c98f3SStanislav Mekhanoshin                 }
2684c9c98f3SStanislav Mekhanoshin                 ArgSize = NSizeStr;
2694c9c98f3SStanislav Mekhanoshin               }
2704c9c98f3SStanislav Mekhanoshin             } else {
2714c9c98f3SStanislav Mekhanoshin               ArgSize = sizeof(NonLiteralStr);
2724c9c98f3SStanislav Mekhanoshin             }
2734c9c98f3SStanislav Mekhanoshin           } else {
2744c9c98f3SStanislav Mekhanoshin             ArgSize = sizeof(NonLiteralStr);
2754c9c98f3SStanislav Mekhanoshin           }
2764c9c98f3SStanislav Mekhanoshin         }
2774c9c98f3SStanislav Mekhanoshin         LLVM_DEBUG(dbgs() << "Printf ArgSize (in buffer) = " << ArgSize
2784c9c98f3SStanislav Mekhanoshin                           << " for type: " << *ArgType << '\n');
2794c9c98f3SStanislav Mekhanoshin         Sizes << ArgSize << ':';
2804c9c98f3SStanislav Mekhanoshin         Sum += ArgSize;
2814c9c98f3SStanislav Mekhanoshin       }
2824c9c98f3SStanislav Mekhanoshin       LLVM_DEBUG(dbgs() << "Printf format string in source = " << Str.str()
2834c9c98f3SStanislav Mekhanoshin                         << '\n');
284262dd1e4SKazu Hirata       for (char C : Str) {
2854c9c98f3SStanislav Mekhanoshin         // Rest of the C escape sequences (e.g. \') are handled correctly
2864c9c98f3SStanislav Mekhanoshin         // by the MDParser
287262dd1e4SKazu Hirata         switch (C) {
2884c9c98f3SStanislav Mekhanoshin         case '\a':
2894c9c98f3SStanislav Mekhanoshin           Sizes << "\\a";
2904c9c98f3SStanislav Mekhanoshin           break;
2914c9c98f3SStanislav Mekhanoshin         case '\b':
2924c9c98f3SStanislav Mekhanoshin           Sizes << "\\b";
2934c9c98f3SStanislav Mekhanoshin           break;
2944c9c98f3SStanislav Mekhanoshin         case '\f':
2954c9c98f3SStanislav Mekhanoshin           Sizes << "\\f";
2964c9c98f3SStanislav Mekhanoshin           break;
2974c9c98f3SStanislav Mekhanoshin         case '\n':
2984c9c98f3SStanislav Mekhanoshin           Sizes << "\\n";
2994c9c98f3SStanislav Mekhanoshin           break;
3004c9c98f3SStanislav Mekhanoshin         case '\r':
3014c9c98f3SStanislav Mekhanoshin           Sizes << "\\r";
3024c9c98f3SStanislav Mekhanoshin           break;
3034c9c98f3SStanislav Mekhanoshin         case '\v':
3044c9c98f3SStanislav Mekhanoshin           Sizes << "\\v";
3054c9c98f3SStanislav Mekhanoshin           break;
3064c9c98f3SStanislav Mekhanoshin         case ':':
3074c9c98f3SStanislav Mekhanoshin           // ':' cannot be scanned by Flex, as it is defined as a delimiter
3084c9c98f3SStanislav Mekhanoshin           // Replace it with it's octal representation \72
3094c9c98f3SStanislav Mekhanoshin           Sizes << "\\72";
3104c9c98f3SStanislav Mekhanoshin           break;
3114c9c98f3SStanislav Mekhanoshin         default:
312262dd1e4SKazu Hirata           Sizes << C;
3134c9c98f3SStanislav Mekhanoshin           break;
3144c9c98f3SStanislav Mekhanoshin         }
3154c9c98f3SStanislav Mekhanoshin       }
3164c9c98f3SStanislav Mekhanoshin 
3174c9c98f3SStanislav Mekhanoshin       // Insert the printf_alloc call
3184c9c98f3SStanislav Mekhanoshin       Builder.SetInsertPoint(CI);
3194c9c98f3SStanislav Mekhanoshin       Builder.SetCurrentDebugLocation(CI->getDebugLoc());
3204c9c98f3SStanislav Mekhanoshin 
3214c9c98f3SStanislav Mekhanoshin       AttributeList Attr = AttributeList::get(Ctx, AttributeList::FunctionIndex,
3224c9c98f3SStanislav Mekhanoshin                                               Attribute::NoUnwind);
3234c9c98f3SStanislav Mekhanoshin 
3244c9c98f3SStanislav Mekhanoshin       Type *SizetTy = Type::getInt32Ty(Ctx);
3254c9c98f3SStanislav Mekhanoshin 
3264c9c98f3SStanislav Mekhanoshin       Type *Tys_alloc[1] = {SizetTy};
327cfb94212SNikita Popov       Type *I8Ty = Type::getInt8Ty(Ctx);
328cfb94212SNikita Popov       Type *I8Ptr = PointerType::get(I8Ty, 1);
3294c9c98f3SStanislav Mekhanoshin       FunctionType *FTy_alloc = FunctionType::get(I8Ptr, Tys_alloc, false);
3304c9c98f3SStanislav Mekhanoshin       FunctionCallee PrintfAllocFn =
3314c9c98f3SStanislav Mekhanoshin           M.getOrInsertFunction(StringRef("__printf_alloc"), FTy_alloc, Attr);
3324c9c98f3SStanislav Mekhanoshin 
3334c9c98f3SStanislav Mekhanoshin       LLVM_DEBUG(dbgs() << "Printf metadata = " << Sizes.str() << '\n');
334c50faffbSKazu Hirata       std::string fmtstr = itostr(++UniqID) + ":" + Sizes.str();
3354c9c98f3SStanislav Mekhanoshin       MDString *fmtStrArray = MDString::get(Ctx, fmtstr);
3364c9c98f3SStanislav Mekhanoshin 
3374c9c98f3SStanislav Mekhanoshin       // Instead of creating global variables, the
3384c9c98f3SStanislav Mekhanoshin       // printf format strings are extracted
3394c9c98f3SStanislav Mekhanoshin       // and passed as metadata. This avoids
3404c9c98f3SStanislav Mekhanoshin       // polluting llvm's symbol tables in this module.
3414c9c98f3SStanislav Mekhanoshin       // Metadata is going to be extracted
3424c9c98f3SStanislav Mekhanoshin       // by the backend passes and inserted
3434c9c98f3SStanislav Mekhanoshin       // into the OpenCL binary as appropriate.
3444c9c98f3SStanislav Mekhanoshin       StringRef amd("llvm.printf.fmts");
3454c9c98f3SStanislav Mekhanoshin       NamedMDNode *metaD = M.getOrInsertNamedMetadata(amd);
3464c9c98f3SStanislav Mekhanoshin       MDNode *myMD = MDNode::get(Ctx, fmtStrArray);
3474c9c98f3SStanislav Mekhanoshin       metaD->addOperand(myMD);
3484c9c98f3SStanislav Mekhanoshin       Value *sumC = ConstantInt::get(SizetTy, Sum, false);
3494c9c98f3SStanislav Mekhanoshin       SmallVector<Value *, 1> alloc_args;
3504c9c98f3SStanislav Mekhanoshin       alloc_args.push_back(sumC);
3514c9c98f3SStanislav Mekhanoshin       CallInst *pcall =
3524c9c98f3SStanislav Mekhanoshin           CallInst::Create(PrintfAllocFn, alloc_args, "printf_alloc_fn", CI);
3534c9c98f3SStanislav Mekhanoshin 
3544c9c98f3SStanislav Mekhanoshin       //
3554c9c98f3SStanislav Mekhanoshin       // Insert code to split basicblock with a
3564c9c98f3SStanislav Mekhanoshin       // piece of hammock code.
3574c9c98f3SStanislav Mekhanoshin       // basicblock splits after buffer overflow check
3584c9c98f3SStanislav Mekhanoshin       //
3594c9c98f3SStanislav Mekhanoshin       ConstantPointerNull *zeroIntPtr =
360cfb94212SNikita Popov           ConstantPointerNull::get(PointerType::get(I8Ty, 1));
3610805e40aSSimon Pilgrim       auto *cmp = cast<ICmpInst>(Builder.CreateICmpNE(pcall, zeroIntPtr, ""));
3624c9c98f3SStanislav Mekhanoshin       if (!CI->use_empty()) {
3634c9c98f3SStanislav Mekhanoshin         Value *result =
3644c9c98f3SStanislav Mekhanoshin             Builder.CreateSExt(Builder.CreateNot(cmp), I32Ty, "printf_res");
3654c9c98f3SStanislav Mekhanoshin         CI->replaceAllUsesWith(result);
3664c9c98f3SStanislav Mekhanoshin       }
3674c9c98f3SStanislav Mekhanoshin       SplitBlock(CI->getParent(), cmp);
3684c9c98f3SStanislav Mekhanoshin       Instruction *Brnch =
3694c9c98f3SStanislav Mekhanoshin           SplitBlockAndInsertIfThen(cmp, cmp->getNextNode(), false);
3704c9c98f3SStanislav Mekhanoshin 
3714c9c98f3SStanislav Mekhanoshin       Builder.SetInsertPoint(Brnch);
3724c9c98f3SStanislav Mekhanoshin 
3734c9c98f3SStanislav Mekhanoshin       // store unique printf id in the buffer
3744c9c98f3SStanislav Mekhanoshin       //
37597a23ab2SSimon Pilgrim       GetElementPtrInst *BufferIdx = GetElementPtrInst::Create(
3769e225a2aSNikita Popov           I8Ty, pcall, ConstantInt::get(Ctx, APInt(32, 0)), "PrintBuffID",
3779e225a2aSNikita Popov           Brnch);
3784c9c98f3SStanislav Mekhanoshin 
3794c9c98f3SStanislav Mekhanoshin       Type *idPointer = PointerType::get(I32Ty, AMDGPUAS::GLOBAL_ADDRESS);
3804c9c98f3SStanislav Mekhanoshin       Value *id_gep_cast =
3814c9c98f3SStanislav Mekhanoshin           new BitCastInst(BufferIdx, idPointer, "PrintBuffIdCast", Brnch);
3824c9c98f3SStanislav Mekhanoshin 
38311aa3707SEli Friedman       new StoreInst(ConstantInt::get(I32Ty, UniqID), id_gep_cast, Brnch);
3844c9c98f3SStanislav Mekhanoshin 
3859e225a2aSNikita Popov       // 1st 4 bytes hold the printf_id
3864c9c98f3SStanislav Mekhanoshin       // the following GEP is the buffer pointer
3879e225a2aSNikita Popov       BufferIdx = GetElementPtrInst::Create(
3889e225a2aSNikita Popov           I8Ty, pcall, ConstantInt::get(Ctx, APInt(32, 4)), "PrintBuffGep",
3899e225a2aSNikita Popov           Brnch);
3904c9c98f3SStanislav Mekhanoshin 
3914c9c98f3SStanislav Mekhanoshin       Type *Int32Ty = Type::getInt32Ty(Ctx);
3924c9c98f3SStanislav Mekhanoshin       Type *Int64Ty = Type::getInt64Ty(Ctx);
393c1e32b3fSKazu Hirata       for (unsigned ArgCount = 1;
394c1e32b3fSKazu Hirata            ArgCount < CI->arg_size() && ArgCount <= OpConvSpecifiers.size();
3954c9c98f3SStanislav Mekhanoshin            ArgCount++) {
3964c9c98f3SStanislav Mekhanoshin         Value *Arg = CI->getArgOperand(ArgCount);
3974c9c98f3SStanislav Mekhanoshin         Type *ArgType = Arg->getType();
3984c9c98f3SStanislav Mekhanoshin         SmallVector<Value *, 32> WhatToStore;
3992dea3f12SChristopher Tetreault         if (ArgType->isFPOrFPVectorTy() && !isa<VectorType>(ArgType)) {
4004c9c98f3SStanislav Mekhanoshin           Type *IType = (ArgType->isFloatTy()) ? Int32Ty : Int64Ty;
4014c9c98f3SStanislav Mekhanoshin           if (OpConvSpecifiers[ArgCount - 1] == 'f') {
40297a23ab2SSimon Pilgrim             if (auto *FpCons = dyn_cast<ConstantFP>(Arg)) {
40397a23ab2SSimon Pilgrim               APFloat Val(FpCons->getValueAPF());
4044c9c98f3SStanislav Mekhanoshin               bool Lost = false;
4054c9c98f3SStanislav Mekhanoshin               Val.convert(APFloat::IEEEsingle(), APFloat::rmNearestTiesToEven,
4064c9c98f3SStanislav Mekhanoshin                           &Lost);
4074c9c98f3SStanislav Mekhanoshin               Arg = ConstantFP::get(Ctx, Val);
4084c9c98f3SStanislav Mekhanoshin               IType = Int32Ty;
40997a23ab2SSimon Pilgrim             } else if (auto *FpExt = dyn_cast<FPExtInst>(Arg)) {
41097a23ab2SSimon Pilgrim               if (FpExt->getType()->isDoubleTy() &&
4114c9c98f3SStanislav Mekhanoshin                   FpExt->getOperand(0)->getType()->isFloatTy()) {
4124c9c98f3SStanislav Mekhanoshin                 Arg = FpExt->getOperand(0);
4134c9c98f3SStanislav Mekhanoshin                 IType = Int32Ty;
4144c9c98f3SStanislav Mekhanoshin               }
4154c9c98f3SStanislav Mekhanoshin             }
4164c9c98f3SStanislav Mekhanoshin           }
4174c9c98f3SStanislav Mekhanoshin           Arg = new BitCastInst(Arg, IType, "PrintArgFP", Brnch);
4184c9c98f3SStanislav Mekhanoshin           WhatToStore.push_back(Arg);
4194c9c98f3SStanislav Mekhanoshin         } else if (ArgType->getTypeID() == Type::PointerTyID) {
4204c9c98f3SStanislav Mekhanoshin           if (shouldPrintAsStr(OpConvSpecifiers[ArgCount - 1], ArgType)) {
4214c9c98f3SStanislav Mekhanoshin             const char *S = NonLiteralStr;
42297a23ab2SSimon Pilgrim             if (auto *ConstExpr = dyn_cast<ConstantExpr>(Arg)) {
42397a23ab2SSimon Pilgrim               auto *GV = dyn_cast<GlobalVariable>(ConstExpr->getOperand(0));
4244c9c98f3SStanislav Mekhanoshin               if (GV && GV->hasInitializer()) {
4254c9c98f3SStanislav Mekhanoshin                 Constant *Init = GV->getInitializer();
426ee3da895SSimon Pilgrim                 bool IsZeroValue = Init->isZeroValue();
427ee3da895SSimon Pilgrim                 auto *CA = dyn_cast<ConstantDataArray>(Init);
428ee3da895SSimon Pilgrim                 if (IsZeroValue || (CA && CA->isString())) {
429ee3da895SSimon Pilgrim                   S = IsZeroValue ? "" : CA->getAsCString().data();
4304c9c98f3SStanislav Mekhanoshin                 }
4314c9c98f3SStanislav Mekhanoshin               }
4324c9c98f3SStanislav Mekhanoshin             }
4334c9c98f3SStanislav Mekhanoshin             size_t SizeStr = strlen(S) + 1;
4344c9c98f3SStanislav Mekhanoshin             size_t Rem = SizeStr % DWORD_ALIGN;
4354c9c98f3SStanislav Mekhanoshin             size_t NSizeStr = 0;
4364c9c98f3SStanislav Mekhanoshin             if (Rem) {
4374c9c98f3SStanislav Mekhanoshin               NSizeStr = SizeStr + (DWORD_ALIGN - Rem);
4384c9c98f3SStanislav Mekhanoshin             } else {
4394c9c98f3SStanislav Mekhanoshin               NSizeStr = SizeStr;
4404c9c98f3SStanislav Mekhanoshin             }
4414c9c98f3SStanislav Mekhanoshin             if (S[0]) {
4424c9c98f3SStanislav Mekhanoshin               char *MyNewStr = new char[NSizeStr]();
4434c9c98f3SStanislav Mekhanoshin               strcpy(MyNewStr, S);
4444c9c98f3SStanislav Mekhanoshin               int NumInts = NSizeStr / 4;
4454c9c98f3SStanislav Mekhanoshin               int CharC = 0;
4464c9c98f3SStanislav Mekhanoshin               while (NumInts) {
4474c9c98f3SStanislav Mekhanoshin                 int ANum = *(int *)(MyNewStr + CharC);
4484c9c98f3SStanislav Mekhanoshin                 CharC += 4;
4494c9c98f3SStanislav Mekhanoshin                 NumInts--;
4504c9c98f3SStanislav Mekhanoshin                 Value *ANumV = ConstantInt::get(Int32Ty, ANum, false);
4514c9c98f3SStanislav Mekhanoshin                 WhatToStore.push_back(ANumV);
4524c9c98f3SStanislav Mekhanoshin               }
4534c9c98f3SStanislav Mekhanoshin               delete[] MyNewStr;
4544c9c98f3SStanislav Mekhanoshin             } else {
4554c9c98f3SStanislav Mekhanoshin               // Empty string, give a hint to RT it is no NULL
4564c9c98f3SStanislav Mekhanoshin               Value *ANumV = ConstantInt::get(Int32Ty, 0xFFFFFF00, false);
4574c9c98f3SStanislav Mekhanoshin               WhatToStore.push_back(ANumV);
4584c9c98f3SStanislav Mekhanoshin             }
4594c9c98f3SStanislav Mekhanoshin           } else {
4604c9c98f3SStanislav Mekhanoshin             uint64_t Size = TD->getTypeAllocSizeInBits(ArgType);
4614c9c98f3SStanislav Mekhanoshin             assert((Size == 32 || Size == 64) && "unsupported size");
4624c9c98f3SStanislav Mekhanoshin             Type *DstType = (Size == 32) ? Int32Ty : Int64Ty;
4634c9c98f3SStanislav Mekhanoshin             Arg = new PtrToIntInst(Arg, DstType, "PrintArgPtr", Brnch);
4644c9c98f3SStanislav Mekhanoshin             WhatToStore.push_back(Arg);
4654c9c98f3SStanislav Mekhanoshin           }
4662dea3f12SChristopher Tetreault         } else if (isa<FixedVectorType>(ArgType)) {
4675a667c0eSKazu Hirata           Type *IType = nullptr;
4683254a001SChristopher Tetreault           uint32_t EleCount = cast<FixedVectorType>(ArgType)->getNumElements();
4694c9c98f3SStanislav Mekhanoshin           uint32_t EleSize = ArgType->getScalarSizeInBits();
4704c9c98f3SStanislav Mekhanoshin           uint32_t TotalSize = EleCount * EleSize;
4714c9c98f3SStanislav Mekhanoshin           if (EleCount == 3) {
472cc035d47SBenjamin Kramer             ShuffleVectorInst *Shuffle =
473cc035d47SBenjamin Kramer                 new ShuffleVectorInst(Arg, Arg, ArrayRef<int>{0, 1, 2, 2});
4744c9c98f3SStanislav Mekhanoshin             Shuffle->insertBefore(Brnch);
4754c9c98f3SStanislav Mekhanoshin             Arg = Shuffle;
4764c9c98f3SStanislav Mekhanoshin             ArgType = Arg->getType();
4774c9c98f3SStanislav Mekhanoshin             TotalSize += EleSize;
4784c9c98f3SStanislav Mekhanoshin           }
4794c9c98f3SStanislav Mekhanoshin           switch (EleSize) {
4804c9c98f3SStanislav Mekhanoshin           default:
4814c9c98f3SStanislav Mekhanoshin             EleCount = TotalSize / 64;
48297a23ab2SSimon Pilgrim             IType = Type::getInt64Ty(ArgType->getContext());
4834c9c98f3SStanislav Mekhanoshin             break;
4844c9c98f3SStanislav Mekhanoshin           case 8:
4854c9c98f3SStanislav Mekhanoshin             if (EleCount >= 8) {
4864c9c98f3SStanislav Mekhanoshin               EleCount = TotalSize / 64;
48797a23ab2SSimon Pilgrim               IType = Type::getInt64Ty(ArgType->getContext());
4884c9c98f3SStanislav Mekhanoshin             } else if (EleCount >= 3) {
4894c9c98f3SStanislav Mekhanoshin               EleCount = 1;
49097a23ab2SSimon Pilgrim               IType = Type::getInt32Ty(ArgType->getContext());
4914c9c98f3SStanislav Mekhanoshin             } else {
4924c9c98f3SStanislav Mekhanoshin               EleCount = 1;
49397a23ab2SSimon Pilgrim               IType = Type::getInt16Ty(ArgType->getContext());
4944c9c98f3SStanislav Mekhanoshin             }
4954c9c98f3SStanislav Mekhanoshin             break;
4964c9c98f3SStanislav Mekhanoshin           case 16:
4974c9c98f3SStanislav Mekhanoshin             if (EleCount >= 3) {
4984c9c98f3SStanislav Mekhanoshin               EleCount = TotalSize / 64;
49997a23ab2SSimon Pilgrim               IType = Type::getInt64Ty(ArgType->getContext());
5004c9c98f3SStanislav Mekhanoshin             } else {
5014c9c98f3SStanislav Mekhanoshin               EleCount = 1;
50297a23ab2SSimon Pilgrim               IType = Type::getInt32Ty(ArgType->getContext());
5034c9c98f3SStanislav Mekhanoshin             }
5044c9c98f3SStanislav Mekhanoshin             break;
5054c9c98f3SStanislav Mekhanoshin           }
5064c9c98f3SStanislav Mekhanoshin           if (EleCount > 1) {
507aad93654SChristopher Tetreault             IType = FixedVectorType::get(IType, EleCount);
5084c9c98f3SStanislav Mekhanoshin           }
5094c9c98f3SStanislav Mekhanoshin           Arg = new BitCastInst(Arg, IType, "PrintArgVect", Brnch);
5104c9c98f3SStanislav Mekhanoshin           WhatToStore.push_back(Arg);
5114c9c98f3SStanislav Mekhanoshin         } else {
5124c9c98f3SStanislav Mekhanoshin           WhatToStore.push_back(Arg);
5134c9c98f3SStanislav Mekhanoshin         }
514438315bfSStanislav Mekhanoshin         for (unsigned I = 0, E = WhatToStore.size(); I != E; ++I) {
515438315bfSStanislav Mekhanoshin           Value *TheBtCast = WhatToStore[I];
5164c9c98f3SStanislav Mekhanoshin           unsigned ArgSize =
5174c9c98f3SStanislav Mekhanoshin               TD->getTypeAllocSizeInBits(TheBtCast->getType()) / 8;
5184c9c98f3SStanislav Mekhanoshin           SmallVector<Value *, 1> BuffOffset;
5194c9c98f3SStanislav Mekhanoshin           BuffOffset.push_back(ConstantInt::get(I32Ty, ArgSize));
5204c9c98f3SStanislav Mekhanoshin 
5214c9c98f3SStanislav Mekhanoshin           Type *ArgPointer = PointerType::get(TheBtCast->getType(), 1);
5224c9c98f3SStanislav Mekhanoshin           Value *CastedGEP =
5234c9c98f3SStanislav Mekhanoshin               new BitCastInst(BufferIdx, ArgPointer, "PrintBuffPtrCast", Brnch);
5244c9c98f3SStanislav Mekhanoshin           StoreInst *StBuff = new StoreInst(TheBtCast, CastedGEP, Brnch);
5254c9c98f3SStanislav Mekhanoshin           LLVM_DEBUG(dbgs() << "inserting store to printf buffer:\n"
5264c9c98f3SStanislav Mekhanoshin                             << *StBuff << '\n');
5274c9c98f3SStanislav Mekhanoshin           (void)StBuff;
528c1e32b3fSKazu Hirata           if (I + 1 == E && ArgCount + 1 == CI->arg_size())
5294c9c98f3SStanislav Mekhanoshin             break;
530cfb94212SNikita Popov           BufferIdx = GetElementPtrInst::Create(I8Ty, BufferIdx, BuffOffset,
53197a23ab2SSimon Pilgrim                                                 "PrintBuffNextPtr", Brnch);
5324c9c98f3SStanislav Mekhanoshin           LLVM_DEBUG(dbgs() << "inserting gep to the printf buffer:\n"
5334c9c98f3SStanislav Mekhanoshin                             << *BufferIdx << '\n');
5344c9c98f3SStanislav Mekhanoshin         }
5354c9c98f3SStanislav Mekhanoshin       }
5364c9c98f3SStanislav Mekhanoshin     }
5374c9c98f3SStanislav Mekhanoshin   }
5384c9c98f3SStanislav Mekhanoshin 
5394c9c98f3SStanislav Mekhanoshin   // erase the printf calls
540dafda610SJay Foad   for (auto CI : Printfs)
5414c9c98f3SStanislav Mekhanoshin     CI->eraseFromParent();
5424c9c98f3SStanislav Mekhanoshin 
5434c9c98f3SStanislav Mekhanoshin   Printfs.clear();
5444c9c98f3SStanislav Mekhanoshin   return true;
5454c9c98f3SStanislav Mekhanoshin }
5464c9c98f3SStanislav Mekhanoshin 
run(Module & M)547fd323a89SArthur Eubanks bool AMDGPUPrintfRuntimeBindingImpl::run(Module &M) {
5484c9c98f3SStanislav Mekhanoshin   Triple TT(M.getTargetTriple());
5494c9c98f3SStanislav Mekhanoshin   if (TT.getArch() == Triple::r600)
5504c9c98f3SStanislav Mekhanoshin     return false;
5514c9c98f3SStanislav Mekhanoshin 
552dafda610SJay Foad   auto PrintfFunction = M.getFunction("printf");
553dafda610SJay Foad   if (!PrintfFunction)
554dafda610SJay Foad     return false;
555dafda610SJay Foad 
556dafda610SJay Foad   for (auto &U : PrintfFunction->uses()) {
557dafda610SJay Foad     if (auto *CI = dyn_cast<CallInst>(U.getUser())) {
558dafda610SJay Foad       if (CI->isCallee(&U))
559dafda610SJay Foad         Printfs.push_back(CI);
560dafda610SJay Foad     }
561dafda610SJay Foad   }
5624c9c98f3SStanislav Mekhanoshin 
5634c9c98f3SStanislav Mekhanoshin   if (Printfs.empty())
5644c9c98f3SStanislav Mekhanoshin     return false;
5654c9c98f3SStanislav Mekhanoshin 
5664c9c98f3SStanislav Mekhanoshin   TD = &M.getDataLayout();
567fd323a89SArthur Eubanks 
568fd323a89SArthur Eubanks   return lowerPrintfForGpu(M);
569fd323a89SArthur Eubanks }
570fd323a89SArthur Eubanks 
runOnModule(Module & M)571fd323a89SArthur Eubanks bool AMDGPUPrintfRuntimeBinding::runOnModule(Module &M) {
572fd323a89SArthur Eubanks   auto GetDT = [this](Function &F) -> DominatorTree & {
573fd323a89SArthur Eubanks     return this->getAnalysis<DominatorTreeWrapperPass>(F).getDomTree();
574fd323a89SArthur Eubanks   };
5759c27b59cSTeresa Johnson   auto GetTLI = [this](Function &F) -> TargetLibraryInfo & {
5769c27b59cSTeresa Johnson     return this->getAnalysis<TargetLibraryInfoWrapperPass>().getTLI(F);
5779c27b59cSTeresa Johnson   };
5784c9c98f3SStanislav Mekhanoshin 
579fd323a89SArthur Eubanks   return AMDGPUPrintfRuntimeBindingImpl(GetDT, GetTLI).run(M);
580fd323a89SArthur Eubanks }
581fd323a89SArthur Eubanks 
582fd323a89SArthur Eubanks PreservedAnalyses
run(Module & M,ModuleAnalysisManager & AM)583fd323a89SArthur Eubanks AMDGPUPrintfRuntimeBindingPass::run(Module &M, ModuleAnalysisManager &AM) {
584fd323a89SArthur Eubanks   FunctionAnalysisManager &FAM =
585fd323a89SArthur Eubanks       AM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager();
586fd323a89SArthur Eubanks   auto GetDT = [&FAM](Function &F) -> DominatorTree & {
587fd323a89SArthur Eubanks     return FAM.getResult<DominatorTreeAnalysis>(F);
588fd323a89SArthur Eubanks   };
589fd323a89SArthur Eubanks   auto GetTLI = [&FAM](Function &F) -> TargetLibraryInfo & {
590fd323a89SArthur Eubanks     return FAM.getResult<TargetLibraryAnalysis>(F);
591fd323a89SArthur Eubanks   };
592fd323a89SArthur Eubanks   bool Changed = AMDGPUPrintfRuntimeBindingImpl(GetDT, GetTLI).run(M);
593fd323a89SArthur Eubanks   return Changed ? PreservedAnalyses::none() : PreservedAnalyses::all();
5944c9c98f3SStanislav Mekhanoshin }
595