1a014a982SJohannes Doerfert //===--- RuntimeDebugBuilder.cpp - Helper to insert prints into LLVM-IR ---===//
2a014a982SJohannes Doerfert //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6a014a982SJohannes Doerfert //
7a014a982SJohannes Doerfert //===----------------------------------------------------------------------===//
8a014a982SJohannes Doerfert //
9a014a982SJohannes Doerfert //===----------------------------------------------------------------------===//
10a014a982SJohannes Doerfert 
11a014a982SJohannes Doerfert #include "polly/CodeGen/RuntimeDebugBuilder.h"
125368f35eSHeejin Ahn #include "llvm/IR/IntrinsicsNVPTX.h"
13a014a982SJohannes Doerfert #include "llvm/IR/Module.h"
14e7e628ccSTobias Grosser #include <string>
15e7e628ccSTobias Grosser #include <vector>
16a014a982SJohannes Doerfert 
17a014a982SJohannes Doerfert using namespace llvm;
18a014a982SJohannes Doerfert using namespace polly;
19a014a982SJohannes Doerfert 
getVPrintF(PollyIRBuilder & Builder)20e7e628ccSTobias Grosser Function *RuntimeDebugBuilder::getVPrintF(PollyIRBuilder &Builder) {
21e7e628ccSTobias Grosser   Module *M = Builder.GetInsertBlock()->getParent()->getParent();
22e7e628ccSTobias Grosser   const char *Name = "vprintf";
23e7e628ccSTobias Grosser   Function *F = M->getFunction(Name);
24e7e628ccSTobias Grosser 
25e7e628ccSTobias Grosser   if (!F) {
26e7e628ccSTobias Grosser     GlobalValue::LinkageTypes Linkage = Function::ExternalLinkage;
27e7e628ccSTobias Grosser     FunctionType *Ty = FunctionType::get(
28e7e628ccSTobias Grosser         Builder.getInt32Ty(), {Builder.getInt8PtrTy(), Builder.getInt8PtrTy()},
29e7e628ccSTobias Grosser         false);
30e7e628ccSTobias Grosser     F = Function::Create(Ty, Linkage, Name, M);
31e7e628ccSTobias Grosser   }
32e7e628ccSTobias Grosser 
33e7e628ccSTobias Grosser   return F;
34e7e628ccSTobias Grosser }
35e7e628ccSTobias Grosser 
getAddressSpaceCast(PollyIRBuilder & Builder,unsigned Src,unsigned Dst,unsigned SrcBits,unsigned DstBits)36e7e628ccSTobias Grosser Function *RuntimeDebugBuilder::getAddressSpaceCast(PollyIRBuilder &Builder,
37e7e628ccSTobias Grosser                                                    unsigned Src, unsigned Dst,
38e7e628ccSTobias Grosser                                                    unsigned SrcBits,
39e7e628ccSTobias Grosser                                                    unsigned DstBits) {
40e7e628ccSTobias Grosser   Module *M = Builder.GetInsertBlock()->getParent()->getParent();
41e7e628ccSTobias Grosser   auto Name = std::string("llvm.nvvm.ptr.constant.to.gen.p") +
42e7e628ccSTobias Grosser               std::to_string(Dst) + "i" + std::to_string(DstBits) + ".p" +
43e7e628ccSTobias Grosser               std::to_string(Src) + "i" + std::to_string(SrcBits);
44e7e628ccSTobias Grosser   Function *F = M->getFunction(Name);
45e7e628ccSTobias Grosser 
46e7e628ccSTobias Grosser   if (!F) {
47e7e628ccSTobias Grosser     GlobalValue::LinkageTypes Linkage = Function::ExternalLinkage;
48e7e628ccSTobias Grosser     FunctionType *Ty = FunctionType::get(
49e7e628ccSTobias Grosser         PointerType::get(Builder.getIntNTy(DstBits), Dst),
50e7e628ccSTobias Grosser         PointerType::get(Builder.getIntNTy(SrcBits), Src), false);
51e7e628ccSTobias Grosser     F = Function::Create(Ty, Linkage, Name, M);
52e7e628ccSTobias Grosser   }
53e7e628ccSTobias Grosser 
54e7e628ccSTobias Grosser   return F;
55e7e628ccSTobias Grosser }
56e7e628ccSTobias Grosser 
57ec46e537STobias Grosser std::vector<Value *>
getGPUThreadIdentifiers(PollyIRBuilder & Builder)58ec46e537STobias Grosser RuntimeDebugBuilder::getGPUThreadIdentifiers(PollyIRBuilder &Builder) {
59ec46e537STobias Grosser   std::vector<Value *> Identifiers;
60ec46e537STobias Grosser 
61ec46e537STobias Grosser   auto M = Builder.GetInsertBlock()->getParent()->getParent();
62ec46e537STobias Grosser 
63ec46e537STobias Grosser   std::vector<Function *> BlockIDs = {
64e2467babSJustin Bogner       Intrinsic::getDeclaration(M, Intrinsic::nvvm_read_ptx_sreg_ctaid_x),
65e2467babSJustin Bogner       Intrinsic::getDeclaration(M, Intrinsic::nvvm_read_ptx_sreg_ctaid_y),
66e2467babSJustin Bogner       Intrinsic::getDeclaration(M, Intrinsic::nvvm_read_ptx_sreg_ctaid_z),
67ec46e537STobias Grosser   };
68ec46e537STobias Grosser 
69ec46e537STobias Grosser   Identifiers.push_back(Builder.CreateGlobalStringPtr("> block-id: ", "", 4));
70ec46e537STobias Grosser   for (auto GetID : BlockIDs) {
71ec46e537STobias Grosser     Value *Id = Builder.CreateCall(GetID, {});
72ec46e537STobias Grosser     Id = Builder.CreateIntCast(Id, Builder.getInt64Ty(), false);
73ec46e537STobias Grosser     Identifiers.push_back(Id);
74ec46e537STobias Grosser     Identifiers.push_back(Builder.CreateGlobalStringPtr(" ", "", 4));
75ec46e537STobias Grosser   }
76ec46e537STobias Grosser 
77ec46e537STobias Grosser   Identifiers.push_back(Builder.CreateGlobalStringPtr("| ", "", 4));
78ec46e537STobias Grosser 
79ec46e537STobias Grosser   std::vector<Function *> ThreadIDs = {
80e2467babSJustin Bogner       Intrinsic::getDeclaration(M, Intrinsic::nvvm_read_ptx_sreg_tid_x),
81e2467babSJustin Bogner       Intrinsic::getDeclaration(M, Intrinsic::nvvm_read_ptx_sreg_tid_y),
82e2467babSJustin Bogner       Intrinsic::getDeclaration(M, Intrinsic::nvvm_read_ptx_sreg_tid_z),
83ec46e537STobias Grosser   };
84ec46e537STobias Grosser 
85ec46e537STobias Grosser   Identifiers.push_back(Builder.CreateGlobalStringPtr("thread-id: ", "", 4));
86ec46e537STobias Grosser   for (auto GetId : ThreadIDs) {
87ec46e537STobias Grosser     Value *Id = Builder.CreateCall(GetId, {});
88ec46e537STobias Grosser     Id = Builder.CreateIntCast(Id, Builder.getInt64Ty(), false);
89ec46e537STobias Grosser     Identifiers.push_back(Id);
90ec46e537STobias Grosser     Identifiers.push_back(Builder.CreateGlobalStringPtr(" ", "", 4));
91ec46e537STobias Grosser   }
92ec46e537STobias Grosser 
93ec46e537STobias Grosser   return Identifiers;
94ec46e537STobias Grosser }
95ec46e537STobias Grosser 
createPrinter(PollyIRBuilder & Builder,bool IsGPU,ArrayRef<Value * > Values)9686bc93a9STobias Grosser void RuntimeDebugBuilder::createPrinter(PollyIRBuilder &Builder, bool IsGPU,
9786bc93a9STobias Grosser                                         ArrayRef<Value *> Values) {
9886bc93a9STobias Grosser   if (IsGPU)
9986bc93a9STobias Grosser     createGPUPrinterT(Builder, Values);
10086bc93a9STobias Grosser   else
10186bc93a9STobias Grosser     createCPUPrinterT(Builder, Values);
10286bc93a9STobias Grosser }
10386bc93a9STobias Grosser 
isPrintable(Type * Ty)104e819fffeSMichael Kruse bool RuntimeDebugBuilder::isPrintable(Type *Ty) {
105e819fffeSMichael Kruse   if (Ty->isFloatingPointTy())
106e819fffeSMichael Kruse     return true;
107e819fffeSMichael Kruse 
108e819fffeSMichael Kruse   if (Ty->isIntegerTy())
109e819fffeSMichael Kruse     return Ty->getIntegerBitWidth() <= 64;
110e819fffeSMichael Kruse 
111e819fffeSMichael Kruse   if (isa<PointerType>(Ty))
112e819fffeSMichael Kruse     return true;
113e819fffeSMichael Kruse 
114e819fffeSMichael Kruse   return false;
115e819fffeSMichael Kruse }
116e819fffeSMichael Kruse 
11786bc93a9STobias Grosser static std::tuple<std::string, std::vector<Value *>>
prepareValuesForPrinting(PollyIRBuilder & Builder,ArrayRef<Value * > Values)11886bc93a9STobias Grosser prepareValuesForPrinting(PollyIRBuilder &Builder, ArrayRef<Value *> Values) {
11986bc93a9STobias Grosser   std::string FormatString;
12086bc93a9STobias Grosser   std::vector<Value *> ValuesToPrint;
12186bc93a9STobias Grosser 
12286bc93a9STobias Grosser   for (auto Val : Values) {
12386bc93a9STobias Grosser     Type *Ty = Val->getType();
12486bc93a9STobias Grosser 
12586bc93a9STobias Grosser     if (Ty->isFloatingPointTy()) {
12686bc93a9STobias Grosser       if (!Ty->isDoubleTy())
12786bc93a9STobias Grosser         Val = Builder.CreateFPExt(Val, Builder.getDoubleTy());
12886bc93a9STobias Grosser     } else if (Ty->isIntegerTy()) {
12986bc93a9STobias Grosser       if (Ty->getIntegerBitWidth() < 64)
13086bc93a9STobias Grosser         Val = Builder.CreateSExt(Val, Builder.getInt64Ty());
13186bc93a9STobias Grosser       else
13286bc93a9STobias Grosser         assert(Ty->getIntegerBitWidth() &&
13386bc93a9STobias Grosser                "Integer types larger 64 bit not supported");
13486bc93a9STobias Grosser     } else if (isa<PointerType>(Ty)) {
135*76174459SNikita Popov       if (Ty == Builder.getInt8PtrTy(4)) {
1362c68ecccSNikita Popov         Val = Builder.CreateGEP(Builder.getInt8Ty(), Val, Builder.getInt64(0));
13786bc93a9STobias Grosser       } else {
13886bc93a9STobias Grosser         Val = Builder.CreatePtrToInt(Val, Builder.getInt64Ty());
13986bc93a9STobias Grosser       }
14086bc93a9STobias Grosser     } else {
14186bc93a9STobias Grosser       llvm_unreachable("Unknown type");
14286bc93a9STobias Grosser     }
14386bc93a9STobias Grosser 
14486bc93a9STobias Grosser     Ty = Val->getType();
14586bc93a9STobias Grosser 
14686bc93a9STobias Grosser     if (Ty->isFloatingPointTy())
14786bc93a9STobias Grosser       FormatString += "%f";
14886bc93a9STobias Grosser     else if (Ty->isIntegerTy())
14986bc93a9STobias Grosser       FormatString += "%ld";
15086bc93a9STobias Grosser     else
15186bc93a9STobias Grosser       FormatString += "%s";
15286bc93a9STobias Grosser 
15386bc93a9STobias Grosser     ValuesToPrint.push_back(Val);
15486bc93a9STobias Grosser   }
15586bc93a9STobias Grosser 
15686bc93a9STobias Grosser   return std::make_tuple(FormatString, ValuesToPrint);
15786bc93a9STobias Grosser }
15886bc93a9STobias Grosser 
createCPUPrinterT(PollyIRBuilder & Builder,ArrayRef<Value * > Values)15986bc93a9STobias Grosser void RuntimeDebugBuilder::createCPUPrinterT(PollyIRBuilder &Builder,
16086bc93a9STobias Grosser                                             ArrayRef<Value *> Values) {
16186bc93a9STobias Grosser 
16286bc93a9STobias Grosser   std::string FormatString;
16386bc93a9STobias Grosser   std::vector<Value *> ValuesToPrint;
16486bc93a9STobias Grosser 
16586bc93a9STobias Grosser   std::tie(FormatString, ValuesToPrint) =
16686bc93a9STobias Grosser       prepareValuesForPrinting(Builder, Values);
16786bc93a9STobias Grosser 
16886bc93a9STobias Grosser   createPrintF(Builder, FormatString, ValuesToPrint);
16986bc93a9STobias Grosser   createFlush(Builder);
17086bc93a9STobias Grosser }
17186bc93a9STobias Grosser 
createGPUPrinterT(PollyIRBuilder & Builder,ArrayRef<Value * > Values)17286bc93a9STobias Grosser void RuntimeDebugBuilder::createGPUPrinterT(PollyIRBuilder &Builder,
173e7e628ccSTobias Grosser                                             ArrayRef<Value *> Values) {
174e7e628ccSTobias Grosser   std::string str;
175e7e628ccSTobias Grosser 
176e7e628ccSTobias Grosser   auto *Zero = Builder.getInt64(0);
177e7e628ccSTobias Grosser 
178ec46e537STobias Grosser   auto ToPrint = getGPUThreadIdentifiers(Builder);
179ec46e537STobias Grosser 
180ec46e537STobias Grosser   ToPrint.push_back(Builder.CreateGlobalStringPtr("\n  ", "", 4));
181ec46e537STobias Grosser   ToPrint.insert(ToPrint.end(), Values.begin(), Values.end());
182ec46e537STobias Grosser 
183b3e30c32SMatt Arsenault   const DataLayout &DL = Builder.GetInsertBlock()->getModule()->getDataLayout();
184b3e30c32SMatt Arsenault 
1854bf262a0STobias Grosser   // Allocate print buffer (assuming 2*32 bit per element)
1864bf262a0STobias Grosser   auto T = ArrayType::get(Builder.getInt32Ty(), ToPrint.size() * 2);
1874bf262a0STobias Grosser   Value *Data = new AllocaInst(
188b3e30c32SMatt Arsenault       T, DL.getAllocaAddrSpace(), "polly.vprint.buffer",
189b8f58b53SDuncan P. N. Exon Smith       &Builder.GetInsertBlock()->getParent()->getEntryBlock().front());
19042eb658fSNikita Popov   auto *DataPtr = Builder.CreateGEP(T, Data, {Zero, Zero});
1914bf262a0STobias Grosser 
192e7e628ccSTobias Grosser   int Offset = 0;
193ec46e537STobias Grosser   for (auto Val : ToPrint) {
1942c68ecccSNikita Popov     auto Ptr = Builder.CreateGEP(Builder.getInt32Ty(), DataPtr,
1952c68ecccSNikita Popov                                  Builder.getInt64(Offset));
196e7e628ccSTobias Grosser     Type *Ty = Val->getType();
197e7e628ccSTobias Grosser 
198e7e628ccSTobias Grosser     if (Ty->isFloatingPointTy()) {
199e58d3581STobias Grosser       if (!Ty->isDoubleTy())
200e58d3581STobias Grosser         Val = Builder.CreateFPExt(Val, Builder.getDoubleTy());
201e7e628ccSTobias Grosser     } else if (Ty->isIntegerTy()) {
202c49f115bSTobias Grosser       if (Ty->getIntegerBitWidth() < 64) {
203e58d3581STobias Grosser         Val = Builder.CreateSExt(Val, Builder.getInt64Ty());
204c49f115bSTobias Grosser       } else {
205c49f115bSTobias Grosser         assert(Ty->getIntegerBitWidth() == 64 &&
206c49f115bSTobias Grosser                "Integer types larger 64 bit not supported");
207c49f115bSTobias Grosser         // fallthrough
208c49f115bSTobias Grosser       }
209*76174459SNikita Popov     } else if (isa<PointerType>(Ty)) {
210*76174459SNikita Popov       if (Ty == Builder.getInt8PtrTy(4)) {
211495124c4STobias Grosser         // Pointers in constant address space are printed as strings
212*76174459SNikita Popov         Val = Builder.CreateGEP(Builder.getInt8Ty(), Val, Builder.getInt64(0));
213e7e628ccSTobias Grosser         auto F = RuntimeDebugBuilder::getAddressSpaceCast(Builder, 4, 0);
214e7e628ccSTobias Grosser         Val = Builder.CreateCall(F, Val);
215495124c4STobias Grosser       } else {
216495124c4STobias Grosser         Val = Builder.CreatePtrToInt(Val, Builder.getInt64Ty());
217495124c4STobias Grosser       }
218495124c4STobias Grosser     } else {
219495124c4STobias Grosser       llvm_unreachable("Unknown type");
220e7e628ccSTobias Grosser     }
221e7e628ccSTobias Grosser 
222e58d3581STobias Grosser     Ty = Val->getType();
223e7e628ccSTobias Grosser     Ptr = Builder.CreatePointerBitCastOrAddrSpaceCast(Ptr, Ty->getPointerTo(5));
22459f95222SGuillaume Chatelet     Builder.CreateAlignedStore(Val, Ptr, Align(4));
225e7e628ccSTobias Grosser 
226e7e628ccSTobias Grosser     if (Ty->isFloatingPointTy())
227e7e628ccSTobias Grosser       str += "%f";
228e7e628ccSTobias Grosser     else if (Ty->isIntegerTy())
229e7e628ccSTobias Grosser       str += "%ld";
230e7e628ccSTobias Grosser     else
231e7e628ccSTobias Grosser       str += "%s";
232e7e628ccSTobias Grosser 
233e7e628ccSTobias Grosser     Offset += 2;
234e7e628ccSTobias Grosser   }
235e7e628ccSTobias Grosser 
236e7e628ccSTobias Grosser   Value *Format = Builder.CreateGlobalStringPtr(str, "polly.vprintf.buffer", 4);
237e7e628ccSTobias Grosser   Format = Builder.CreateCall(getAddressSpaceCast(Builder, 4, 0), Format);
238e7e628ccSTobias Grosser 
239e7e628ccSTobias Grosser   Data = Builder.CreateBitCast(Data, Builder.getInt8PtrTy());
240e7e628ccSTobias Grosser 
241e7e628ccSTobias Grosser   Builder.CreateCall(getVPrintF(Builder), {Format, Data});
242e7e628ccSTobias Grosser }
243e7e628ccSTobias Grosser 
getPrintF(PollyIRBuilder & Builder)244a014a982SJohannes Doerfert Function *RuntimeDebugBuilder::getPrintF(PollyIRBuilder &Builder) {
245a014a982SJohannes Doerfert   Module *M = Builder.GetInsertBlock()->getParent()->getParent();
246a014a982SJohannes Doerfert   const char *Name = "printf";
247a014a982SJohannes Doerfert   Function *F = M->getFunction(Name);
248a014a982SJohannes Doerfert 
249a014a982SJohannes Doerfert   if (!F) {
250a014a982SJohannes Doerfert     GlobalValue::LinkageTypes Linkage = Function::ExternalLinkage;
25186bc93a9STobias Grosser     FunctionType *Ty = FunctionType::get(Builder.getInt32Ty(), true);
252a014a982SJohannes Doerfert     F = Function::Create(Ty, Linkage, Name, M);
253a014a982SJohannes Doerfert   }
254a014a982SJohannes Doerfert 
255a014a982SJohannes Doerfert   return F;
256a014a982SJohannes Doerfert }
257a014a982SJohannes Doerfert 
createPrintF(PollyIRBuilder & Builder,std::string Format,ArrayRef<Value * > Values)25886bc93a9STobias Grosser void RuntimeDebugBuilder::createPrintF(PollyIRBuilder &Builder,
25986bc93a9STobias Grosser                                        std::string Format,
26086bc93a9STobias Grosser                                        ArrayRef<Value *> Values) {
26186bc93a9STobias Grosser   Value *FormatString = Builder.CreateGlobalStringPtr(Format);
26286bc93a9STobias Grosser   std::vector<Value *> Arguments;
26386bc93a9STobias Grosser 
26486bc93a9STobias Grosser   Arguments.push_back(FormatString);
26586bc93a9STobias Grosser   Arguments.insert(Arguments.end(), Values.begin(), Values.end());
26686bc93a9STobias Grosser   Builder.CreateCall(getPrintF(Builder), Arguments);
26786bc93a9STobias Grosser }
26886bc93a9STobias Grosser 
createFlush(PollyIRBuilder & Builder)269a014a982SJohannes Doerfert void RuntimeDebugBuilder::createFlush(PollyIRBuilder &Builder) {
270a014a982SJohannes Doerfert   Module *M = Builder.GetInsertBlock()->getParent()->getParent();
271a014a982SJohannes Doerfert   const char *Name = "fflush";
272a014a982SJohannes Doerfert   Function *F = M->getFunction(Name);
273a014a982SJohannes Doerfert 
274a014a982SJohannes Doerfert   if (!F) {
275a014a982SJohannes Doerfert     GlobalValue::LinkageTypes Linkage = Function::ExternalLinkage;
276a014a982SJohannes Doerfert     FunctionType *Ty =
277a014a982SJohannes Doerfert         FunctionType::get(Builder.getInt32Ty(), Builder.getInt8PtrTy(), false);
278a014a982SJohannes Doerfert     F = Function::Create(Ty, Linkage, Name, M);
279a014a982SJohannes Doerfert   }
280a014a982SJohannes Doerfert 
281477a1dceSTobias Grosser   // fflush(NULL) flushes _all_ open output streams.
282477a1dceSTobias Grosser   //
283477a1dceSTobias Grosser   // fflush is declared as 'int fflush(FILE *stream)'. As we only pass on a NULL
284477a1dceSTobias Grosser   // pointer, the type we point to does conceptually not matter. However, if
285477a1dceSTobias Grosser   // fflush is already declared in this translation unit, we use the very same
286477a1dceSTobias Grosser   // type to ensure that LLVM does not complain about mismatching types.
287477a1dceSTobias Grosser   Builder.CreateCall(F, Constant::getNullValue(F->arg_begin()->getType()));
288a014a982SJohannes Doerfert }
289