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