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