From 6091417ebceb53fe76fa3ecd2f42b60248888814 Mon Sep 17 00:00:00 2001 From: Tobias Grosser Date: Sat, 6 Jun 2015 08:43:22 +0000 Subject: [PATCH] Add NVIDIA vprintf printing to RuntimeDebugBuilder llvm-svn: 239219 --- polly/include/polly/CodeGen/RuntimeDebugBuilder.h | 67 +++++++++++++- polly/lib/CodeGen/RuntimeDebugBuilder.cpp | 101 ++++++++++++++++++++++ 2 files changed, 167 insertions(+), 1 deletion(-) diff --git a/polly/include/polly/CodeGen/RuntimeDebugBuilder.h b/polly/include/polly/CodeGen/RuntimeDebugBuilder.h index 733cdde..0c0f041 100644 --- a/polly/include/polly/CodeGen/RuntimeDebugBuilder.h +++ b/polly/include/polly/CodeGen/RuntimeDebugBuilder.h @@ -13,7 +13,8 @@ #define RUNTIME_DEBUG_BUILDER_H #include "polly/CodeGen/IRBuilder.h" -#include +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringRef.h" namespace llvm { class Value; @@ -52,6 +53,70 @@ struct RuntimeDebugBuilder { /// If the current module does not yet contain a reference to printf, we /// insert a reference to it. Otherwise the existing reference is returned. static llvm::Function *getPrintF(PollyIRBuilder &Builder); + + /// @brief Print a set of LLVM-IR Values or StringRefs on an NVIDIA GPU. + /// + /// This function emits a call to vprintf that will print the given + /// arguments from within a kernel thread. It is useful for debugging + /// CUDA program kernels. All arguments given in this list will be + /// automatically concatenated and the resulting string will be printed + /// atomically. We also support ArrayRef arguments, which can be used to + /// provide for example a list of thread-id values. + /// + /// @param Builder The builder used to emit the printer calls. + /// @param Args The list of values to print. + template + static void createGPUPrinter(PollyIRBuilder &Builder, Args... args) { + std::vector Vector; + createGPUVAPrinter(Builder, Vector, args...); + } + +private: + /// @brief GPU printing - Print a list of LLVM Values. + /// + static void createGPUVAPrinter(PollyIRBuilder &Builder, + llvm::ArrayRef Values); + + /// @brief GPU printing - Handle Values. + template + static void createGPUVAPrinter(PollyIRBuilder &Builder, + std::vector &Values, + llvm::Value *Value, Args... args) { + Values.push_back(Value); + createGPUVAPrinter(Builder, Values, args...); + } + + /// @brief GPU printing - Handle StringRefs. + template + static void createGPUVAPrinter(PollyIRBuilder &Builder, + std::vector &Values, + llvm::StringRef String, Args... args) { + Values.push_back(Builder.CreateGlobalStringPtr(String, "", 4)); + createGPUVAPrinter(Builder, Values, args...); + } + + /// @brief GPU printing - Handle ArrayRefs. + template + static void createGPUVAPrinter(PollyIRBuilder &Builder, + std::vector &Values, + llvm::ArrayRef Array, + Args... args) { + if (Array.size() >= 2) + createGPUVAPrinter( + Builder, Values, Array[0], " ", + llvm::ArrayRef(&Array[1], Array.size() - 1), args...); + else + createGPUVAPrinter(Builder, Values, Array[0], args...); + } + + /// @brief Get (and possibly insert) a vprintf declaration into the module. + static llvm::Function *getVPrintF(PollyIRBuilder &Builder); + + /// @brief Get (and possibly insert) a NVIDIA address space cast call. + static llvm::Function *getAddressSpaceCast(PollyIRBuilder &Builder, + unsigned Src, unsigned Dst, + unsigned SrcBits = 8, + unsigned DstBits = 8); }; } diff --git a/polly/lib/CodeGen/RuntimeDebugBuilder.cpp b/polly/lib/CodeGen/RuntimeDebugBuilder.cpp index 5d50450..14cc115 100644 --- a/polly/lib/CodeGen/RuntimeDebugBuilder.cpp +++ b/polly/lib/CodeGen/RuntimeDebugBuilder.cpp @@ -11,10 +11,111 @@ #include "polly/CodeGen/RuntimeDebugBuilder.h" #include "llvm/IR/Module.h" +#include "llvm/Support/Debug.h" +#include +#include using namespace llvm; using namespace polly; +Function *RuntimeDebugBuilder::getVPrintF(PollyIRBuilder &Builder) { + Module *M = Builder.GetInsertBlock()->getParent()->getParent(); + const char *Name = "vprintf"; + Function *F = M->getFunction(Name); + + if (!F) { + GlobalValue::LinkageTypes Linkage = Function::ExternalLinkage; + FunctionType *Ty = FunctionType::get( + Builder.getInt32Ty(), {Builder.getInt8PtrTy(), Builder.getInt8PtrTy()}, + false); + F = Function::Create(Ty, Linkage, Name, M); + } + + return F; +} + +Function *RuntimeDebugBuilder::getAddressSpaceCast(PollyIRBuilder &Builder, + unsigned Src, unsigned Dst, + unsigned SrcBits, + unsigned DstBits) { + Module *M = Builder.GetInsertBlock()->getParent()->getParent(); + auto Name = std::string("llvm.nvvm.ptr.constant.to.gen.p") + + std::to_string(Dst) + "i" + std::to_string(DstBits) + ".p" + + std::to_string(Src) + "i" + std::to_string(SrcBits); + Function *F = M->getFunction(Name); + + if (!F) { + GlobalValue::LinkageTypes Linkage = Function::ExternalLinkage; + FunctionType *Ty = FunctionType::get( + PointerType::get(Builder.getIntNTy(DstBits), Dst), + PointerType::get(Builder.getIntNTy(SrcBits), Src), false); + F = Function::Create(Ty, Linkage, Name, M); + } + + return F; +} + +void RuntimeDebugBuilder::createGPUVAPrinter(PollyIRBuilder &Builder, + ArrayRef Values) { + std::string str; + + // Allocate print buffer (assuming 2*32 bit per element) + auto T = ArrayType::get(Builder.getInt32Ty(), Values.size() * 2); + Value *Data = new AllocaInst( + T, "polly.vprint.buffer", + Builder.GetInsertBlock()->getParent()->getEntryBlock().begin()); + + auto *Zero = Builder.getInt64(0); + auto *DataPtr = Builder.CreateGEP(Data, {Zero, Zero}); + + int Offset = 0; + for (auto Val : Values) { + auto Ptr = Builder.CreateGEP(DataPtr, {Builder.getInt64(Offset)}); + Type *Ty = Val->getType(); + + if (Ty->isFloatingPointTy()) { + if (!Ty->isDoubleTy()) { + Ty = Builder.getDoubleTy(); + Val = Builder.CreateFPExt(Val, Ty); + } + } else if (Ty->isIntegerTy()) { + auto Int64Bitwidth = Builder.getInt64Ty()->getIntegerBitWidth(); + assert(Ty->getIntegerBitWidth() <= Int64Bitwidth); + if (Ty->getIntegerBitWidth() < Int64Bitwidth) { + Ty = Builder.getInt64Ty(); + Val = Builder.CreateSExt(Val, Ty); + } + } else { + // If it is not a number, it must be a string type. + Val = Builder.CreateGEP(Val, Builder.getInt64(0)); + assert((Val->getType() == Builder.getInt8PtrTy(4)) && + "Expected i8 ptr placed in constant address space"); + auto F = RuntimeDebugBuilder::getAddressSpaceCast(Builder, 4, 0); + Val = Builder.CreateCall(F, Val); + Ty = Val->getType(); + } + + Ptr = Builder.CreatePointerBitCastOrAddrSpaceCast(Ptr, Ty->getPointerTo(5)); + Builder.CreateAlignedStore(Val, Ptr, 4); + + if (Ty->isFloatingPointTy()) + str += "%f"; + else if (Ty->isIntegerTy()) + str += "%ld"; + else + str += "%s"; + + Offset += 2; + } + + Value *Format = Builder.CreateGlobalStringPtr(str, "polly.vprintf.buffer", 4); + Format = Builder.CreateCall(getAddressSpaceCast(Builder, 4, 0), Format); + + Data = Builder.CreateBitCast(Data, Builder.getInt8PtrTy()); + + Builder.CreateCall(getVPrintF(Builder), {Format, Data}); +} + Function *RuntimeDebugBuilder::getPrintF(PollyIRBuilder &Builder) { Module *M = Builder.GetInsertBlock()->getParent()->getParent(); const char *Name = "printf"; -- 2.7.4