1 //===--- RuntimeDebugBuilder.cpp - Helper to insert prints into LLVM-IR ---===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 //===----------------------------------------------------------------------===//
10 
11 #include "polly/CodeGen/RuntimeDebugBuilder.h"
12 #include "llvm/IR/Intrinsics.h"
13 #include "llvm/IR/Module.h"
14 #include "llvm/Support/Debug.h"
15 #include <string>
16 #include <vector>
17 
18 using namespace llvm;
19 using namespace polly;
20 
21 Function *RuntimeDebugBuilder::getVPrintF(PollyIRBuilder &Builder) {
22   Module *M = Builder.GetInsertBlock()->getParent()->getParent();
23   const char *Name = "vprintf";
24   Function *F = M->getFunction(Name);
25 
26   if (!F) {
27     GlobalValue::LinkageTypes Linkage = Function::ExternalLinkage;
28     FunctionType *Ty = FunctionType::get(
29         Builder.getInt32Ty(), {Builder.getInt8PtrTy(), Builder.getInt8PtrTy()},
30         false);
31     F = Function::Create(Ty, Linkage, Name, M);
32   }
33 
34   return F;
35 }
36 
37 Function *RuntimeDebugBuilder::getAddressSpaceCast(PollyIRBuilder &Builder,
38                                                    unsigned Src, unsigned Dst,
39                                                    unsigned SrcBits,
40                                                    unsigned DstBits) {
41   Module *M = Builder.GetInsertBlock()->getParent()->getParent();
42   auto Name = std::string("llvm.nvvm.ptr.constant.to.gen.p") +
43               std::to_string(Dst) + "i" + std::to_string(DstBits) + ".p" +
44               std::to_string(Src) + "i" + std::to_string(SrcBits);
45   Function *F = M->getFunction(Name);
46 
47   if (!F) {
48     GlobalValue::LinkageTypes Linkage = Function::ExternalLinkage;
49     FunctionType *Ty = FunctionType::get(
50         PointerType::get(Builder.getIntNTy(DstBits), Dst),
51         PointerType::get(Builder.getIntNTy(SrcBits), Src), false);
52     F = Function::Create(Ty, Linkage, Name, M);
53   }
54 
55   return F;
56 }
57 
58 std::vector<Value *>
59 RuntimeDebugBuilder::getGPUThreadIdentifiers(PollyIRBuilder &Builder) {
60   std::vector<Value *> Identifiers;
61 
62   auto M = Builder.GetInsertBlock()->getParent()->getParent();
63 
64   std::vector<Function *> BlockIDs = {
65       Intrinsic::getDeclaration(M, Intrinsic::nvvm_read_ptx_sreg_ctaid_x),
66       Intrinsic::getDeclaration(M, Intrinsic::nvvm_read_ptx_sreg_ctaid_y),
67       Intrinsic::getDeclaration(M, Intrinsic::nvvm_read_ptx_sreg_ctaid_z),
68   };
69 
70   Identifiers.push_back(Builder.CreateGlobalStringPtr("> block-id: ", "", 4));
71   for (auto GetID : BlockIDs) {
72     Value *Id = Builder.CreateCall(GetID, {});
73     Id = Builder.CreateIntCast(Id, Builder.getInt64Ty(), false);
74     Identifiers.push_back(Id);
75     Identifiers.push_back(Builder.CreateGlobalStringPtr(" ", "", 4));
76   }
77 
78   Identifiers.push_back(Builder.CreateGlobalStringPtr("| ", "", 4));
79 
80   std::vector<Function *> ThreadIDs = {
81       Intrinsic::getDeclaration(M, Intrinsic::nvvm_read_ptx_sreg_tid_x),
82       Intrinsic::getDeclaration(M, Intrinsic::nvvm_read_ptx_sreg_tid_y),
83       Intrinsic::getDeclaration(M, Intrinsic::nvvm_read_ptx_sreg_tid_z),
84   };
85 
86   Identifiers.push_back(Builder.CreateGlobalStringPtr("thread-id: ", "", 4));
87   for (auto GetId : ThreadIDs) {
88     Value *Id = Builder.CreateCall(GetId, {});
89     Id = Builder.CreateIntCast(Id, Builder.getInt64Ty(), false);
90     Identifiers.push_back(Id);
91     Identifiers.push_back(Builder.CreateGlobalStringPtr(" ", "", 4));
92   }
93 
94   return Identifiers;
95 }
96 
97 void RuntimeDebugBuilder::createPrinter(PollyIRBuilder &Builder, bool IsGPU,
98                                         ArrayRef<Value *> Values) {
99   if (IsGPU)
100     createGPUPrinterT(Builder, Values);
101   else
102     createCPUPrinterT(Builder, Values);
103 }
104 
105 bool RuntimeDebugBuilder::isPrintable(Type *Ty) {
106   if (Ty->isFloatingPointTy())
107     return true;
108 
109   if (Ty->isIntegerTy())
110     return Ty->getIntegerBitWidth() <= 64;
111 
112   if (isa<PointerType>(Ty))
113     return true;
114 
115   return false;
116 }
117 
118 static std::tuple<std::string, std::vector<Value *>>
119 prepareValuesForPrinting(PollyIRBuilder &Builder, ArrayRef<Value *> Values) {
120   std::string FormatString;
121   std::vector<Value *> ValuesToPrint;
122 
123   for (auto Val : Values) {
124     Type *Ty = Val->getType();
125 
126     if (Ty->isFloatingPointTy()) {
127       if (!Ty->isDoubleTy())
128         Val = Builder.CreateFPExt(Val, Builder.getDoubleTy());
129     } else if (Ty->isIntegerTy()) {
130       if (Ty->getIntegerBitWidth() < 64)
131         Val = Builder.CreateSExt(Val, Builder.getInt64Ty());
132       else
133         assert(Ty->getIntegerBitWidth() &&
134                "Integer types larger 64 bit not supported");
135     } else if (isa<PointerType>(Ty)) {
136       if (Ty->getPointerElementType() == Builder.getInt8Ty() &&
137           Ty->getPointerAddressSpace() == 4) {
138         Val = Builder.CreateGEP(Val, Builder.getInt64(0));
139       } else {
140         Val = Builder.CreatePtrToInt(Val, Builder.getInt64Ty());
141       }
142     } else {
143       llvm_unreachable("Unknown type");
144     }
145 
146     Ty = Val->getType();
147 
148     if (Ty->isFloatingPointTy())
149       FormatString += "%f";
150     else if (Ty->isIntegerTy())
151       FormatString += "%ld";
152     else
153       FormatString += "%s";
154 
155     ValuesToPrint.push_back(Val);
156   }
157 
158   return std::make_tuple(FormatString, ValuesToPrint);
159 }
160 
161 void RuntimeDebugBuilder::createCPUPrinterT(PollyIRBuilder &Builder,
162                                             ArrayRef<Value *> Values) {
163 
164   std::string FormatString;
165   std::vector<Value *> ValuesToPrint;
166 
167   std::tie(FormatString, ValuesToPrint) =
168       prepareValuesForPrinting(Builder, Values);
169 
170   createPrintF(Builder, FormatString, ValuesToPrint);
171   createFlush(Builder);
172 }
173 
174 void RuntimeDebugBuilder::createGPUPrinterT(PollyIRBuilder &Builder,
175                                             ArrayRef<Value *> Values) {
176   std::string str;
177 
178   auto *Zero = Builder.getInt64(0);
179 
180   auto ToPrint = getGPUThreadIdentifiers(Builder);
181 
182   ToPrint.push_back(Builder.CreateGlobalStringPtr("\n  ", "", 4));
183   ToPrint.insert(ToPrint.end(), Values.begin(), Values.end());
184 
185   const DataLayout &DL = Builder.GetInsertBlock()->getModule()->getDataLayout();
186 
187   // Allocate print buffer (assuming 2*32 bit per element)
188   auto T = ArrayType::get(Builder.getInt32Ty(), ToPrint.size() * 2);
189   Value *Data = new AllocaInst(
190       T, DL.getAllocaAddrSpace(), "polly.vprint.buffer",
191       &Builder.GetInsertBlock()->getParent()->getEntryBlock().front());
192   auto *DataPtr = Builder.CreateGEP(Data, {Zero, Zero});
193 
194   int Offset = 0;
195   for (auto Val : ToPrint) {
196     auto Ptr = Builder.CreateGEP(DataPtr, Builder.getInt64(Offset));
197     Type *Ty = Val->getType();
198 
199     if (Ty->isFloatingPointTy()) {
200       if (!Ty->isDoubleTy())
201         Val = Builder.CreateFPExt(Val, Builder.getDoubleTy());
202     } else if (Ty->isIntegerTy()) {
203       if (Ty->getIntegerBitWidth() < 64) {
204         Val = Builder.CreateSExt(Val, Builder.getInt64Ty());
205       } else {
206         assert(Ty->getIntegerBitWidth() == 64 &&
207                "Integer types larger 64 bit not supported");
208         // fallthrough
209       }
210     } else if (auto PtTy = dyn_cast<PointerType>(Ty)) {
211       if (PtTy->getAddressSpace() == 4) {
212         // Pointers in constant address space are printed as strings
213         Val = Builder.CreateGEP(Val, Builder.getInt64(0));
214         auto F = RuntimeDebugBuilder::getAddressSpaceCast(Builder, 4, 0);
215         Val = Builder.CreateCall(F, Val);
216       } else {
217         Val = Builder.CreatePtrToInt(Val, Builder.getInt64Ty());
218       }
219     } else {
220       llvm_unreachable("Unknown type");
221     }
222 
223     Ty = Val->getType();
224     Ptr = Builder.CreatePointerBitCastOrAddrSpaceCast(Ptr, Ty->getPointerTo(5));
225     Builder.CreateAlignedStore(Val, Ptr, 4);
226 
227     if (Ty->isFloatingPointTy())
228       str += "%f";
229     else if (Ty->isIntegerTy())
230       str += "%ld";
231     else
232       str += "%s";
233 
234     Offset += 2;
235   }
236 
237   Value *Format = Builder.CreateGlobalStringPtr(str, "polly.vprintf.buffer", 4);
238   Format = Builder.CreateCall(getAddressSpaceCast(Builder, 4, 0), Format);
239 
240   Data = Builder.CreateBitCast(Data, Builder.getInt8PtrTy());
241 
242   Builder.CreateCall(getVPrintF(Builder), {Format, Data});
243 }
244 
245 Function *RuntimeDebugBuilder::getPrintF(PollyIRBuilder &Builder) {
246   Module *M = Builder.GetInsertBlock()->getParent()->getParent();
247   const char *Name = "printf";
248   Function *F = M->getFunction(Name);
249 
250   if (!F) {
251     GlobalValue::LinkageTypes Linkage = Function::ExternalLinkage;
252     FunctionType *Ty = FunctionType::get(Builder.getInt32Ty(), true);
253     F = Function::Create(Ty, Linkage, Name, M);
254   }
255 
256   return F;
257 }
258 
259 void RuntimeDebugBuilder::createPrintF(PollyIRBuilder &Builder,
260                                        std::string Format,
261                                        ArrayRef<Value *> Values) {
262   Value *FormatString = Builder.CreateGlobalStringPtr(Format);
263   std::vector<Value *> Arguments;
264 
265   Arguments.push_back(FormatString);
266   Arguments.insert(Arguments.end(), Values.begin(), Values.end());
267   Builder.CreateCall(getPrintF(Builder), Arguments);
268 }
269 
270 void RuntimeDebugBuilder::createFlush(PollyIRBuilder &Builder) {
271   Module *M = Builder.GetInsertBlock()->getParent()->getParent();
272   const char *Name = "fflush";
273   Function *F = M->getFunction(Name);
274 
275   if (!F) {
276     GlobalValue::LinkageTypes Linkage = Function::ExternalLinkage;
277     FunctionType *Ty =
278         FunctionType::get(Builder.getInt32Ty(), Builder.getInt8PtrTy(), false);
279     F = Function::Create(Ty, Linkage, Name, M);
280   }
281 
282   // fflush(NULL) flushes _all_ open output streams.
283   //
284   // fflush is declared as 'int fflush(FILE *stream)'. As we only pass on a NULL
285   // pointer, the type we point to does conceptually not matter. However, if
286   // fflush is already declared in this translation unit, we use the very same
287   // type to ensure that LLVM does not complain about mismatching types.
288   Builder.CreateCall(F, Constant::getNullValue(F->arg_begin()->getType()));
289 }
290