1 | //===- ScopDetectionDiagnostic.cpp - Error diagnostics --------------------===// |
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 | // Small set of diagnostic helper classes to encapsulate any errors occurred |
10 | // during the detection of Scops. |
11 | // |
12 | // The ScopDetection defines a set of error classes (via Statistic variables) |
13 | // that groups a number of individual errors into a group, e.g. non-affinity |
14 | // related errors. |
15 | // On error we generate an object that carries enough additional information |
16 | // to diagnose the error and generate a helpful error message. |
17 | // |
18 | //===----------------------------------------------------------------------===// |
19 | |
20 | #include "polly/ScopDetectionDiagnostic.h" |
21 | #include "llvm/ADT/SmallPtrSet.h" |
22 | #include "llvm/ADT/SmallVector.h" |
23 | #include "llvm/ADT/Statistic.h" |
24 | #include "llvm/ADT/StringRef.h" |
25 | #include "llvm/ADT/Twine.h" |
26 | #include "llvm/Analysis/AliasSetTracker.h" |
27 | #include "llvm/Analysis/LoopInfo.h" |
28 | #include "llvm/Analysis/OptimizationRemarkEmitter.h" |
29 | #include "llvm/Analysis/RegionInfo.h" |
30 | #include "llvm/Analysis/ScalarEvolution.h" |
31 | #include "llvm/IR/BasicBlock.h" |
32 | #include "llvm/IR/CFG.h" |
33 | #include "llvm/IR/DebugLoc.h" |
34 | #include "llvm/IR/DiagnosticInfo.h" |
35 | #include "llvm/IR/Instruction.h" |
36 | #include "llvm/IR/Value.h" |
37 | #include "llvm/Support/raw_ostream.h" |
38 | #include <algorithm> |
39 | #include <cassert> |
40 | #include <string> |
41 | #include <utility> |
42 | |
43 | using namespace llvm; |
44 | |
45 | #define DEBUG_TYPE "polly-detect" |
46 | |
47 | #define SCOP_STAT(NAME, DESC) \ |
48 | {"polly-detect", "NAME", "Number of rejected regions: " DESC} |
49 | |
50 | static Statistic RejectStatistics[] = { |
51 | SCOP_STAT(CFG, "" ), |
52 | SCOP_STAT(InvalidTerminator, "Unsupported terminator instruction" ), |
53 | SCOP_STAT(IrreducibleRegion, "Irreducible loops" ), |
54 | SCOP_STAT(UnreachableInExit, "Unreachable in exit block" ), |
55 | SCOP_STAT(IndirectPredecessor, "Branch from indirect terminator" ), |
56 | SCOP_STAT(LastCFG, "" ), |
57 | SCOP_STAT(AffFunc, "" ), |
58 | SCOP_STAT(UndefCond, "Undefined branch condition" ), |
59 | SCOP_STAT(InvalidCond, "Non-integer branch condition" ), |
60 | SCOP_STAT(UndefOperand, "Undefined operands in comparison" ), |
61 | SCOP_STAT(NonAffBranch, "Non-affine branch condition" ), |
62 | SCOP_STAT(NoBasePtr, "No base pointer" ), |
63 | SCOP_STAT(UndefBasePtr, "Undefined base pointer" ), |
64 | SCOP_STAT(VariantBasePtr, "Variant base pointer" ), |
65 | SCOP_STAT(NonAffineAccess, "Non-affine memory accesses" ), |
66 | SCOP_STAT(DifferentElementSize, "Accesses with differing sizes" ), |
67 | SCOP_STAT(LastAffFunc, "" ), |
68 | SCOP_STAT(LoopBound, "Uncomputable loop bounds" ), |
69 | SCOP_STAT(LoopHasNoExit, "Loop without exit" ), |
70 | SCOP_STAT(LoopHasMultipleExits, "Loop with multiple exits" ), |
71 | SCOP_STAT(LoopOnlySomeLatches, "Not all loop latches in scop" ), |
72 | SCOP_STAT(FuncCall, "Function call with side effects" ), |
73 | SCOP_STAT(NonSimpleMemoryAccess, |
74 | "Compilated access semantics (volatile or atomic)" ), |
75 | SCOP_STAT(Alias, "Base address aliasing" ), |
76 | SCOP_STAT(Other, "" ), |
77 | SCOP_STAT(IntToPtr, "Integer to pointer conversions" ), |
78 | SCOP_STAT(Alloca, "Stack allocations" ), |
79 | SCOP_STAT(UnknownInst, "Unknown Instructions" ), |
80 | SCOP_STAT(Entry, "Contains entry block" ), |
81 | SCOP_STAT(Unprofitable, "Assumed to be unprofitable" ), |
82 | SCOP_STAT(LastOther, "" ), |
83 | }; |
84 | |
85 | namespace polly { |
86 | |
87 | /// Small string conversion via raw_string_stream. |
88 | template <typename T> std::string operator+(Twine LHS, const T &RHS) { |
89 | std::string Buf; |
90 | raw_string_ostream fmt(Buf); |
91 | fmt << RHS; |
92 | fmt.flush(); |
93 | |
94 | return LHS.concat(Suffix: Buf).str(); |
95 | } |
96 | } // namespace polly |
97 | |
98 | namespace llvm { |
99 | |
100 | // Lexicographic order on (line, col) of our debug locations. |
101 | static bool operator<(const DebugLoc &LHS, const DebugLoc &RHS) { |
102 | return LHS.getLine() < RHS.getLine() || |
103 | (LHS.getLine() == RHS.getLine() && LHS.getCol() < RHS.getCol()); |
104 | } |
105 | } // namespace llvm |
106 | |
107 | namespace polly { |
108 | |
109 | BBPair getBBPairForRegion(const Region *R) { |
110 | return std::make_pair(x: R->getEntry(), y: R->getExit()); |
111 | } |
112 | |
113 | void getDebugLocations(const BBPair &P, DebugLoc &Begin, DebugLoc &End) { |
114 | SmallPtrSet<BasicBlock *, 32> Seen; |
115 | SmallVector<BasicBlock *, 32> Todo; |
116 | Todo.push_back(Elt: P.first); |
117 | while (!Todo.empty()) { |
118 | auto *BB = Todo.pop_back_val(); |
119 | if (BB == P.second) |
120 | continue; |
121 | if (!Seen.insert(Ptr: BB).second) |
122 | continue; |
123 | Todo.append(in_start: succ_begin(BB), in_end: succ_end(BB)); |
124 | for (const Instruction &Inst : *BB) { |
125 | DebugLoc DL = Inst.getStableDebugLoc(); |
126 | if (!DL) |
127 | continue; |
128 | |
129 | Begin = Begin ? std::min(a: Begin, b: DL) : DL; |
130 | End = End ? std::max(a: End, b: DL) : DL; |
131 | } |
132 | } |
133 | } |
134 | |
135 | void (const BBPair &P, const RejectLog &Log, |
136 | OptimizationRemarkEmitter &ORE) { |
137 | DebugLoc Begin, End; |
138 | getDebugLocations(P, Begin, End); |
139 | |
140 | ORE.emit( |
141 | OptDiag&: OptimizationRemarkMissed(DEBUG_TYPE, "RejectionErrors" , Begin, P.first) |
142 | << "The following errors keep this region from being a Scop." ); |
143 | |
144 | for (RejectReasonPtr RR : Log) { |
145 | |
146 | if (const DebugLoc &Loc = RR->getDebugLoc()) |
147 | ORE.emit(OptDiag&: OptimizationRemarkMissed(DEBUG_TYPE, RR->getRemarkName(), Loc, |
148 | RR->getRemarkBB()) |
149 | << RR->getEndUserMessage()); |
150 | else |
151 | ORE.emit(OptDiag&: OptimizationRemarkMissed(DEBUG_TYPE, RR->getRemarkName(), Begin, |
152 | RR->getRemarkBB()) |
153 | << RR->getEndUserMessage()); |
154 | } |
155 | |
156 | /* Check to see if Region is a top level region, getExit = NULL*/ |
157 | if (P.second) |
158 | ORE.emit( |
159 | OptDiag&: OptimizationRemarkMissed(DEBUG_TYPE, "InvalidScopEnd" , End, P.second) |
160 | << "Invalid Scop candidate ends here." ); |
161 | else |
162 | ORE.emit( |
163 | OptDiag&: OptimizationRemarkMissed(DEBUG_TYPE, "InvalidScopEnd" , End, P.first) |
164 | << "Invalid Scop candidate ends here." ); |
165 | } |
166 | |
167 | //===----------------------------------------------------------------------===// |
168 | // RejectReason. |
169 | |
170 | RejectReason::RejectReason(RejectReasonKind K) : Kind(K) { |
171 | RejectStatistics[static_cast<int>(K)]++; |
172 | } |
173 | |
174 | const DebugLoc RejectReason::Unknown = DebugLoc(); |
175 | |
176 | const DebugLoc &RejectReason::getDebugLoc() const { |
177 | // Allocate an empty DebugLoc and return it a reference to it. |
178 | return Unknown; |
179 | } |
180 | |
181 | // RejectLog. |
182 | void RejectLog::print(raw_ostream &OS, int level) const { |
183 | int j = 0; |
184 | for (auto Reason : ErrorReports) |
185 | OS.indent(NumSpaces: level) << "[" << j++ << "] " << Reason->getMessage() << "\n" ; |
186 | } |
187 | |
188 | //===----------------------------------------------------------------------===// |
189 | // ReportCFG. |
190 | |
191 | ReportCFG::ReportCFG(const RejectReasonKind K) : RejectReason(K) {} |
192 | |
193 | bool ReportCFG::classof(const RejectReason *RR) { |
194 | return RR->getKind() >= RejectReasonKind::CFG && |
195 | RR->getKind() <= RejectReasonKind::LastCFG; |
196 | } |
197 | |
198 | //===----------------------------------------------------------------------===// |
199 | // ReportInvalidTerminator. |
200 | |
201 | std::string ReportInvalidTerminator::() const { |
202 | return "InvalidTerminator" ; |
203 | } |
204 | |
205 | const Value *ReportInvalidTerminator::() const { return BB; } |
206 | |
207 | std::string ReportInvalidTerminator::getMessage() const { |
208 | return ("Invalid instruction terminates BB: " + BB->getName()).str(); |
209 | } |
210 | |
211 | const DebugLoc &ReportInvalidTerminator::getDebugLoc() const { |
212 | return BB->getTerminator()->getDebugLoc(); |
213 | } |
214 | |
215 | bool ReportInvalidTerminator::classof(const RejectReason *RR) { |
216 | return RR->getKind() == RejectReasonKind::InvalidTerminator; |
217 | } |
218 | |
219 | //===----------------------------------------------------------------------===// |
220 | // UnreachableInExit. |
221 | |
222 | std::string ReportUnreachableInExit::() const { |
223 | return "UnreachableInExit" ; |
224 | } |
225 | |
226 | const Value *ReportUnreachableInExit::() const { return BB; } |
227 | |
228 | std::string ReportUnreachableInExit::getMessage() const { |
229 | std::string BBName = BB->getName().str(); |
230 | return "Unreachable in exit block" + BBName; |
231 | } |
232 | |
233 | const DebugLoc &ReportUnreachableInExit::getDebugLoc() const { return DbgLoc; } |
234 | |
235 | std::string ReportUnreachableInExit::getEndUserMessage() const { |
236 | return "Unreachable in exit block." ; |
237 | } |
238 | |
239 | bool ReportUnreachableInExit::classof(const RejectReason *RR) { |
240 | return RR->getKind() == RejectReasonKind::UnreachableInExit; |
241 | } |
242 | |
243 | //===----------------------------------------------------------------------===// |
244 | // IndirectPredecessor. |
245 | |
246 | std::string ReportIndirectPredecessor::() const { |
247 | return "IndirectPredecessor" ; |
248 | } |
249 | |
250 | const Value *ReportIndirectPredecessor::() const { |
251 | if (Inst) |
252 | return Inst->getParent(); |
253 | return nullptr; |
254 | } |
255 | |
256 | std::string ReportIndirectPredecessor::getMessage() const { |
257 | if (Inst) |
258 | return "Branch from indirect terminator: " + *Inst; |
259 | return getEndUserMessage(); |
260 | } |
261 | |
262 | const DebugLoc &ReportIndirectPredecessor::getDebugLoc() const { |
263 | return DbgLoc; |
264 | } |
265 | |
266 | std::string ReportIndirectPredecessor::getEndUserMessage() const { |
267 | return "Branch from indirect terminator." ; |
268 | } |
269 | |
270 | bool ReportIndirectPredecessor::classof(const RejectReason *RR) { |
271 | return RR->getKind() == RejectReasonKind::IndirectPredecessor; |
272 | } |
273 | |
274 | //===----------------------------------------------------------------------===// |
275 | // ReportIrreducibleRegion. |
276 | |
277 | std::string ReportIrreducibleRegion::() const { |
278 | return "IrreducibleRegion" ; |
279 | } |
280 | |
281 | const Value *ReportIrreducibleRegion::() const { |
282 | return R->getEntry(); |
283 | } |
284 | |
285 | std::string ReportIrreducibleRegion::getMessage() const { |
286 | return "Irreducible region encountered: " + R->getNameStr(); |
287 | } |
288 | |
289 | const DebugLoc &ReportIrreducibleRegion::getDebugLoc() const { return DbgLoc; } |
290 | |
291 | std::string ReportIrreducibleRegion::getEndUserMessage() const { |
292 | return "Irreducible region encountered in control flow." ; |
293 | } |
294 | |
295 | bool ReportIrreducibleRegion::classof(const RejectReason *RR) { |
296 | return RR->getKind() == RejectReasonKind::IrreducibleRegion; |
297 | } |
298 | |
299 | //===----------------------------------------------------------------------===// |
300 | // ReportAffFunc. |
301 | |
302 | ReportAffFunc::ReportAffFunc(const RejectReasonKind K, const Instruction *Inst) |
303 | : RejectReason(K), Inst(Inst) {} |
304 | |
305 | bool ReportAffFunc::classof(const RejectReason *RR) { |
306 | return RR->getKind() >= RejectReasonKind::AffFunc && |
307 | RR->getKind() <= RejectReasonKind::LastAffFunc; |
308 | } |
309 | |
310 | //===----------------------------------------------------------------------===// |
311 | // ReportUndefCond. |
312 | |
313 | std::string ReportUndefCond::() const { return "UndefCond" ; } |
314 | |
315 | const Value *ReportUndefCond::() const { return BB; } |
316 | |
317 | std::string ReportUndefCond::getMessage() const { |
318 | return ("Condition based on 'undef' value in BB: " + BB->getName()).str(); |
319 | } |
320 | |
321 | bool ReportUndefCond::classof(const RejectReason *RR) { |
322 | return RR->getKind() == RejectReasonKind::UndefCond; |
323 | } |
324 | |
325 | //===----------------------------------------------------------------------===// |
326 | // ReportInvalidCond. |
327 | |
328 | std::string ReportInvalidCond::() const { return "InvalidCond" ; } |
329 | |
330 | const Value *ReportInvalidCond::() const { return BB; } |
331 | |
332 | std::string ReportInvalidCond::getMessage() const { |
333 | return ("Condition in BB '" + BB->getName()).str() + |
334 | "' neither constant nor an icmp instruction" ; |
335 | } |
336 | |
337 | bool ReportInvalidCond::classof(const RejectReason *RR) { |
338 | return RR->getKind() == RejectReasonKind::InvalidCond; |
339 | } |
340 | |
341 | //===----------------------------------------------------------------------===// |
342 | // ReportUndefOperand. |
343 | |
344 | std::string ReportUndefOperand::getRemarkName() const { return "UndefOperand" ; } |
345 | |
346 | const Value *ReportUndefOperand::getRemarkBB() const { return BB; } |
347 | |
348 | std::string ReportUndefOperand::getMessage() const { |
349 | return ("undef operand in branch at BB: " + BB->getName()).str(); |
350 | } |
351 | |
352 | bool ReportUndefOperand::classof(const RejectReason *RR) { |
353 | return RR->getKind() == RejectReasonKind::UndefOperand; |
354 | } |
355 | |
356 | //===----------------------------------------------------------------------===// |
357 | // ReportNonAffBranch. |
358 | |
359 | std::string ReportNonAffBranch::() const { return "NonAffBranch" ; } |
360 | |
361 | const Value *ReportNonAffBranch::() const { return BB; } |
362 | |
363 | std::string ReportNonAffBranch::getMessage() const { |
364 | return ("Non affine branch in BB '" + BB->getName()).str() + |
365 | "' with LHS: " + *LHS + " and RHS: " + *RHS; |
366 | } |
367 | |
368 | bool ReportNonAffBranch::classof(const RejectReason *RR) { |
369 | return RR->getKind() == RejectReasonKind::NonAffBranch; |
370 | } |
371 | |
372 | //===----------------------------------------------------------------------===// |
373 | // ReportNoBasePtr. |
374 | |
375 | std::string ReportNoBasePtr::() const { return "NoBasePtr" ; } |
376 | |
377 | const Value *ReportNoBasePtr::() const { return Inst->getParent(); } |
378 | |
379 | std::string ReportNoBasePtr::getMessage() const { return "No base pointer" ; } |
380 | |
381 | bool ReportNoBasePtr::classof(const RejectReason *RR) { |
382 | return RR->getKind() == RejectReasonKind::NoBasePtr; |
383 | } |
384 | |
385 | //===----------------------------------------------------------------------===// |
386 | // ReportUndefBasePtr. |
387 | |
388 | std::string ReportUndefBasePtr::() const { return "UndefBasePtr" ; } |
389 | |
390 | const Value *ReportUndefBasePtr::() const { |
391 | return Inst->getParent(); |
392 | } |
393 | |
394 | std::string ReportUndefBasePtr::getMessage() const { |
395 | return "Undefined base pointer" ; |
396 | } |
397 | |
398 | bool ReportUndefBasePtr::classof(const RejectReason *RR) { |
399 | return RR->getKind() == RejectReasonKind::UndefBasePtr; |
400 | } |
401 | |
402 | //===----------------------------------------------------------------------===// |
403 | // ReportVariantBasePtr. |
404 | |
405 | std::string ReportVariantBasePtr::() const { |
406 | return "VariantBasePtr" ; |
407 | } |
408 | |
409 | const Value *ReportVariantBasePtr::() const { |
410 | return Inst->getParent(); |
411 | } |
412 | |
413 | std::string ReportVariantBasePtr::getMessage() const { |
414 | return "Base address not invariant in current region:" + *BaseValue; |
415 | } |
416 | |
417 | std::string ReportVariantBasePtr::getEndUserMessage() const { |
418 | return "The base address of this array is not invariant inside the loop" ; |
419 | } |
420 | |
421 | bool ReportVariantBasePtr::classof(const RejectReason *RR) { |
422 | return RR->getKind() == RejectReasonKind::VariantBasePtr; |
423 | } |
424 | |
425 | //===----------------------------------------------------------------------===// |
426 | // ReportDifferentArrayElementSize |
427 | |
428 | std::string ReportDifferentArrayElementSize::() const { |
429 | return "DifferentArrayElementSize" ; |
430 | } |
431 | |
432 | const Value *ReportDifferentArrayElementSize::() const { |
433 | return Inst->getParent(); |
434 | } |
435 | |
436 | std::string ReportDifferentArrayElementSize::getMessage() const { |
437 | return "Access to one array through data types of different size" ; |
438 | } |
439 | |
440 | bool ReportDifferentArrayElementSize::classof(const RejectReason *RR) { |
441 | return RR->getKind() == RejectReasonKind::DifferentElementSize; |
442 | } |
443 | |
444 | std::string ReportDifferentArrayElementSize::getEndUserMessage() const { |
445 | StringRef BaseName = BaseValue->getName(); |
446 | std::string Name = BaseName.empty() ? "UNKNOWN" : BaseName.str(); |
447 | return "The array \"" + Name + |
448 | "\" is accessed through elements that differ " |
449 | "in size" ; |
450 | } |
451 | |
452 | //===----------------------------------------------------------------------===// |
453 | // ReportNonAffineAccess. |
454 | |
455 | std::string ReportNonAffineAccess::() const { |
456 | return "NonAffineAccess" ; |
457 | } |
458 | |
459 | const Value *ReportNonAffineAccess::() const { |
460 | return Inst->getParent(); |
461 | } |
462 | |
463 | std::string ReportNonAffineAccess::getMessage() const { |
464 | return "Non affine access function: " + *AccessFunction; |
465 | } |
466 | |
467 | bool ReportNonAffineAccess::classof(const RejectReason *RR) { |
468 | return RR->getKind() == RejectReasonKind::NonAffineAccess; |
469 | } |
470 | |
471 | std::string ReportNonAffineAccess::getEndUserMessage() const { |
472 | StringRef BaseName = BaseValue->getName(); |
473 | std::string Name = BaseName.empty() ? "UNKNOWN" : BaseName.str(); |
474 | return "The array subscript of \"" + Name + "\" is not affine" ; |
475 | } |
476 | |
477 | //===----------------------------------------------------------------------===// |
478 | // ReportLoopBound. |
479 | |
480 | ReportLoopBound::ReportLoopBound(Loop *L, const SCEV *LoopCount) |
481 | : RejectReason(RejectReasonKind::LoopBound), L(L), LoopCount(LoopCount), |
482 | Loc(L->getStartLoc()) {} |
483 | |
484 | std::string ReportLoopBound::() const { return "LoopBound" ; } |
485 | |
486 | const Value *ReportLoopBound::() const { return L->getHeader(); } |
487 | |
488 | std::string ReportLoopBound::getMessage() const { |
489 | return "Non affine loop bound '" + *LoopCount + |
490 | "' in loop: " + L->getHeader()->getName(); |
491 | } |
492 | |
493 | const DebugLoc &ReportLoopBound::getDebugLoc() const { return Loc; } |
494 | |
495 | bool ReportLoopBound::classof(const RejectReason *RR) { |
496 | return RR->getKind() == RejectReasonKind::LoopBound; |
497 | } |
498 | |
499 | std::string ReportLoopBound::getEndUserMessage() const { |
500 | return "Failed to derive an affine function from the loop bounds." ; |
501 | } |
502 | |
503 | //===----------------------------------------------------------------------===// |
504 | // ReportLoopHasNoExit. |
505 | |
506 | std::string ReportLoopHasNoExit::() const { |
507 | return "LoopHasNoExit" ; |
508 | } |
509 | |
510 | const Value *ReportLoopHasNoExit::() const { return L->getHeader(); } |
511 | |
512 | std::string ReportLoopHasNoExit::getMessage() const { |
513 | return "Loop " + L->getHeader()->getName() + " has no exit." ; |
514 | } |
515 | |
516 | bool ReportLoopHasNoExit::classof(const RejectReason *RR) { |
517 | return RR->getKind() == RejectReasonKind::LoopHasNoExit; |
518 | } |
519 | |
520 | const DebugLoc &ReportLoopHasNoExit::getDebugLoc() const { return Loc; } |
521 | |
522 | std::string ReportLoopHasNoExit::getEndUserMessage() const { |
523 | return "Loop cannot be handled because it has no exit." ; |
524 | } |
525 | |
526 | //===----------------------------------------------------------------------===// |
527 | // ReportLoopHasMultipleExits. |
528 | |
529 | std::string ReportLoopHasMultipleExits::() const { |
530 | return "ReportLoopHasMultipleExits" ; |
531 | } |
532 | |
533 | const Value *ReportLoopHasMultipleExits::() const { |
534 | return L->getHeader(); |
535 | } |
536 | |
537 | std::string ReportLoopHasMultipleExits::getMessage() const { |
538 | return "Loop " + L->getHeader()->getName() + " has multiple exits." ; |
539 | } |
540 | |
541 | bool ReportLoopHasMultipleExits::classof(const RejectReason *RR) { |
542 | return RR->getKind() == RejectReasonKind::LoopHasMultipleExits; |
543 | } |
544 | |
545 | const DebugLoc &ReportLoopHasMultipleExits::getDebugLoc() const { return Loc; } |
546 | |
547 | std::string ReportLoopHasMultipleExits::getEndUserMessage() const { |
548 | return "Loop cannot be handled because it has multiple exits." ; |
549 | } |
550 | |
551 | //===----------------------------------------------------------------------===// |
552 | // ReportLoopOnlySomeLatches |
553 | |
554 | std::string ReportLoopOnlySomeLatches::() const { |
555 | return "LoopHasNoExit" ; |
556 | } |
557 | |
558 | const Value *ReportLoopOnlySomeLatches::() const { |
559 | return L->getHeader(); |
560 | } |
561 | |
562 | std::string ReportLoopOnlySomeLatches::getMessage() const { |
563 | return "Not all latches of loop " + L->getHeader()->getName() + |
564 | " part of scop." ; |
565 | } |
566 | |
567 | bool ReportLoopOnlySomeLatches::classof(const RejectReason *RR) { |
568 | return RR->getKind() == RejectReasonKind::LoopHasNoExit; |
569 | } |
570 | |
571 | const DebugLoc &ReportLoopOnlySomeLatches::getDebugLoc() const { return Loc; } |
572 | |
573 | std::string ReportLoopOnlySomeLatches::getEndUserMessage() const { |
574 | return "Loop cannot be handled because not all latches are part of loop " |
575 | "region." ; |
576 | } |
577 | |
578 | //===----------------------------------------------------------------------===// |
579 | // ReportFuncCall. |
580 | |
581 | ReportFuncCall::ReportFuncCall(Instruction *Inst) |
582 | : RejectReason(RejectReasonKind::FuncCall), Inst(Inst) {} |
583 | |
584 | std::string ReportFuncCall::() const { return "FuncCall" ; } |
585 | |
586 | const Value *ReportFuncCall::() const { return Inst->getParent(); } |
587 | |
588 | std::string ReportFuncCall::getMessage() const { |
589 | return "Call instruction: " + *Inst; |
590 | } |
591 | |
592 | const DebugLoc &ReportFuncCall::getDebugLoc() const { |
593 | return Inst->getDebugLoc(); |
594 | } |
595 | |
596 | std::string ReportFuncCall::getEndUserMessage() const { |
597 | return "This function call cannot be handled. " |
598 | "Try to inline it." ; |
599 | } |
600 | |
601 | bool ReportFuncCall::classof(const RejectReason *RR) { |
602 | return RR->getKind() == RejectReasonKind::FuncCall; |
603 | } |
604 | |
605 | //===----------------------------------------------------------------------===// |
606 | // ReportNonSimpleMemoryAccess |
607 | |
608 | ReportNonSimpleMemoryAccess::ReportNonSimpleMemoryAccess(Instruction *Inst) |
609 | : ReportOther(RejectReasonKind::NonSimpleMemoryAccess), Inst(Inst) {} |
610 | |
611 | std::string ReportNonSimpleMemoryAccess::() const { |
612 | return "NonSimpleMemoryAccess" ; |
613 | } |
614 | |
615 | const Value *ReportNonSimpleMemoryAccess::() const { |
616 | return Inst->getParent(); |
617 | } |
618 | |
619 | std::string ReportNonSimpleMemoryAccess::getMessage() const { |
620 | return "Non-simple memory access: " + *Inst; |
621 | } |
622 | |
623 | const DebugLoc &ReportNonSimpleMemoryAccess::getDebugLoc() const { |
624 | return Inst->getDebugLoc(); |
625 | } |
626 | |
627 | std::string ReportNonSimpleMemoryAccess::getEndUserMessage() const { |
628 | return "Volatile memory accesses or memory accesses for atomic types " |
629 | "are not supported." ; |
630 | } |
631 | |
632 | bool ReportNonSimpleMemoryAccess::classof(const RejectReason *RR) { |
633 | return RR->getKind() == RejectReasonKind::NonSimpleMemoryAccess; |
634 | } |
635 | |
636 | //===----------------------------------------------------------------------===// |
637 | // ReportAlias. |
638 | |
639 | ReportAlias::ReportAlias(Instruction *Inst, AliasSet &AS) |
640 | : RejectReason(RejectReasonKind::Alias), Inst(Inst) { |
641 | append_range(C&: Pointers, R: AS.getPointers()); |
642 | } |
643 | |
644 | std::string ReportAlias::formatInvalidAlias(std::string Prefix, |
645 | std::string Suffix) const { |
646 | std::string Message; |
647 | raw_string_ostream OS(Message); |
648 | |
649 | OS << Prefix; |
650 | |
651 | for (PointerSnapshotTy::const_iterator PI = Pointers.begin(), |
652 | PE = Pointers.end(); |
653 | ;) { |
654 | const Value *V = *PI; |
655 | assert(V && "Diagnostic info does not match found LLVM-IR anymore." ); |
656 | |
657 | if (V->getName().empty()) |
658 | OS << "\" <unknown> \"" ; |
659 | else |
660 | OS << "\"" << V->getName() << "\"" ; |
661 | |
662 | ++PI; |
663 | |
664 | if (PI != PE) |
665 | OS << ", " ; |
666 | else |
667 | break; |
668 | } |
669 | |
670 | OS << Suffix; |
671 | |
672 | return OS.str(); |
673 | } |
674 | |
675 | std::string ReportAlias::() const { return "Alias" ; } |
676 | |
677 | const Value *ReportAlias::() const { return Inst->getParent(); } |
678 | |
679 | std::string ReportAlias::getMessage() const { |
680 | return formatInvalidAlias(Prefix: "Possible aliasing: " ); |
681 | } |
682 | |
683 | std::string ReportAlias::getEndUserMessage() const { |
684 | return formatInvalidAlias(Prefix: "Accesses to the arrays " , |
685 | Suffix: " may access the same memory." ); |
686 | } |
687 | |
688 | const DebugLoc &ReportAlias::getDebugLoc() const { return Inst->getDebugLoc(); } |
689 | |
690 | bool ReportAlias::classof(const RejectReason *RR) { |
691 | return RR->getKind() == RejectReasonKind::Alias; |
692 | } |
693 | |
694 | //===----------------------------------------------------------------------===// |
695 | // ReportOther. |
696 | |
697 | std::string ReportOther::() const { return "UnknownRejectReason" ; } |
698 | |
699 | std::string ReportOther::getMessage() const { return "Unknown reject reason" ; } |
700 | |
701 | ReportOther::ReportOther(const RejectReasonKind K) : RejectReason(K) {} |
702 | |
703 | bool ReportOther::classof(const RejectReason *RR) { |
704 | return RR->getKind() >= RejectReasonKind::Other && |
705 | RR->getKind() <= RejectReasonKind::LastOther; |
706 | } |
707 | |
708 | //===----------------------------------------------------------------------===// |
709 | // ReportIntToPtr. |
710 | ReportIntToPtr::ReportIntToPtr(Instruction *BaseValue) |
711 | : ReportOther(RejectReasonKind::IntToPtr), BaseValue(BaseValue) {} |
712 | |
713 | std::string ReportIntToPtr::() const { return "IntToPtr" ; } |
714 | |
715 | const Value *ReportIntToPtr::() const { |
716 | return BaseValue->getParent(); |
717 | } |
718 | |
719 | std::string ReportIntToPtr::getMessage() const { |
720 | return "Find bad intToptr prt: " + *BaseValue; |
721 | } |
722 | |
723 | const DebugLoc &ReportIntToPtr::getDebugLoc() const { |
724 | return BaseValue->getDebugLoc(); |
725 | } |
726 | |
727 | bool ReportIntToPtr::classof(const RejectReason *RR) { |
728 | return RR->getKind() == RejectReasonKind::IntToPtr; |
729 | } |
730 | |
731 | //===----------------------------------------------------------------------===// |
732 | // ReportAlloca. |
733 | |
734 | ReportAlloca::ReportAlloca(Instruction *Inst) |
735 | : ReportOther(RejectReasonKind::Alloca), Inst(Inst) {} |
736 | |
737 | std::string ReportAlloca::() const { return "Alloca" ; } |
738 | |
739 | const Value *ReportAlloca::() const { return Inst->getParent(); } |
740 | |
741 | std::string ReportAlloca::getMessage() const { |
742 | return "Alloca instruction: " + *Inst; |
743 | } |
744 | |
745 | const DebugLoc &ReportAlloca::getDebugLoc() const { |
746 | return Inst->getDebugLoc(); |
747 | } |
748 | |
749 | bool ReportAlloca::classof(const RejectReason *RR) { |
750 | return RR->getKind() == RejectReasonKind::Alloca; |
751 | } |
752 | |
753 | //===----------------------------------------------------------------------===// |
754 | // ReportUnknownInst. |
755 | |
756 | ReportUnknownInst::ReportUnknownInst(Instruction *Inst) |
757 | : ReportOther(RejectReasonKind::UnknownInst), Inst(Inst) {} |
758 | |
759 | std::string ReportUnknownInst::() const { return "UnknownInst" ; } |
760 | |
761 | const Value *ReportUnknownInst::() const { |
762 | return Inst->getParent(); |
763 | } |
764 | |
765 | std::string ReportUnknownInst::getMessage() const { |
766 | return "Unknown instruction: " + *Inst; |
767 | } |
768 | |
769 | const DebugLoc &ReportUnknownInst::getDebugLoc() const { |
770 | return Inst->getDebugLoc(); |
771 | } |
772 | |
773 | bool ReportUnknownInst::classof(const RejectReason *RR) { |
774 | return RR->getKind() == RejectReasonKind::UnknownInst; |
775 | } |
776 | |
777 | //===----------------------------------------------------------------------===// |
778 | // ReportEntry. |
779 | |
780 | ReportEntry::ReportEntry(BasicBlock *BB) |
781 | : ReportOther(RejectReasonKind::Entry), BB(BB) {} |
782 | |
783 | std::string ReportEntry::() const { return "Entry" ; } |
784 | |
785 | const Value *ReportEntry::() const { return BB; } |
786 | |
787 | std::string ReportEntry::getMessage() const { |
788 | return "Region containing entry block of function is invalid!" ; |
789 | } |
790 | |
791 | std::string ReportEntry::getEndUserMessage() const { |
792 | return "Scop contains function entry (not yet supported)." ; |
793 | } |
794 | |
795 | const DebugLoc &ReportEntry::getDebugLoc() const { |
796 | return BB->getTerminator()->getDebugLoc(); |
797 | } |
798 | |
799 | bool ReportEntry::classof(const RejectReason *RR) { |
800 | return RR->getKind() == RejectReasonKind::Entry; |
801 | } |
802 | |
803 | //===----------------------------------------------------------------------===// |
804 | // ReportUnprofitable. |
805 | |
806 | ReportUnprofitable::ReportUnprofitable(Region *R) |
807 | : ReportOther(RejectReasonKind::Unprofitable), R(R) {} |
808 | |
809 | std::string ReportUnprofitable::() const { return "Unprofitable" ; } |
810 | |
811 | const Value *ReportUnprofitable::() const { return R->getEntry(); } |
812 | |
813 | std::string ReportUnprofitable::getMessage() const { |
814 | return "Region can not profitably be optimized!" ; |
815 | } |
816 | |
817 | std::string ReportUnprofitable::getEndUserMessage() const { |
818 | return "No profitable polyhedral optimization found" ; |
819 | } |
820 | |
821 | const DebugLoc &ReportUnprofitable::getDebugLoc() const { |
822 | for (const BasicBlock *BB : R->blocks()) |
823 | for (const Instruction &Inst : *BB) |
824 | if (const DebugLoc &DL = Inst.getStableDebugLoc()) |
825 | return DL; |
826 | |
827 | return R->getEntry()->getTerminator()->getDebugLoc(); |
828 | } |
829 | |
830 | bool ReportUnprofitable::classof(const RejectReason *RR) { |
831 | return RR->getKind() == RejectReasonKind::Unprofitable; |
832 | } |
833 | } // namespace polly |
834 | |