1 //===--- RuntimeDebugBuilder.cpp - Helper to insert prints into LLVM-IR ---===//
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
7 //===----------------------------------------------------------------------===//
9 //===----------------------------------------------------------------------===//
11 #include "polly/CodeGen/RuntimeDebugBuilder.h"
12 #include "llvm/IR/IntrinsicsNVPTX.h"
13 #include "llvm/IR/Module.h"
18 using namespace polly
;
20 Function
*RuntimeDebugBuilder::getVPrintF(PollyIRBuilder
&Builder
) {
21 Module
*M
= Builder
.GetInsertBlock()->getParent()->getParent();
22 const char *Name
= "vprintf";
23 Function
*F
= M
->getFunction(Name
);
26 GlobalValue::LinkageTypes Linkage
= Function::ExternalLinkage
;
27 FunctionType
*Ty
= FunctionType::get(
28 Builder
.getInt32Ty(), {Builder
.getInt8PtrTy(), Builder
.getInt8PtrTy()},
30 F
= Function::Create(Ty
, Linkage
, Name
, M
);
36 Function
*RuntimeDebugBuilder::getAddressSpaceCast(PollyIRBuilder
&Builder
,
37 unsigned Src
, unsigned Dst
,
40 Module
*M
= Builder
.GetInsertBlock()->getParent()->getParent();
41 auto Name
= std::string("llvm.nvvm.ptr.constant.to.gen.p") +
42 std::to_string(Dst
) + "i" + std::to_string(DstBits
) + ".p" +
43 std::to_string(Src
) + "i" + std::to_string(SrcBits
);
44 Function
*F
= M
->getFunction(Name
);
47 GlobalValue::LinkageTypes Linkage
= Function::ExternalLinkage
;
48 FunctionType
*Ty
= FunctionType::get(
49 PointerType::get(Builder
.getIntNTy(DstBits
), Dst
),
50 PointerType::get(Builder
.getIntNTy(SrcBits
), Src
), false);
51 F
= Function::Create(Ty
, Linkage
, Name
, M
);
58 RuntimeDebugBuilder::getGPUThreadIdentifiers(PollyIRBuilder
&Builder
) {
59 std::vector
<Value
*> Identifiers
;
61 auto M
= Builder
.GetInsertBlock()->getParent()->getParent();
63 std::vector
<Function
*> BlockIDs
= {
64 Intrinsic::getDeclaration(M
, Intrinsic::nvvm_read_ptx_sreg_ctaid_x
),
65 Intrinsic::getDeclaration(M
, Intrinsic::nvvm_read_ptx_sreg_ctaid_y
),
66 Intrinsic::getDeclaration(M
, Intrinsic::nvvm_read_ptx_sreg_ctaid_z
),
69 Identifiers
.push_back(Builder
.CreateGlobalStringPtr("> block-id: ", "", 4));
70 for (auto GetID
: BlockIDs
) {
71 Value
*Id
= Builder
.CreateCall(GetID
, {});
72 Id
= Builder
.CreateIntCast(Id
, Builder
.getInt64Ty(), false);
73 Identifiers
.push_back(Id
);
74 Identifiers
.push_back(Builder
.CreateGlobalStringPtr(" ", "", 4));
77 Identifiers
.push_back(Builder
.CreateGlobalStringPtr("| ", "", 4));
79 std::vector
<Function
*> ThreadIDs
= {
80 Intrinsic::getDeclaration(M
, Intrinsic::nvvm_read_ptx_sreg_tid_x
),
81 Intrinsic::getDeclaration(M
, Intrinsic::nvvm_read_ptx_sreg_tid_y
),
82 Intrinsic::getDeclaration(M
, Intrinsic::nvvm_read_ptx_sreg_tid_z
),
85 Identifiers
.push_back(Builder
.CreateGlobalStringPtr("thread-id: ", "", 4));
86 for (auto GetId
: ThreadIDs
) {
87 Value
*Id
= Builder
.CreateCall(GetId
, {});
88 Id
= Builder
.CreateIntCast(Id
, Builder
.getInt64Ty(), false);
89 Identifiers
.push_back(Id
);
90 Identifiers
.push_back(Builder
.CreateGlobalStringPtr(" ", "", 4));
96 void RuntimeDebugBuilder::createPrinter(PollyIRBuilder
&Builder
, bool IsGPU
,
97 ArrayRef
<Value
*> Values
) {
99 createGPUPrinterT(Builder
, Values
);
101 createCPUPrinterT(Builder
, Values
);
104 bool RuntimeDebugBuilder::isPrintable(Type
*Ty
) {
105 if (Ty
->isFloatingPointTy())
108 if (Ty
->isIntegerTy())
109 return Ty
->getIntegerBitWidth() <= 64;
111 if (isa
<PointerType
>(Ty
))
117 static std::tuple
<std::string
, std::vector
<Value
*>>
118 prepareValuesForPrinting(PollyIRBuilder
&Builder
, ArrayRef
<Value
*> Values
) {
119 std::string FormatString
;
120 std::vector
<Value
*> ValuesToPrint
;
122 for (auto Val
: Values
) {
123 Type
*Ty
= Val
->getType();
125 if (Ty
->isFloatingPointTy()) {
126 if (!Ty
->isDoubleTy())
127 Val
= Builder
.CreateFPExt(Val
, Builder
.getDoubleTy());
128 } else if (Ty
->isIntegerTy()) {
129 if (Ty
->getIntegerBitWidth() < 64)
130 Val
= Builder
.CreateSExt(Val
, Builder
.getInt64Ty());
132 assert(Ty
->getIntegerBitWidth() &&
133 "Integer types larger 64 bit not supported");
134 } else if (isa
<PointerType
>(Ty
)) {
135 if (Ty
->getPointerElementType() == Builder
.getInt8Ty() &&
136 Ty
->getPointerAddressSpace() == 4) {
137 Val
= Builder
.CreateGEP(Val
, Builder
.getInt64(0));
139 Val
= Builder
.CreatePtrToInt(Val
, Builder
.getInt64Ty());
142 llvm_unreachable("Unknown type");
147 if (Ty
->isFloatingPointTy())
148 FormatString
+= "%f";
149 else if (Ty
->isIntegerTy())
150 FormatString
+= "%ld";
152 FormatString
+= "%s";
154 ValuesToPrint
.push_back(Val
);
157 return std::make_tuple(FormatString
, ValuesToPrint
);
160 void RuntimeDebugBuilder::createCPUPrinterT(PollyIRBuilder
&Builder
,
161 ArrayRef
<Value
*> Values
) {
163 std::string FormatString
;
164 std::vector
<Value
*> ValuesToPrint
;
166 std::tie(FormatString
, ValuesToPrint
) =
167 prepareValuesForPrinting(Builder
, Values
);
169 createPrintF(Builder
, FormatString
, ValuesToPrint
);
170 createFlush(Builder
);
173 void RuntimeDebugBuilder::createGPUPrinterT(PollyIRBuilder
&Builder
,
174 ArrayRef
<Value
*> Values
) {
177 auto *Zero
= Builder
.getInt64(0);
179 auto ToPrint
= getGPUThreadIdentifiers(Builder
);
181 ToPrint
.push_back(Builder
.CreateGlobalStringPtr("\n ", "", 4));
182 ToPrint
.insert(ToPrint
.end(), Values
.begin(), Values
.end());
184 const DataLayout
&DL
= Builder
.GetInsertBlock()->getModule()->getDataLayout();
186 // Allocate print buffer (assuming 2*32 bit per element)
187 auto T
= ArrayType::get(Builder
.getInt32Ty(), ToPrint
.size() * 2);
188 Value
*Data
= new AllocaInst(
189 T
, DL
.getAllocaAddrSpace(), "polly.vprint.buffer",
190 &Builder
.GetInsertBlock()->getParent()->getEntryBlock().front());
191 auto *DataPtr
= Builder
.CreateGEP(Data
, {Zero
, Zero
});
194 for (auto Val
: ToPrint
) {
195 auto Ptr
= Builder
.CreateGEP(DataPtr
, Builder
.getInt64(Offset
));
196 Type
*Ty
= Val
->getType();
198 if (Ty
->isFloatingPointTy()) {
199 if (!Ty
->isDoubleTy())
200 Val
= Builder
.CreateFPExt(Val
, Builder
.getDoubleTy());
201 } else if (Ty
->isIntegerTy()) {
202 if (Ty
->getIntegerBitWidth() < 64) {
203 Val
= Builder
.CreateSExt(Val
, Builder
.getInt64Ty());
205 assert(Ty
->getIntegerBitWidth() == 64 &&
206 "Integer types larger 64 bit not supported");
209 } else if (auto PtTy
= dyn_cast
<PointerType
>(Ty
)) {
210 if (PtTy
->getAddressSpace() == 4) {
211 // Pointers in constant address space are printed as strings
212 Val
= Builder
.CreateGEP(Val
, Builder
.getInt64(0));
213 auto F
= RuntimeDebugBuilder::getAddressSpaceCast(Builder
, 4, 0);
214 Val
= Builder
.CreateCall(F
, Val
);
216 Val
= Builder
.CreatePtrToInt(Val
, Builder
.getInt64Ty());
219 llvm_unreachable("Unknown type");
223 Ptr
= Builder
.CreatePointerBitCastOrAddrSpaceCast(Ptr
, Ty
->getPointerTo(5));
224 Builder
.CreateAlignedStore(Val
, Ptr
, Align(4));
226 if (Ty
->isFloatingPointTy())
228 else if (Ty
->isIntegerTy())
236 Value
*Format
= Builder
.CreateGlobalStringPtr(str
, "polly.vprintf.buffer", 4);
237 Format
= Builder
.CreateCall(getAddressSpaceCast(Builder
, 4, 0), Format
);
239 Data
= Builder
.CreateBitCast(Data
, Builder
.getInt8PtrTy());
241 Builder
.CreateCall(getVPrintF(Builder
), {Format
, Data
});
244 Function
*RuntimeDebugBuilder::getPrintF(PollyIRBuilder
&Builder
) {
245 Module
*M
= Builder
.GetInsertBlock()->getParent()->getParent();
246 const char *Name
= "printf";
247 Function
*F
= M
->getFunction(Name
);
250 GlobalValue::LinkageTypes Linkage
= Function::ExternalLinkage
;
251 FunctionType
*Ty
= FunctionType::get(Builder
.getInt32Ty(), true);
252 F
= Function::Create(Ty
, Linkage
, Name
, M
);
258 void RuntimeDebugBuilder::createPrintF(PollyIRBuilder
&Builder
,
260 ArrayRef
<Value
*> Values
) {
261 Value
*FormatString
= Builder
.CreateGlobalStringPtr(Format
);
262 std::vector
<Value
*> Arguments
;
264 Arguments
.push_back(FormatString
);
265 Arguments
.insert(Arguments
.end(), Values
.begin(), Values
.end());
266 Builder
.CreateCall(getPrintF(Builder
), Arguments
);
269 void RuntimeDebugBuilder::createFlush(PollyIRBuilder
&Builder
) {
270 Module
*M
= Builder
.GetInsertBlock()->getParent()->getParent();
271 const char *Name
= "fflush";
272 Function
*F
= M
->getFunction(Name
);
275 GlobalValue::LinkageTypes Linkage
= Function::ExternalLinkage
;
277 FunctionType::get(Builder
.getInt32Ty(), Builder
.getInt8PtrTy(), false);
278 F
= Function::Create(Ty
, Linkage
, Name
, M
);
281 // fflush(NULL) flushes _all_ open output streams.
283 // fflush is declared as 'int fflush(FILE *stream)'. As we only pass on a NULL
284 // pointer, the type we point to does conceptually not matter. However, if
285 // fflush is already declared in this translation unit, we use the very same
286 // type to ensure that LLVM does not complain about mismatching types.
287 Builder
.CreateCall(F
, Constant::getNullValue(F
->arg_begin()->getType()));