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