From 5569bf300dc1cf5c43223805f8adc76170c800fa Mon Sep 17 00:00:00 2001 From: Andreas Simbuerger Date: Thu, 26 Jun 2014 10:06:40 +0000 Subject: [PATCH] Support the new DiagnosticRemarks Add support for generating optimization remarks after completing the detection of Scops. The goal is to provide end-users with useful hints about opportunities that help to increase the size of the detected Scops in their code. By default the remark is unspecified and the debug location is empty. Future patches have to expand on the messages generated. This patch brings a simple test case for ReportFuncCall to demonstrate the feature. Reports all missed opportunities to increase the size/number of valid Scops: clang <...> -Rpass-missed="polly-detect" <...> opt <...> -pass-remarks-missed="polly-detect" <...> Reports beginning and end of all valid Scops: clang <...> -Rpass="polly-detect" <...> opt <...> -pass-remarks="polly-detect" <...> Differential Revision: http://reviews.llvm.org/D4171 llvm-svn: 211769 --- polly/include/polly/ScopDetection.h | 17 ++ polly/include/polly/ScopDetectionDiagnostic.h | 174 +++++++++++----- polly/lib/Analysis/ScopDetection.cpp | 76 +++++-- polly/lib/Analysis/ScopDetectionDiagnostic.cpp | 231 ++++++++++++++++++++- .../ScopDetectionDiagnostics/ReportFuncCall-01.ll | 67 ++++++ 5 files changed, 488 insertions(+), 77 deletions(-) create mode 100644 polly/test/ScopDetectionDiagnostics/ReportFuncCall-01.ll diff --git a/polly/include/polly/ScopDetection.h b/polly/include/polly/ScopDetection.h index 5bab520..34b0844 100644 --- a/polly/include/polly/ScopDetection.h +++ b/polly/include/polly/ScopDetection.h @@ -326,6 +326,23 @@ public: const_reject_iterator reject_end() const { return RejectLogs.end(); } //@} + /// @brief Emit rejection remarks for all smallest invalid regions. + /// + /// @param F The function to emit remarks for. + /// @param R The region to start the region tree traversal for. + void emitMissedRemarksForLeaves(const Function &F, const Region *R); + + /// @brief Emit rejection remarks for the parent regions of all valid regions. + /// + /// Emitting rejection remarks for the parent regions of all valid regions + /// may give the end-user clues about how to increase the size of the + /// detected Scops. + /// + /// @param F The function to emit remarks for. + /// @param ValidRegions The set of valid regions to emit remarks for. + void emitMissedRemarksForValidRegions(const Function &F, + const RegionSet &ValidRegions); + /// @brief Mark the function as invalid so we will not extract any scop from /// the function. /// diff --git a/polly/include/polly/ScopDetectionDiagnostic.h b/polly/include/polly/ScopDetectionDiagnostic.h index 1006770..78ee71f 100644 --- a/polly/include/polly/ScopDetectionDiagnostic.h +++ b/polly/include/polly/ScopDetectionDiagnostic.h @@ -52,6 +52,20 @@ namespace polly { void getDebugLocation(const Region *R, unsigned &LineBegin, unsigned &LineEnd, std::string &FileName); +class RejectLog; +/// @brief Emit optimization remarks about the rejected regions to the user. +/// +/// This emits the content of the reject log as optimization remarks. +/// Remember to at least track failures (-polly-detect-track-failures). +/// @param F The function we emit remarks for. +/// @param Log The error log containing all messages being emitted as remark. +void emitRejectionRemarks(const llvm::Function &F, const RejectLog &Log); + +/// @brief Emit diagnostic remarks for a valid Scop +/// +/// @param F The function we emit remarks for +/// @param R The region that marks a valid Scop +void emitValidRemarks(const llvm::Function &F, const Region *R); //===----------------------------------------------------------------------===// /// @brief Base class of all reject reasons found during Scop detection. /// @@ -67,6 +81,23 @@ public: /// /// @return A debug message representing this error. virtual std::string getMessage() const = 0; + + /// @brief Generate a message for the end-user describing this error. + /// + /// The message provided has to be suitable for the end-user. So it should + /// not reference any LLVM internal data structures or terminology. + /// Ideally, the message helps the end-user to increase the size of the + /// regions amenable to Polly. + /// + /// @return A short message representing this error. + virtual std::string getEndUserMessage() const { + return "Unspecified error."; + }; + + /// @brief Get the source location of this error. + /// + /// @return The debug location for this error. + virtual const llvm::DebugLoc &getDebugLoc() const; }; typedef std::shared_ptr RejectReasonPtr; @@ -79,10 +110,10 @@ class RejectLog { public: explicit RejectLog(Region *R) : R(R) {} - typedef llvm::SmallVector::iterator iterator; + typedef llvm::SmallVector::const_iterator iterator; - iterator begin() { return ErrorReports.begin(); } - iterator end() { return ErrorReports.end(); } + iterator begin() const { return ErrorReports.begin(); } + iterator end() const { return ErrorReports.end(); } size_t size() { return ErrorReports.size(); } const Region *region() const { return R; } @@ -104,11 +135,12 @@ class ReportNonBranchTerminator : public ReportCFG { BasicBlock *BB; public: - ReportNonBranchTerminator(BasicBlock *BB) : BB(BB) {} + ReportNonBranchTerminator(BasicBlock *BB) : ReportCFG(), BB(BB) {} /// @name RejectReason interface //@{ - virtual std::string getMessage() const; + virtual std::string getMessage() const override; + virtual const DebugLoc &getDebugLoc() const override; //@} }; @@ -121,11 +153,12 @@ class ReportCondition : public ReportCFG { BasicBlock *BB; public: - ReportCondition(BasicBlock *BB) : BB(BB) {} + ReportCondition(BasicBlock *BB) : ReportCFG(), BB(BB) {} /// @name RejectReason interface //@{ - virtual std::string getMessage() const; + virtual std::string getMessage() const override; + virtual const DebugLoc &getDebugLoc() const override; //@} }; @@ -136,8 +169,16 @@ public: /// this class. class ReportAffFunc : public RejectReason { //===--------------------------------------------------------------------===// + + // The instruction that caused non-affinity to occur. + const Instruction *Inst; + public: - ReportAffFunc(); + ReportAffFunc(const Instruction *Inst); + + virtual const DebugLoc &getDebugLoc() const override { + return Inst->getDebugLoc(); + } }; //===----------------------------------------------------------------------===// @@ -149,11 +190,12 @@ class ReportUndefCond : public ReportAffFunc { BasicBlock *BB; public: - ReportUndefCond(BasicBlock *BB) : BB(BB) {} + ReportUndefCond(const Instruction *Inst, BasicBlock *BB) + : ReportAffFunc(Inst), BB(BB) {} /// @name RejectReason interface //@{ - virtual std::string getMessage() const; + virtual std::string getMessage() const override; //@} }; @@ -168,11 +210,12 @@ class ReportInvalidCond : public ReportAffFunc { BasicBlock *BB; public: - ReportInvalidCond(BasicBlock *BB) : BB(BB) {} + ReportInvalidCond(const Instruction *Inst, BasicBlock *BB) + : ReportAffFunc(Inst), BB(BB) {} /// @name RejectReason interface //@{ - virtual std::string getMessage() const; + virtual std::string getMessage() const override; //@} }; @@ -185,11 +228,12 @@ class ReportUndefOperand : public ReportAffFunc { BasicBlock *BB; public: - ReportUndefOperand(BasicBlock *BB) : BB(BB) {} + ReportUndefOperand(BasicBlock *BB, const Instruction *Inst) + : ReportAffFunc(Inst), BB(BB) {} /// @name RejectReason interface //@{ - virtual std::string getMessage() const; + virtual std::string getMessage() const override; //@} }; @@ -208,15 +252,16 @@ class ReportNonAffBranch : public ReportAffFunc { //@} public: - ReportNonAffBranch(BasicBlock *BB, const SCEV *LHS, const SCEV *RHS) - : BB(BB), LHS(LHS), RHS(RHS) {} + ReportNonAffBranch(BasicBlock *BB, const SCEV *LHS, const SCEV *RHS, + const Instruction *Inst) + : ReportAffFunc(Inst), BB(BB), LHS(LHS), RHS(RHS) {} const SCEV *lhs() { return LHS; } const SCEV *rhs() { return RHS; } /// @name RejectReason interface //@{ - virtual std::string getMessage() const; + virtual std::string getMessage() const override; //@} }; @@ -225,9 +270,11 @@ public: class ReportNoBasePtr : public ReportAffFunc { //===--------------------------------------------------------------------===// public: + ReportNoBasePtr(const Instruction *Inst) : ReportAffFunc(Inst) {} + /// @name RejectReason interface //@{ - virtual std::string getMessage() const; + virtual std::string getMessage() const override; //@} }; @@ -236,9 +283,11 @@ public: class ReportUndefBasePtr : public ReportAffFunc { //===--------------------------------------------------------------------===// public: + ReportUndefBasePtr(const Instruction *Inst) : ReportAffFunc(Inst) {} + /// @name RejectReason interface //@{ - virtual std::string getMessage() const; + virtual std::string getMessage() const override; //@} }; @@ -251,11 +300,12 @@ class ReportVariantBasePtr : public ReportAffFunc { Value *BaseValue; public: - ReportVariantBasePtr(Value *BaseValue) : BaseValue(BaseValue) {} + ReportVariantBasePtr(Value *BaseValue, const Instruction *Inst) + : ReportAffFunc(Inst), BaseValue(BaseValue) {} /// @name RejectReason interface //@{ - virtual std::string getMessage() const; + virtual std::string getMessage() const override; //@} }; @@ -268,14 +318,14 @@ class ReportNonAffineAccess : public ReportAffFunc { const SCEV *AccessFunction; public: - ReportNonAffineAccess(const SCEV *AccessFunction) - : AccessFunction(AccessFunction) {} + ReportNonAffineAccess(const SCEV *AccessFunction, const Instruction *Inst) + : ReportAffFunc(Inst), AccessFunction(AccessFunction) {} const SCEV *get() { return AccessFunction; } /// @name RejectReason interface //@{ - virtual std::string getMessage() const; + virtual std::string getMessage() const override; //@} }; @@ -299,11 +349,12 @@ class ReportPhiNodeRefInRegion : public ReportIndVar { Instruction *Inst; public: - ReportPhiNodeRefInRegion(Instruction *Inst) : Inst(Inst) {} + ReportPhiNodeRefInRegion(Instruction *Inst); /// @name RejectReason interface //@{ - virtual std::string getMessage() const; + virtual std::string getMessage() const override; + virtual const DebugLoc &getDebugLoc() const override; //@} }; @@ -316,11 +367,12 @@ class ReportNonCanonicalPhiNode : public ReportIndVar { Instruction *Inst; public: - ReportNonCanonicalPhiNode(Instruction *Inst) : Inst(Inst) {} + ReportNonCanonicalPhiNode(Instruction *Inst); /// @name RejectReason interface //@{ - virtual std::string getMessage() const; + virtual std::string getMessage() const override; + virtual const DebugLoc &getDebugLoc() const override; //@} }; @@ -333,11 +385,12 @@ class ReportLoopHeader : public ReportIndVar { Loop *L; public: - ReportLoopHeader(Loop *L) : L(L) {} + ReportLoopHeader(Loop *L); /// @name RejectReason interface //@{ - virtual std::string getMessage() const; + virtual std::string getMessage() const override; + virtual const DebugLoc &getDebugLoc() const override; //@} }; @@ -345,12 +398,16 @@ public: /// @brief Captures a region with invalid entering edges. class ReportIndEdge : public RejectReason { //===--------------------------------------------------------------------===// + + BasicBlock *BB; + public: - ReportIndEdge(); + ReportIndEdge(BasicBlock *BB); /// @name RejectReason interface //@{ - virtual std::string getMessage() const; + virtual std::string getMessage() const override; + virtual const DebugLoc &getDebugLoc() const override; //@} }; @@ -372,7 +429,8 @@ public: /// @name RejectReason interface //@{ - virtual std::string getMessage() const; + virtual std::string getMessage() const override; + virtual const DebugLoc &getDebugLoc() const override; //@} }; @@ -389,7 +447,9 @@ public: /// @name RejectReason interface //@{ - std::string getMessage() const; + virtual std::string getMessage() const override; + virtual const DebugLoc &getDebugLoc() const override; + virtual std::string getEndUserMessage() const override; //@} }; @@ -398,20 +458,21 @@ public: class ReportAlias : public RejectReason { //===--------------------------------------------------------------------===// - // The offending alias set. - AliasSet *AS; - /// @brief Format an invalid alias set. /// /// @param AS The invalid alias set to format. std::string formatInvalidAlias(AliasSet &AS) const; + AliasSet *AS; + Instruction *Inst; + public: - ReportAlias(AliasSet *AS); + ReportAlias(Instruction *Inst, AliasSet *AS); /// @name RejectReason interface //@{ - std::string getMessage() const; + virtual std::string getMessage() const override; + virtual const DebugLoc &getDebugLoc() const override; //@} }; @@ -424,7 +485,7 @@ public: /// @name RejectReason interface //@{ - std::string getMessage() const; + virtual std::string getMessage() const override; //@} }; @@ -437,7 +498,7 @@ public: /// @name RejectReason interface //@{ - std::string getMessage() const { return "Unknown reject reason"; } + virtual std::string getMessage() const override; //@} }; @@ -447,14 +508,15 @@ class ReportIntToPtr : public ReportOther { //===--------------------------------------------------------------------===// // The offending base value. - Value *BaseValue; + Instruction *BaseValue; public: - ReportIntToPtr(Value *BaseValue) : BaseValue(BaseValue) {} + ReportIntToPtr(Instruction *BaseValue); /// @name RejectReason interface //@{ - std::string getMessage() const; + virtual std::string getMessage() const override; + virtual const DebugLoc &getDebugLoc() const override; //@} }; @@ -465,11 +527,12 @@ class ReportAlloca : public ReportOther { Instruction *Inst; public: - ReportAlloca(Instruction *Inst) : Inst(Inst) {} + ReportAlloca(Instruction *Inst); /// @name RejectReason interface //@{ - std::string getMessage() const; + virtual std::string getMessage() const override; + virtual const DebugLoc &getDebugLoc() const override; //@} }; @@ -480,11 +543,12 @@ class ReportUnknownInst : public ReportOther { Instruction *Inst; public: - ReportUnknownInst(Instruction *Inst) : Inst(Inst) {} + ReportUnknownInst(Instruction *Inst); /// @name RejectReason interface //@{ - std::string getMessage() const; + virtual std::string getMessage() const override; + virtual const DebugLoc &getDebugLoc() const override; //@} }; @@ -492,10 +556,15 @@ public: /// @brief Captures errors with phi nodes in exit BBs. class ReportPHIinExit : public ReportOther { //===--------------------------------------------------------------------===// + Instruction *Inst; + public: + ReportPHIinExit(Instruction *Inst); + /// @name RejectReason interface //@{ - std::string getMessage() const; + virtual std::string getMessage() const override; + virtual const DebugLoc &getDebugLoc() const override; //@} }; @@ -503,10 +572,15 @@ public: /// @brief Captures errors with regions containing the function entry block. class ReportEntry : public ReportOther { //===--------------------------------------------------------------------===// + BasicBlock *BB; + public: + ReportEntry(BasicBlock *BB); + /// @name RejectReason interface //@{ - std::string getMessage() const; + virtual std::string getMessage() const override; + virtual const DebugLoc &getDebugLoc() const override; //@} }; diff --git a/polly/lib/Analysis/ScopDetection.cpp b/polly/lib/Analysis/ScopDetection.cpp index f1fafaa..06b16c4 100644 --- a/polly/lib/Analysis/ScopDetection.cpp +++ b/polly/lib/Analysis/ScopDetection.cpp @@ -250,11 +250,11 @@ bool ScopDetection::isValidCFG(BasicBlock &BB, // UndefValue is not allowed as condition. if (isa(Condition)) - return invalid(Context, /*Assert=*/true, &BB); + return invalid(Context, /*Assert=*/true, Br, &BB); // Only Constant and ICmpInst are allowed as condition. if (!(isa(Condition) || isa(Condition))) - return invalid(Context, /*Assert=*/true, &BB); + return invalid(Context, /*Assert=*/true, Br, &BB); // Allow perfectly nested conditions. assert(Br->getNumSuccessors() == 2 && "Unexpected number of successors"); @@ -271,7 +271,7 @@ bool ScopDetection::isValidCFG(BasicBlock &BB, // Are both operands of the ICmp affine? if (isa(ICmp->getOperand(0)) || isa(ICmp->getOperand(1))) - return invalid(Context, /*Assert=*/true, &BB); + return invalid(Context, /*Assert=*/true, &BB, ICmp); Loop *L = LI->getLoopFor(ICmp->getParent()); const SCEV *LHS = SE->getSCEVAtScope(ICmp->getOperand(0), L); @@ -280,7 +280,7 @@ bool ScopDetection::isValidCFG(BasicBlock &BB, if (!isAffineExpr(&Context.CurRegion, LHS, *SE) || !isAffineExpr(&Context.CurRegion, RHS, *SE)) return invalid(Context, /*Assert=*/true, &BB, LHS, - RHS); + RHS, ICmp); } // Allow loop exit conditions. @@ -380,8 +380,8 @@ bool ScopDetection::hasAffineMemoryAccesses(DetectionContext &Context) const { const SCEVAddRecExpr *AF = PIAF.second; const Instruction *Insn = PIAF.first; if (Shape->DelinearizedSizes.empty()) - return invalid(Context, /*Assert=*/true, - PIAF.second); + return invalid(Context, /*Assert=*/true, AF, + Insn); MemAcc *Acc = new MemAcc(Insn, Shape); InsnToMemAcc.insert({Insn, Acc}); @@ -389,12 +389,14 @@ bool ScopDetection::hasAffineMemoryAccesses(DetectionContext &Context) const { Shape->DelinearizedSizes); if (Shape->DelinearizedSizes.empty() || Acc->DelinearizedSubscripts.empty()) - return invalid(Context, /*Assert=*/true, AF); + return invalid(Context, /*Assert=*/true, AF, + Insn); // Check that the delinearized subscripts are affine. for (const SCEV *S : Acc->DelinearizedSubscripts) if (!isAffineExpr(&Context.CurRegion, S, *SE, BaseValue)) - return invalid(Context, /*Assert=*/true, AF); + return invalid(Context, /*Assert=*/true, AF, + Insn); } } return true; @@ -411,12 +413,12 @@ bool ScopDetection::isValidMemoryAccess(Instruction &Inst, BasePointer = dyn_cast(SE->getPointerBase(AccessFunction)); if (!BasePointer) - return invalid(Context, /*Assert=*/true); + return invalid(Context, /*Assert=*/true, &Inst); BaseValue = BasePointer->getValue(); if (isa(BaseValue)) - return invalid(Context, /*Assert=*/true); + return invalid(Context, /*Assert=*/true, &Inst); // Check that the base address of the access is invariant in the current // region. @@ -424,7 +426,8 @@ bool ScopDetection::isValidMemoryAccess(Instruction &Inst, // Verification of this property is difficult as the independent blocks // pass may introduce aliasing that we did not have when running the // scop detection. - return invalid(Context, /*Assert=*/false, BaseValue); + return invalid(Context, /*Assert=*/false, BaseValue, + &Inst); AccessFunction = SE->getMinusSCEV(AccessFunction, BasePointer); @@ -436,7 +439,7 @@ bool ScopDetection::isValidMemoryAccess(Instruction &Inst, if (!PollyDelinearize || !AF) return invalid(Context, /*Assert=*/true, - AccessFunction); + AccessFunction, &Inst); const SCEV *ElementSize = SE->getElementSize(&Inst); Context.ElementSize[BasePointer] = ElementSize; @@ -456,8 +459,8 @@ bool ScopDetection::isValidMemoryAccess(Instruction &Inst, // FIXME: Alias Analysis thinks IntToPtrInst aliases with alloca instructions // created by IndependentBlocks Pass. - if (isa(BaseValue)) - return invalid(Context, /*Assert=*/true, BaseValue); + if (IntToPtrInst *Inst = dyn_cast(BaseValue)) + return invalid(Context, /*Assert=*/true, Inst); if (IgnoreAliasing) return true; @@ -476,7 +479,7 @@ bool ScopDetection::isValidMemoryAccess(Instruction &Inst, // not proof this without -basicaa we would fail. We disable this check to // not cause irrelevant verification failures. if (!AS.isMustAlias()) - return invalid(Context, /*Assert=*/true, &AS); + return invalid(Context, /*Assert=*/true, &Inst, &AS); return true; } @@ -692,7 +695,7 @@ bool ScopDetection::isValidExit(DetectionContext &Context) const { if (BasicBlock *Exit = R.getExit()) { BasicBlock::iterator I = Exit->begin(); if (I != Exit->end() && isa(*I)) - return invalid(Context, /*Assert=*/true); + return invalid(Context, /*Assert=*/true, I); } return true; @@ -745,7 +748,7 @@ bool ScopDetection::isValidRegion(DetectionContext &Context) const { // Region entering edges come from the same loop but outside the region // are not allowed. if (L->contains(*PI) && !R.contains(*PI)) - return invalid(Context, /*Assert=*/true); + return invalid(Context, /*Assert=*/true, *PI); } } } @@ -753,7 +756,7 @@ bool ScopDetection::isValidRegion(DetectionContext &Context) const { // SCoP cannot contain the entry block of the function, because we need // to insert alloca instruction there when translate scalar to array. if (R.getEntry() == &(R.getEntry()->getParent()->getEntryBlock())) - return invalid(Context, /*Assert=*/true); + return invalid(Context, /*Assert=*/true, R.getEntry()); if (!isValidExit(Context)) return false; @@ -780,6 +783,34 @@ void ScopDetection::printLocations(llvm::Function &F) { } } +void +ScopDetection::emitMissedRemarksForValidRegions(const Function &F, + const RegionSet &ValidRegions) { + for (const Region *R : ValidRegions) { + const Region *Parent = R->getParent(); + if (Parent && !Parent->isTopLevelRegion() && RejectLogs.count(Parent)) + emitRejectionRemarks(F, RejectLogs.at(Parent)); + } +} + +void ScopDetection::emitMissedRemarksForLeaves(const Function &F, + const Region *R) { + for (const std::unique_ptr &Child : *R) { + bool IsValid = ValidRegions.count(Child.get()); + if (IsValid) + continue; + + bool IsLeaf = Child->begin() == Child->end(); + if (!IsLeaf) + emitMissedRemarksForLeaves(F, Child.get()); + else { + if (RejectLogs.count(Child.get())) { + emitRejectionRemarks(F, RejectLogs.at(Child.get())); + } + } + } +} + bool ScopDetection::runOnFunction(llvm::Function &F) { LI = &getAnalysis(); RI = &getAnalysis(); @@ -800,6 +831,15 @@ bool ScopDetection::runOnFunction(llvm::Function &F) { findScops(*TopRegion); + // Only makes sense when we tracked errors. + if (PollyTrackFailures) { + emitMissedRemarksForValidRegions(F, ValidRegions); + emitMissedRemarksForLeaves(F, TopRegion); + } + + for (const Region *R : ValidRegions) + emitValidRemarks(F, R); + if (ReportLevel >= 1) printLocations(F); diff --git a/polly/lib/Analysis/ScopDetectionDiagnostic.cpp b/polly/lib/Analysis/ScopDetectionDiagnostic.cpp index 0fa7ba7..c18cab3 100644 --- a/polly/lib/Analysis/ScopDetectionDiagnostic.cpp +++ b/polly/lib/Analysis/ScopDetectionDiagnostic.cpp @@ -22,12 +22,15 @@ #include "llvm/Analysis/LoopInfo.h" #include "llvm/Analysis/AliasSetTracker.h" #include "llvm/IR/BasicBlock.h" +#include "llvm/IR/DebugInfo.h" +#include "llvm/IR/DebugLoc.h" +#include "llvm/IR/DiagnosticInfo.h" +#include "llvm/IR/LLVMContext.h" #include "llvm/IR/Value.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/Statistic.h" #include "llvm/Analysis/RegionInfo.h" -#include "llvm/IR/DebugInfo.h" #define DEBUG_TYPE "polly-detect" #include "llvm/Support/Debug.h" @@ -81,75 +84,204 @@ void getDebugLocation(const Region *R, unsigned &LineBegin, unsigned &LineEnd, } } +void emitRejectionRemarks(const llvm::Function &F, const RejectLog &Log) { + LLVMContext &Ctx = F.getContext(); + + const Region *R = Log.region(); + const BasicBlock *Entry = R->getEntry(); + DebugLoc DL = Entry->getTerminator()->getDebugLoc(); + + emitOptimizationRemarkMissed( + Ctx, DEBUG_TYPE, F, DL, + "The following errors keep this region from being a Scop."); + for (RejectReasonPtr RR : Log) { + const DebugLoc &Loc = RR->getDebugLoc(); + if (!Loc.isUnknown()) + emitOptimizationRemarkMissed(Ctx, DEBUG_TYPE, F, Loc, + RR->getEndUserMessage()); + } +} + +void emitValidRemarks(const llvm::Function &F, const Region *R) { + LLVMContext &Ctx = F.getContext(); + + const BasicBlock *Entry = R->getEntry(); + const BasicBlock *Exit = R->getExit(); + + const DebugLoc &Begin = Entry->getFirstNonPHIOrDbg()->getDebugLoc(); + const DebugLoc &End = Exit->getFirstNonPHIOrDbg()->getDebugLoc(); + + emitOptimizationRemark(Ctx, DEBUG_TYPE, F, Begin, + "A valid Scop begins here."); + emitOptimizationRemark(Ctx, DEBUG_TYPE, F, End, "A valid Scop ends here."); +} + +//===----------------------------------------------------------------------===// +// RejectReason. + +const llvm::DebugLoc &RejectReason::getDebugLoc() const { + // Allocate an empty DebugLoc and return it a reference to it. + return *(std::make_shared().get()); +} + //===----------------------------------------------------------------------===// // ReportCFG. ReportCFG::ReportCFG() { ++BadCFGForScop; } +//===----------------------------------------------------------------------===// +// ReportNonBranchTerminator. + std::string ReportNonBranchTerminator::getMessage() const { return ("Non branch instruction terminates BB: " + BB->getName()).str(); } +const DebugLoc &ReportNonBranchTerminator::getDebugLoc() const { + return BB->getTerminator()->getDebugLoc(); +} + +//===----------------------------------------------------------------------===// +// ReportCondition. + std::string ReportCondition::getMessage() const { return ("Not well structured condition at BB: " + BB->getName()).str(); } -ReportAffFunc::ReportAffFunc() { ++BadAffFuncForScop; } +const DebugLoc &ReportCondition::getDebugLoc() const { + return BB->getTerminator()->getDebugLoc(); +} + +//===----------------------------------------------------------------------===// +// ReportAffFunc. + +ReportAffFunc::ReportAffFunc(const Instruction *Inst) + : RejectReason(), Inst(Inst) { + ++BadAffFuncForScop; +} + +//===----------------------------------------------------------------------===// +// ReportUndefCond. std::string ReportUndefCond::getMessage() const { return ("Condition based on 'undef' value in BB: " + BB->getName()).str(); } +//===----------------------------------------------------------------------===// +// ReportInvalidCond. + std::string ReportInvalidCond::getMessage() const { return ("Condition in BB '" + BB->getName()).str() + "' neither constant nor an icmp instruction"; } +//===----------------------------------------------------------------------===// +// ReportUndefOperand. + std::string ReportUndefOperand::getMessage() const { return ("undef operand in branch at BB: " + BB->getName()).str(); } +//===----------------------------------------------------------------------===// +// ReportNonAffBranch. + std::string ReportNonAffBranch::getMessage() const { return ("Non affine branch in BB '" + BB->getName()).str() + "' with LHS: " + *LHS + " and RHS: " + *RHS; } +//===----------------------------------------------------------------------===// +// ReportNoBasePtr. + std::string ReportNoBasePtr::getMessage() const { return "No base pointer"; } +//===----------------------------------------------------------------------===// +// ReportUndefBasePtr. + std::string ReportUndefBasePtr::getMessage() const { return "Undefined base pointer"; } +//===----------------------------------------------------------------------===// +// ReportVariantBasePtr. + std::string ReportVariantBasePtr::getMessage() const { return "Base address not invariant in current region:" + *BaseValue; } +//===----------------------------------------------------------------------===// +// ReportNonAffineAccess. + std::string ReportNonAffineAccess::getMessage() const { return "Non affine access function: " + *AccessFunction; } -ReportIndVar::ReportIndVar() { ++BadIndVarForScop; } +//===----------------------------------------------------------------------===// +// ReportIndVar. + +ReportIndVar::ReportIndVar() : RejectReason() { ++BadIndVarForScop; } + +//===----------------------------------------------------------------------===// +// ReportPhiNodeRefInRegion. + +ReportPhiNodeRefInRegion::ReportPhiNodeRefInRegion(Instruction *Inst) + : ReportIndVar(), Inst(Inst) {} std::string ReportPhiNodeRefInRegion::getMessage() const { return "SCEV of PHI node refers to SSA names in region: " + *Inst; } +const DebugLoc &ReportPhiNodeRefInRegion::getDebugLoc() const { + return Inst->getDebugLoc(); +} + +//===----------------------------------------------------------------------===// +// ReportNonCanonicalPhiNode. + +ReportNonCanonicalPhiNode::ReportNonCanonicalPhiNode(Instruction *Inst) + : ReportIndVar(), Inst(Inst) {} + std::string ReportNonCanonicalPhiNode::getMessage() const { return "Non canonical PHI node: " + *Inst; } +const DebugLoc &ReportNonCanonicalPhiNode::getDebugLoc() const { + return Inst->getDebugLoc(); +} + +//===----------------------------------------------------------------------===// +// ReportLoopHeader. + +ReportLoopHeader::ReportLoopHeader(Loop *L) : ReportIndVar(), L(L) {} + std::string ReportLoopHeader::getMessage() const { return ("No canonical IV at loop header: " + L->getHeader()->getName()).str(); } -ReportIndEdge::ReportIndEdge() { ++BadIndEdgeForScop; } +const DebugLoc &ReportLoopHeader::getDebugLoc() const { + BasicBlock *BB = L->getHeader(); + return BB->getTerminator()->getDebugLoc(); +} + +//===----------------------------------------------------------------------===// +// ReportIndEdge. + +ReportIndEdge::ReportIndEdge(BasicBlock *BB) : RejectReason(), BB(BB) { + ++BadIndEdgeForScop; +} std::string ReportIndEdge::getMessage() const { return "Region has invalid entering edges!"; } +const DebugLoc &ReportIndEdge::getDebugLoc() const { + return BB->getTerminator()->getDebugLoc(); +} + +//===----------------------------------------------------------------------===// +// ReportLoopBound. + ReportLoopBound::ReportLoopBound(Loop *L, const SCEV *LoopCount) - : L(L), LoopCount(LoopCount) { + : RejectReason(), L(L), LoopCount(LoopCount) { ++BadLoopBoundForScop; } @@ -158,7 +290,15 @@ std::string ReportLoopBound::getMessage() const { L->getHeader()->getName(); } -ReportFuncCall::ReportFuncCall(Instruction *Inst) : Inst(Inst) { +const DebugLoc &ReportLoopBound::getDebugLoc() const { + const BasicBlock *BB = L->getHeader(); + return BB->getTerminator()->getDebugLoc(); +} + +//===----------------------------------------------------------------------===// +// ReportFuncCall. + +ReportFuncCall::ReportFuncCall(Instruction *Inst) : RejectReason(), Inst(Inst) { ++BadFuncCallForScop; } @@ -166,7 +306,22 @@ std::string ReportFuncCall::getMessage() const { return "Call instruction: " + *Inst; } -ReportAlias::ReportAlias(AliasSet *AS) : AS(AS) { ++BadAliasForScop; } +const DebugLoc &ReportFuncCall::getDebugLoc() const { + return Inst->getDebugLoc(); +} + +std::string ReportFuncCall::getEndUserMessage() const { + return "This function call cannot be handeled. " + "Try to inline it."; +} + +//===----------------------------------------------------------------------===// +// ReportAlias. + +ReportAlias::ReportAlias(Instruction *Inst, AliasSet *AS) + : RejectReason(), AS(AS), Inst(Inst) { + ++BadAliasForScop; +} std::string ReportAlias::formatInvalidAlias(AliasSet &AS) const { std::string Message; @@ -204,31 +359,89 @@ std::string ReportAlias::formatInvalidAlias(AliasSet &AS) const { std::string ReportAlias::getMessage() const { return formatInvalidAlias(*AS); } -ReportSimpleLoop::ReportSimpleLoop() { ++BadSimpleLoopForScop; } +const DebugLoc &ReportAlias::getDebugLoc() const { return Inst->getDebugLoc(); } + +//===----------------------------------------------------------------------===// +// ReportSimpleLoop. + +ReportSimpleLoop::ReportSimpleLoop() : RejectReason() { + ++BadSimpleLoopForScop; +} std::string ReportSimpleLoop::getMessage() const { return "Loop not in simplify form is invalid!"; } -ReportOther::ReportOther() { ++BadOtherForScop; } +//===----------------------------------------------------------------------===// +// ReportOther. + +std::string ReportOther::getMessage() const { return "Unknown reject reason"; } + +ReportOther::ReportOther() : RejectReason() { ++BadOtherForScop; } + +//===----------------------------------------------------------------------===// +// ReportIntToPtr. +ReportIntToPtr::ReportIntToPtr(Instruction *BaseValue) + : ReportOther(), BaseValue(BaseValue) {} std::string ReportIntToPtr::getMessage() const { return "Find bad intToptr prt: " + *BaseValue; } +const DebugLoc &ReportIntToPtr::getDebugLoc() const { + return BaseValue->getDebugLoc(); +} + +//===----------------------------------------------------------------------===// +// ReportAlloca. + +ReportAlloca::ReportAlloca(Instruction *Inst) : ReportOther(), Inst(Inst) {} + std::string ReportAlloca::getMessage() const { return "Alloca instruction: " + *Inst; } +const DebugLoc &ReportAlloca::getDebugLoc() const { + return Inst->getDebugLoc(); +} + +//===----------------------------------------------------------------------===// +// ReportUnknownInst. + +ReportUnknownInst::ReportUnknownInst(Instruction *Inst) + : ReportOther(), Inst(Inst) {} + std::string ReportUnknownInst::getMessage() const { return "Unknown instruction: " + *Inst; } +const DebugLoc &ReportUnknownInst::getDebugLoc() const { + return Inst->getDebugLoc(); +} + +//===----------------------------------------------------------------------===// +// ReportPHIinExit. + +ReportPHIinExit::ReportPHIinExit(Instruction *Inst) + : ReportOther(), Inst(Inst) {} + std::string ReportPHIinExit::getMessage() const { return "PHI node in exit BB"; } +const DebugLoc &ReportPHIinExit::getDebugLoc() const { + return Inst->getDebugLoc(); +} + +//===----------------------------------------------------------------------===// +// ReportEntry. +ReportEntry::ReportEntry(BasicBlock *BB) : ReportOther(), BB(BB) {} + std::string ReportEntry::getMessage() const { return "Region containing entry block of function is invalid!"; } + +const DebugLoc &ReportEntry::getDebugLoc() const { + return BB->getTerminator()->getDebugLoc(); +} } // namespace polly diff --git a/polly/test/ScopDetectionDiagnostics/ReportFuncCall-01.ll b/polly/test/ScopDetectionDiagnostics/ReportFuncCall-01.ll new file mode 100644 index 0000000..81c0f62 --- /dev/null +++ b/polly/test/ScopDetectionDiagnostics/ReportFuncCall-01.ll @@ -0,0 +1,67 @@ +; RUN: opt %loadPolly -pass-remarks-missed="polly-detect" -polly-detect-track-failures -polly-detect -analyze < %s 2>&1 | FileCheck %s + +; #define N 1024 +; double invalidCall(double A[N]); +; +; void a(double A[N], int n) { +; for (int i=0; i