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