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::nvvm_read_ptx_sreg_ctaid_x), 67 Intrinsic::getDeclaration(M, Intrinsic::nvvm_read_ptx_sreg_ctaid_y), 68 Intrinsic::getDeclaration(M, Intrinsic::nvvm_read_ptx_sreg_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::nvvm_read_ptx_sreg_tid_x), 83 Intrinsic::getDeclaration(M, Intrinsic::nvvm_read_ptx_sreg_tid_y), 84 Intrinsic::getDeclaration(M, Intrinsic::nvvm_read_ptx_sreg_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::createPrinter(PollyIRBuilder &Builder, bool IsGPU, 99 ArrayRef<Value *> Values) { 100 if (IsGPU) 101 createGPUPrinterT(Builder, Values); 102 else 103 createCPUPrinterT(Builder, Values); 104 } 105 106 bool RuntimeDebugBuilder::isPrintable(Type *Ty) { 107 if (Ty->isFloatingPointTy()) 108 return true; 109 110 if (Ty->isIntegerTy()) 111 return Ty->getIntegerBitWidth() <= 64; 112 113 if (isa<PointerType>(Ty)) 114 return true; 115 116 return false; 117 } 118 119 static std::tuple<std::string, std::vector<Value *>> 120 prepareValuesForPrinting(PollyIRBuilder &Builder, ArrayRef<Value *> Values) { 121 std::string FormatString; 122 std::vector<Value *> ValuesToPrint; 123 124 for (auto Val : Values) { 125 Type *Ty = Val->getType(); 126 127 if (Ty->isFloatingPointTy()) { 128 if (!Ty->isDoubleTy()) 129 Val = Builder.CreateFPExt(Val, Builder.getDoubleTy()); 130 } else if (Ty->isIntegerTy()) { 131 if (Ty->getIntegerBitWidth() < 64) 132 Val = Builder.CreateSExt(Val, Builder.getInt64Ty()); 133 else 134 assert(Ty->getIntegerBitWidth() && 135 "Integer types larger 64 bit not supported"); 136 } else if (isa<PointerType>(Ty)) { 137 if (Ty->getPointerElementType() == Builder.getInt8Ty() && 138 Ty->getPointerAddressSpace() == 4) { 139 Val = Builder.CreateGEP(Val, Builder.getInt64(0)); 140 } else { 141 Val = Builder.CreatePtrToInt(Val, Builder.getInt64Ty()); 142 } 143 } else { 144 llvm_unreachable("Unknown type"); 145 } 146 147 Ty = Val->getType(); 148 149 if (Ty->isFloatingPointTy()) 150 FormatString += "%f"; 151 else if (Ty->isIntegerTy()) 152 FormatString += "%ld"; 153 else 154 FormatString += "%s"; 155 156 ValuesToPrint.push_back(Val); 157 } 158 159 return std::make_tuple(FormatString, ValuesToPrint); 160 } 161 162 void RuntimeDebugBuilder::createCPUPrinterT(PollyIRBuilder &Builder, 163 ArrayRef<Value *> Values) { 164 165 std::string FormatString; 166 std::vector<Value *> ValuesToPrint; 167 168 std::tie(FormatString, ValuesToPrint) = 169 prepareValuesForPrinting(Builder, Values); 170 171 createPrintF(Builder, FormatString, ValuesToPrint); 172 createFlush(Builder); 173 } 174 175 void RuntimeDebugBuilder::createGPUPrinterT(PollyIRBuilder &Builder, 176 ArrayRef<Value *> Values) { 177 std::string str; 178 179 auto *Zero = Builder.getInt64(0); 180 181 auto ToPrint = getGPUThreadIdentifiers(Builder); 182 183 ToPrint.push_back(Builder.CreateGlobalStringPtr("\n ", "", 4)); 184 ToPrint.insert(ToPrint.end(), Values.begin(), Values.end()); 185 186 const DataLayout &DL = Builder.GetInsertBlock()->getModule()->getDataLayout(); 187 188 // Allocate print buffer (assuming 2*32 bit per element) 189 auto T = ArrayType::get(Builder.getInt32Ty(), ToPrint.size() * 2); 190 Value *Data = new AllocaInst( 191 T, DL.getAllocaAddrSpace(), "polly.vprint.buffer", 192 &Builder.GetInsertBlock()->getParent()->getEntryBlock().front()); 193 auto *DataPtr = Builder.CreateGEP(Data, {Zero, Zero}); 194 195 int Offset = 0; 196 for (auto Val : ToPrint) { 197 auto Ptr = Builder.CreateGEP(DataPtr, Builder.getInt64(Offset)); 198 Type *Ty = Val->getType(); 199 200 if (Ty->isFloatingPointTy()) { 201 if (!Ty->isDoubleTy()) 202 Val = Builder.CreateFPExt(Val, Builder.getDoubleTy()); 203 } else if (Ty->isIntegerTy()) { 204 if (Ty->getIntegerBitWidth() < 64) { 205 Val = Builder.CreateSExt(Val, Builder.getInt64Ty()); 206 } else { 207 assert(Ty->getIntegerBitWidth() == 64 && 208 "Integer types larger 64 bit not supported"); 209 // fallthrough 210 } 211 } else if (auto PtTy = dyn_cast<PointerType>(Ty)) { 212 if (PtTy->getAddressSpace() == 4) { 213 // Pointers in constant address space are printed as strings 214 Val = Builder.CreateGEP(Val, Builder.getInt64(0)); 215 auto F = RuntimeDebugBuilder::getAddressSpaceCast(Builder, 4, 0); 216 Val = Builder.CreateCall(F, Val); 217 } else { 218 Val = Builder.CreatePtrToInt(Val, Builder.getInt64Ty()); 219 } 220 } else { 221 llvm_unreachable("Unknown type"); 222 } 223 224 Ty = Val->getType(); 225 Ptr = Builder.CreatePointerBitCastOrAddrSpaceCast(Ptr, Ty->getPointerTo(5)); 226 Builder.CreateAlignedStore(Val, Ptr, 4); 227 228 if (Ty->isFloatingPointTy()) 229 str += "%f"; 230 else if (Ty->isIntegerTy()) 231 str += "%ld"; 232 else 233 str += "%s"; 234 235 Offset += 2; 236 } 237 238 Value *Format = Builder.CreateGlobalStringPtr(str, "polly.vprintf.buffer", 4); 239 Format = Builder.CreateCall(getAddressSpaceCast(Builder, 4, 0), Format); 240 241 Data = Builder.CreateBitCast(Data, Builder.getInt8PtrTy()); 242 243 Builder.CreateCall(getVPrintF(Builder), {Format, Data}); 244 } 245 246 Function *RuntimeDebugBuilder::getPrintF(PollyIRBuilder &Builder) { 247 Module *M = Builder.GetInsertBlock()->getParent()->getParent(); 248 const char *Name = "printf"; 249 Function *F = M->getFunction(Name); 250 251 if (!F) { 252 GlobalValue::LinkageTypes Linkage = Function::ExternalLinkage; 253 FunctionType *Ty = FunctionType::get(Builder.getInt32Ty(), true); 254 F = Function::Create(Ty, Linkage, Name, M); 255 } 256 257 return F; 258 } 259 260 void RuntimeDebugBuilder::createPrintF(PollyIRBuilder &Builder, 261 std::string Format, 262 ArrayRef<Value *> Values) { 263 Value *FormatString = Builder.CreateGlobalStringPtr(Format); 264 std::vector<Value *> Arguments; 265 266 Arguments.push_back(FormatString); 267 Arguments.insert(Arguments.end(), Values.begin(), Values.end()); 268 Builder.CreateCall(getPrintF(Builder), Arguments); 269 } 270 271 void RuntimeDebugBuilder::createFlush(PollyIRBuilder &Builder) { 272 Module *M = Builder.GetInsertBlock()->getParent()->getParent(); 273 const char *Name = "fflush"; 274 Function *F = M->getFunction(Name); 275 276 if (!F) { 277 GlobalValue::LinkageTypes Linkage = Function::ExternalLinkage; 278 FunctionType *Ty = 279 FunctionType::get(Builder.getInt32Ty(), Builder.getInt8PtrTy(), false); 280 F = Function::Create(Ty, Linkage, Name, M); 281 } 282 283 // fflush(NULL) flushes _all_ open output streams. 284 // 285 // fflush is declared as 'int fflush(FILE *stream)'. As we only pass on a NULL 286 // pointer, the type we point to does conceptually not matter. However, if 287 // fflush is already declared in this translation unit, we use the very same 288 // type to ensure that LLVM does not complain about mismatching types. 289 Builder.CreateCall(F, Constant::getNullValue(F->arg_begin()->getType())); 290 } 291