1 //===--- RuntimeDebugBuilder.cpp - Helper to insert prints into LLVM-IR ---===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 //===----------------------------------------------------------------------===// 11 12 #include "polly/CodeGen/RuntimeDebugBuilder.h" 13 #include "llvm/IR/Intrinsics.h" 14 #include "llvm/IR/Module.h" 15 #include "llvm/Support/Debug.h" 16 #include <string> 17 #include <vector> 18 19 using namespace llvm; 20 using namespace polly; 21 22 Function *RuntimeDebugBuilder::getVPrintF(PollyIRBuilder &Builder) { 23 Module *M = Builder.GetInsertBlock()->getParent()->getParent(); 24 const char *Name = "vprintf"; 25 Function *F = M->getFunction(Name); 26 27 if (!F) { 28 GlobalValue::LinkageTypes Linkage = Function::ExternalLinkage; 29 FunctionType *Ty = FunctionType::get( 30 Builder.getInt32Ty(), {Builder.getInt8PtrTy(), Builder.getInt8PtrTy()}, 31 false); 32 F = Function::Create(Ty, Linkage, Name, M); 33 } 34 35 return F; 36 } 37 38 Function *RuntimeDebugBuilder::getAddressSpaceCast(PollyIRBuilder &Builder, 39 unsigned Src, unsigned Dst, 40 unsigned SrcBits, 41 unsigned DstBits) { 42 Module *M = Builder.GetInsertBlock()->getParent()->getParent(); 43 auto Name = std::string("llvm.nvvm.ptr.constant.to.gen.p") + 44 std::to_string(Dst) + "i" + std::to_string(DstBits) + ".p" + 45 std::to_string(Src) + "i" + std::to_string(SrcBits); 46 Function *F = M->getFunction(Name); 47 48 if (!F) { 49 GlobalValue::LinkageTypes Linkage = Function::ExternalLinkage; 50 FunctionType *Ty = FunctionType::get( 51 PointerType::get(Builder.getIntNTy(DstBits), Dst), 52 PointerType::get(Builder.getIntNTy(SrcBits), Src), false); 53 F = Function::Create(Ty, Linkage, Name, M); 54 } 55 56 return F; 57 } 58 59 std::vector<Value *> 60 RuntimeDebugBuilder::getGPUThreadIdentifiers(PollyIRBuilder &Builder) { 61 std::vector<Value *> Identifiers; 62 63 auto M = Builder.GetInsertBlock()->getParent()->getParent(); 64 65 std::vector<Function *> BlockIDs = { 66 Intrinsic::getDeclaration(M, Intrinsic::ptx_read_ctaid_x), 67 Intrinsic::getDeclaration(M, Intrinsic::ptx_read_ctaid_y), 68 Intrinsic::getDeclaration(M, Intrinsic::ptx_read_ctaid_z), 69 }; 70 71 Identifiers.push_back(Builder.CreateGlobalStringPtr("> block-id: ", "", 4)); 72 for (auto GetID : BlockIDs) { 73 Value *Id = Builder.CreateCall(GetID, {}); 74 Id = Builder.CreateIntCast(Id, Builder.getInt64Ty(), false); 75 Identifiers.push_back(Id); 76 Identifiers.push_back(Builder.CreateGlobalStringPtr(" ", "", 4)); 77 } 78 79 Identifiers.push_back(Builder.CreateGlobalStringPtr("| ", "", 4)); 80 81 std::vector<Function *> ThreadIDs = { 82 Intrinsic::getDeclaration(M, Intrinsic::ptx_read_tid_x), 83 Intrinsic::getDeclaration(M, Intrinsic::ptx_read_tid_y), 84 Intrinsic::getDeclaration(M, Intrinsic::ptx_read_tid_z), 85 }; 86 87 Identifiers.push_back(Builder.CreateGlobalStringPtr("thread-id: ", "", 4)); 88 for (auto GetId : ThreadIDs) { 89 Value *Id = Builder.CreateCall(GetId, {}); 90 Id = Builder.CreateIntCast(Id, Builder.getInt64Ty(), false); 91 Identifiers.push_back(Id); 92 Identifiers.push_back(Builder.CreateGlobalStringPtr(" ", "", 4)); 93 } 94 95 return Identifiers; 96 } 97 98 void RuntimeDebugBuilder::createGPUVAPrinter(PollyIRBuilder &Builder, 99 ArrayRef<Value *> Values) { 100 std::string str; 101 102 // Allocate print buffer (assuming 2*32 bit per element) 103 auto T = ArrayType::get(Builder.getInt32Ty(), Values.size() * 2); 104 Value *Data = new AllocaInst( 105 T, "polly.vprint.buffer", 106 Builder.GetInsertBlock()->getParent()->getEntryBlock().begin()); 107 108 auto *Zero = Builder.getInt64(0); 109 auto *DataPtr = Builder.CreateGEP(Data, {Zero, Zero}); 110 111 auto ToPrint = getGPUThreadIdentifiers(Builder); 112 113 ToPrint.push_back(Builder.CreateGlobalStringPtr("\n ", "", 4)); 114 ToPrint.insert(ToPrint.end(), Values.begin(), Values.end()); 115 116 int Offset = 0; 117 for (auto Val : ToPrint) { 118 auto Ptr = Builder.CreateGEP(DataPtr, Builder.getInt64(Offset)); 119 Type *Ty = Val->getType(); 120 121 if (Ty->isFloatingPointTy()) { 122 if (!Ty->isDoubleTy()) { 123 Ty = Builder.getDoubleTy(); 124 Val = Builder.CreateFPExt(Val, Ty); 125 } 126 } else if (Ty->isIntegerTy()) { 127 auto Int64Bitwidth = Builder.getInt64Ty()->getIntegerBitWidth(); 128 assert(Ty->getIntegerBitWidth() <= Int64Bitwidth); 129 if (Ty->getIntegerBitWidth() < Int64Bitwidth) { 130 Ty = Builder.getInt64Ty(); 131 Val = Builder.CreateSExt(Val, Ty); 132 } 133 } else { 134 // If it is not a number, it must be a string type. 135 Val = Builder.CreateGEP(Val, Builder.getInt64(0)); 136 assert((Val->getType() == Builder.getInt8PtrTy(4)) && 137 "Expected i8 ptr placed in constant address space"); 138 auto F = RuntimeDebugBuilder::getAddressSpaceCast(Builder, 4, 0); 139 Val = Builder.CreateCall(F, Val); 140 Ty = Val->getType(); 141 } 142 143 Ptr = Builder.CreatePointerBitCastOrAddrSpaceCast(Ptr, Ty->getPointerTo(5)); 144 Builder.CreateAlignedStore(Val, Ptr, 4); 145 146 if (Ty->isFloatingPointTy()) 147 str += "%f"; 148 else if (Ty->isIntegerTy()) 149 str += "%ld"; 150 else 151 str += "%s"; 152 153 Offset += 2; 154 } 155 156 Value *Format = Builder.CreateGlobalStringPtr(str, "polly.vprintf.buffer", 4); 157 Format = Builder.CreateCall(getAddressSpaceCast(Builder, 4, 0), Format); 158 159 Data = Builder.CreateBitCast(Data, Builder.getInt8PtrTy()); 160 161 Builder.CreateCall(getVPrintF(Builder), {Format, Data}); 162 } 163 164 Function *RuntimeDebugBuilder::getPrintF(PollyIRBuilder &Builder) { 165 Module *M = Builder.GetInsertBlock()->getParent()->getParent(); 166 const char *Name = "printf"; 167 Function *F = M->getFunction(Name); 168 169 if (!F) { 170 GlobalValue::LinkageTypes Linkage = Function::ExternalLinkage; 171 FunctionType *Ty = 172 FunctionType::get(Builder.getInt32Ty(), Builder.getInt8PtrTy(), true); 173 F = Function::Create(Ty, Linkage, Name, M); 174 } 175 176 return F; 177 } 178 179 void RuntimeDebugBuilder::createFlush(PollyIRBuilder &Builder) { 180 Module *M = Builder.GetInsertBlock()->getParent()->getParent(); 181 const char *Name = "fflush"; 182 Function *F = M->getFunction(Name); 183 184 if (!F) { 185 GlobalValue::LinkageTypes Linkage = Function::ExternalLinkage; 186 FunctionType *Ty = 187 FunctionType::get(Builder.getInt32Ty(), Builder.getInt8PtrTy(), false); 188 F = Function::Create(Ty, Linkage, Name, M); 189 } 190 191 // fflush(NULL) flushes _all_ open output streams. 192 // 193 // fflush is declared as 'int fflush(FILE *stream)'. As we only pass on a NULL 194 // pointer, the type we point to does conceptually not matter. However, if 195 // fflush is already declared in this translation unit, we use the very same 196 // type to ensure that LLVM does not complain about mismatching types. 197 Builder.CreateCall(F, Constant::getNullValue(F->arg_begin()->getType())); 198 } 199 200 void RuntimeDebugBuilder::createStrPrinter(PollyIRBuilder &Builder, 201 const std::string &String) { 202 Value *StringValue = Builder.CreateGlobalStringPtr(String); 203 Builder.CreateCall(getPrintF(Builder), StringValue); 204 205 createFlush(Builder); 206 } 207 208 void RuntimeDebugBuilder::createValuePrinter(PollyIRBuilder &Builder, 209 Value *V) { 210 const char *Format = nullptr; 211 212 Type *Ty = V->getType(); 213 if (Ty->isIntegerTy()) 214 Format = "%ld"; 215 else if (Ty->isFloatingPointTy()) 216 Format = "%lf"; 217 else if (Ty->isPointerTy()) 218 Format = "%p"; 219 220 assert(Format && Ty->getPrimitiveSizeInBits() <= 64 && "Bad type to print."); 221 222 Value *FormatString = Builder.CreateGlobalStringPtr(Format); 223 Builder.CreateCall(getPrintF(Builder), {FormatString, V}); 224 createFlush(Builder); 225 } 226