Index: include/polly/ScopDetection.h =================================================================== --- include/polly/ScopDetection.h +++ include/polly/ScopDetection.h @@ -52,6 +52,7 @@ #include "llvm/ADT/SetVector.h" #include "llvm/Analysis/AliasAnalysis.h" #include "llvm/Analysis/AliasSetTracker.h" +#include "llvm/Analysis/OptimizationDiagnosticInfo.h" #include "llvm/Analysis/RegionInfo.h" #include "llvm/Pass.h" #include @@ -526,7 +527,8 @@ public: ScopDetection(Function &F, const DominatorTree &DT, ScalarEvolution &SE, - LoopInfo &LI, RegionInfo &RI, AliasAnalysis &AA); + LoopInfo &LI, RegionInfo &RI, AliasAnalysis &AA, + OptimizationRemarkEmitter &ORE); /// Get the RegionInfo stored in this pass. /// @@ -607,6 +609,9 @@ static ScopDetection::LoopStats countBeneficialLoops(Region *R, ScalarEvolution &SE, LoopInfo &LI, unsigned MinProfitableTrips); + + /// OptimizationRemarkEmitter object used to emit diagnostic remarks + OptimizationRemarkEmitter &ORE; }; struct ScopAnalysis : public AnalysisInfoMixin { Index: include/polly/ScopDetectionDiagnostic.h =================================================================== --- include/polly/ScopDetectionDiagnostic.h +++ include/polly/ScopDetectionDiagnostic.h @@ -25,6 +25,7 @@ #include "llvm/ADT/Twine.h" #include "llvm/Analysis/AliasSetTracker.h" #include "llvm/Analysis/LoopInfo.h" +#include "llvm/Analysis/OptimizationDiagnosticInfo.h" #include "llvm/Analysis/ScalarEvolutionExpressions.h" #include "llvm/IR/BasicBlock.h" #include "llvm/IR/Value.h" @@ -59,7 +60,8 @@ /// Remember to at least track failures (-polly-detect-track-failures). /// @param P The region delimiters (entry & exit) we emit remarks for. /// @param Log The error log containing all messages being emitted as remark. -void emitRejectionRemarks(const BBPair &P, const RejectLog &Log); +void emitRejectionRemarks(const BBPair &P, const RejectLog &Log, + OptimizationRemarkEmitter &ORE); // Discriminator for LLVM-style RTTI (dyn_cast<> et al.) enum class RejectReasonKind { @@ -122,6 +124,16 @@ virtual ~RejectReason() {} + /// Generate the remark name to identify this remark. + /// + /// @return A short string that identifies the error. + virtual std::string getRemarkName() const = 0; + + /// Get the Basic Block containing this remark. + /// + /// @return The Basic Block containing this remark. + virtual const Value *getRemarkBB() const = 0; + /// Generate a reasonable diagnostic message describing this error. /// /// @return A debug message representing this error. @@ -202,6 +214,8 @@ /// @name RejectReason interface //@{ + virtual std::string getRemarkName() const override; + virtual const Value *getRemarkBB() const override; virtual std::string getMessage() const override; virtual const DebugLoc &getDebugLoc() const override; //@} @@ -224,6 +238,8 @@ /// @name RejectReason interface //@{ + virtual std::string getRemarkName() const override; + virtual const Value *getRemarkBB() const override; virtual std::string getMessage() const override; virtual std::string getEndUserMessage() const override; virtual const DebugLoc &getDebugLoc() const override; @@ -248,6 +264,8 @@ /// @name RejectReason interface //@{ + virtual std::string getRemarkName() const override; + virtual const Value *getRemarkBB() const override; virtual std::string getMessage() const override; virtual std::string getEndUserMessage() const override; virtual const DebugLoc &getDebugLoc() const override; @@ -262,6 +280,7 @@ class ReportAffFunc : public RejectReason { //===--------------------------------------------------------------------===// +protected: // The instruction that caused non-affinity to occur. const Instruction *Inst; @@ -300,6 +319,8 @@ /// @name RejectReason interface //@{ + virtual std::string getRemarkName() const override; + virtual const Value *getRemarkBB() const override; virtual std::string getMessage() const override; //@} }; @@ -325,6 +346,8 @@ /// @name RejectReason interface //@{ + virtual std::string getRemarkName() const override; + virtual const Value *getRemarkBB() const override; virtual std::string getMessage() const override; //@} }; @@ -348,6 +371,8 @@ /// @name RejectReason interface //@{ + virtual std::string getRemarkName() const override; + virtual const Value *getRemarkBB() const override; virtual std::string getMessage() const override; //@} }; @@ -382,6 +407,8 @@ /// @name RejectReason interface //@{ + virtual std::string getRemarkName() const override; + virtual const Value *getRemarkBB() const override; virtual std::string getMessage() const override; //@} }; @@ -401,6 +428,8 @@ /// @name RejectReason interface //@{ + virtual std::string getRemarkName() const override; + virtual const Value *getRemarkBB() const override; virtual std::string getMessage() const override; //@} }; @@ -420,6 +449,8 @@ /// @name RejectReason interface //@{ + virtual std::string getRemarkName() const override; + virtual const Value *getRemarkBB() const override; virtual std::string getMessage() const override; //@} }; @@ -444,6 +475,8 @@ /// @name RejectReason interface //@{ + virtual std::string getRemarkName() const override; + virtual const Value *getRemarkBB() const override; virtual std::string getMessage() const override; virtual std::string getEndUserMessage() const override; //@} @@ -475,6 +508,8 @@ /// @name RejectReason interface //@{ + virtual std::string getRemarkName() const override; + virtual const Value *getRemarkBB() const override; virtual std::string getMessage() const override; virtual std::string getEndUserMessage() const override; //@} @@ -500,6 +535,8 @@ /// @name RejectReason interface //@{ + virtual std::string getRemarkName() const override; + virtual const Value *getRemarkBB() const override; virtual std::string getMessage() const override; virtual std::string getEndUserMessage() const override; //@} @@ -531,6 +568,8 @@ /// @name RejectReason interface //@{ + virtual std::string getRemarkName() const override; + virtual const Value *getRemarkBB() const override; virtual std::string getMessage() const override; virtual const DebugLoc &getDebugLoc() const override; virtual std::string getEndUserMessage() const override; @@ -559,6 +598,8 @@ /// @name RejectReason interface //@{ + virtual std::string getRemarkName() const override; + virtual const Value *getRemarkBB() const override; virtual std::string getMessage() const override; virtual const DebugLoc &getDebugLoc() const override; virtual std::string getEndUserMessage() const override; @@ -583,6 +624,8 @@ /// @name RejectReason interface //@{ + virtual std::string getRemarkName() const override; + virtual const Value *getRemarkBB() const override; virtual std::string getMessage() const override; virtual const DebugLoc &getDebugLoc() const override; virtual std::string getEndUserMessage() const override; @@ -621,6 +664,8 @@ /// @name RejectReason interface //@{ + virtual std::string getRemarkName() const override; + virtual const Value *getRemarkBB() const override; virtual std::string getMessage() const override; virtual const DebugLoc &getDebugLoc() const override; virtual std::string getEndUserMessage() const override; @@ -641,6 +686,7 @@ /// @name RejectReason interface //@{ + virtual std::string getRemarkName() const override; virtual std::string getMessage() const override; //@} }; @@ -663,6 +709,8 @@ /// @name RejectReason interface //@{ + virtual std::string getRemarkName() const override; + virtual const Value *getRemarkBB() const override; virtual std::string getMessage() const override; virtual const DebugLoc &getDebugLoc() const override; //@} @@ -684,6 +732,8 @@ /// @name RejectReason interface //@{ + virtual std::string getRemarkName() const override; + virtual const Value *getRemarkBB() const override; virtual std::string getMessage() const override; virtual const DebugLoc &getDebugLoc() const override; //@} @@ -705,6 +755,8 @@ /// @name RejectReason interface //@{ + virtual std::string getRemarkName() const override; + virtual const Value *getRemarkBB() const override; virtual std::string getMessage() const override; virtual const DebugLoc &getDebugLoc() const override; //@} @@ -726,6 +778,8 @@ /// @name RejectReason interface //@{ + virtual std::string getRemarkName() const override; + virtual const Value *getRemarkBB() const override; virtual std::string getMessage() const override; virtual std::string getEndUserMessage() const override; virtual const DebugLoc &getDebugLoc() const override; @@ -748,6 +802,8 @@ /// @name RejectReason interface //@{ + virtual std::string getRemarkName() const override; + virtual const Value *getRemarkBB() const override; virtual std::string getMessage() const override; virtual std::string getEndUserMessage() const override; virtual const DebugLoc &getDebugLoc() const override; @@ -772,6 +828,8 @@ /// @name RejectReason interface //@{ + virtual std::string getRemarkName() const override; + virtual const Value *getRemarkBB() const override; virtual std::string getMessage() const override; virtual const DebugLoc &getDebugLoc() const override; virtual std::string getEndUserMessage() const override; Index: include/polly/ScopInfo.h =================================================================== --- include/polly/ScopInfo.h +++ include/polly/ScopInfo.h @@ -1658,6 +1658,9 @@ /// The context of the SCoP created during SCoP detection. ScopDetection::DetectionContext &DC; + /// OptimizationRemarkEmitter object for displaying diagnostic remarks + OptimizationRemarkEmitter &ORE; + /// Isl context. /// /// We need a shared_ptr with reference counter to delete the context when all @@ -1822,7 +1825,7 @@ /// Scop constructor; invoked from ScopBuilder::buildScop. Scop(Region &R, ScalarEvolution &SE, LoopInfo &LI, - ScopDetection::DetectionContext &DC); + ScopDetection::DetectionContext &DC, OptimizationRemarkEmitter &ORE); //@} @@ -2442,10 +2445,12 @@ /// @param Loc The location in the source that caused this assumption. /// @param Sign Enum to indicate if the assumptions in @p Set are positive /// (needed/assumptions) or negative (invalid/restrictions). + /// @param BB The block in which this assumption was taken. Used to + /// calculate hotness when emitting remark. /// /// @returns True if the assumption is not trivial. bool trackAssumption(AssumptionKind Kind, __isl_keep isl_set *Set, - DebugLoc Loc, AssumptionSign Sign); + DebugLoc Loc, AssumptionSign Sign, BasicBlock *BB); /// Add assumptions to assumed context. /// @@ -2463,8 +2468,10 @@ /// @param Loc The location in the source that caused this assumption. /// @param Sign Enum to indicate if the assumptions in @p Set are positive /// (needed/assumptions) or negative (invalid/restrictions). + /// @param BB The block in which this assumption was taken. Used to + /// calculate hotness when emitting remark. void addAssumption(AssumptionKind Kind, __isl_take isl_set *Set, DebugLoc Loc, - AssumptionSign Sign); + AssumptionSign Sign, BasicBlock *BB); /// Record an assumption for later addition to the assumed context. /// @@ -2497,7 +2504,8 @@ /// /// @param Kind The assumption kind describing the underlying cause. /// @param Loc The location in the source that triggered . - void invalidate(AssumptionKind Kind, DebugLoc Loc); + /// @param BB The BasicBlock where it was triggered. + void invalidate(AssumptionKind Kind, DebugLoc Loc, BasicBlock *BB = nullptr); /// Get the invalid context for this Scop. /// Index: lib/Analysis/ScopBuilder.cpp =================================================================== --- lib/Analysis/ScopBuilder.cpp +++ lib/Analysis/ScopBuilder.cpp @@ -427,7 +427,7 @@ cast(Sizes.back())->getAPInt().getSExtValue(); Sizes.pop_back(); if (ElementSize != DelinearizedSize) - scop->invalidate(DELINEARIZATION, Inst->getDebugLoc()); + scop->invalidate(DELINEARIZATION, Inst->getDebugLoc(), Inst->getParent()); addArrayAccess(Stmt, Inst, AccType, BasePointer->getValue(), ElementType, true, AccItr->second.DelinearizedSubscripts, Sizes, Val); @@ -935,7 +935,7 @@ } void ScopBuilder::buildScop(Region &R, AssumptionCache &AC) { - scop.reset(new Scop(R, SE, LI, *SD.getDetectionContext(&R))); + scop.reset(new Scop(R, SE, LI, *SD.getDetectionContext(&R), SD.ORE)); buildStmts(R); buildAccessFunctions(); @@ -1044,12 +1044,13 @@ ScopDetection &SD, ScalarEvolution &SE) : AA(AA), DL(DL), DT(DT), LI(LI), SD(SD), SE(SE) { - Function *F = R->getEntry()->getParent(); - DebugLoc Beg, End; - getDebugLocations(getBBPairForRegion(R), Beg, End); + auto P = getBBPairForRegion(R); + getDebugLocations(P, Beg, End); + std::string Msg = "SCoP begins here."; - emitOptimizationRemarkAnalysis(F->getContext(), DEBUG_TYPE, *F, Beg, Msg); + SD.ORE.emit(OptimizationRemarkAnalysis(DEBUG_TYPE, "ScopEntry", Beg, P.first) + << Msg); buildScop(*R, AC); @@ -1066,5 +1067,10 @@ ++RichScopFound; } - emitOptimizationRemarkAnalysis(F->getContext(), DEBUG_TYPE, *F, End, Msg); + if (R->isTopLevelRegion()) + SD.ORE.emit(OptimizationRemarkAnalysis(DEBUG_TYPE, "ScopEnd", End, P.first) + << Msg); + else + SD.ORE.emit(OptimizationRemarkAnalysis(DEBUG_TYPE, "ScopEnd", End, P.second) + << Msg); } Index: lib/Analysis/ScopDetection.cpp =================================================================== --- lib/Analysis/ScopDetection.cpp +++ lib/Analysis/ScopDetection.cpp @@ -284,8 +284,8 @@ ScopDetection::ScopDetection(Function &F, const DominatorTree &DT, ScalarEvolution &SE, LoopInfo &LI, RegionInfo &RI, - AliasAnalysis &AA) - : DT(DT), SE(SE), LI(LI), RI(RI), AA(AA) { + AliasAnalysis &AA, OptimizationRemarkEmitter &ORE) + : DT(DT), SE(SE), LI(LI), RI(RI), AA(AA), ORE(ORE) { if (!PollyProcessUnprofitable && LI.empty()) return; @@ -1569,7 +1569,7 @@ for (auto &DIt : DetectionContextMap) { auto &DC = DIt.getSecond(); if (DC.Log.hasErrors()) - emitRejectionRemarks(DIt.getFirst(), DC.Log); + emitRejectionRemarks(DIt.getFirst(), DC.Log, ORE); } } @@ -1718,7 +1718,8 @@ auto &AA = getAnalysis().getAAResults(); auto &SE = getAnalysis().getSE(); auto &DT = getAnalysis().getDomTree(); - Result.reset(new ScopDetection(F, DT, SE, LI, RI, AA)); + auto &ORE = getAnalysis().getORE(); + Result.reset(new ScopDetection(F, DT, SE, LI, RI, AA, ORE)); return false; } @@ -1726,6 +1727,7 @@ AU.addRequired(); AU.addRequiredTransitive(); AU.addRequired(); + AU.addRequired(); // We also need AA and RegionInfo when we are verifying analysis. AU.addRequiredTransitive(); AU.addRequiredTransitive(); @@ -1757,7 +1759,8 @@ auto &AA = FAM.getResult(F); auto &SE = FAM.getResult(F); auto &DT = FAM.getResult(F); - return {F, DT, SE, LI, RI, AA}; + auto &ORE = FAM.getResult(F); + return {F, DT, SE, LI, RI, AA, ORE}; } PreservedAnalyses ScopAnalysisPrinterPass::run(Function &F, @@ -1782,5 +1785,6 @@ INITIALIZE_PASS_DEPENDENCY(RegionInfoPass); INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass); INITIALIZE_PASS_DEPENDENCY(ScalarEvolutionWrapperPass); +INITIALIZE_PASS_DEPENDENCY(OptimizationRemarkEmitterWrapperPass); INITIALIZE_PASS_END(ScopDetectionWrapperPass, "polly-detect", "Polly - Detect static control parts (SCoPs)", false, false) Index: lib/Analysis/ScopDetectionDiagnostic.cpp =================================================================== --- lib/Analysis/ScopDetectionDiagnostic.cpp +++ lib/Analysis/ScopDetectionDiagnostic.cpp @@ -23,6 +23,7 @@ #include "llvm/ADT/Statistic.h" #include "llvm/Analysis/AliasSetTracker.h" #include "llvm/Analysis/LoopInfo.h" +#include "llvm/Analysis/OptimizationDiagnosticInfo.h" #include "llvm/Analysis/RegionInfo.h" #include "llvm/IR/BasicBlock.h" #include "llvm/IR/DebugInfo.h" @@ -120,28 +121,36 @@ } } -void emitRejectionRemarks(const BBPair &P, const RejectLog &Log) { - Function &F = *P.first->getParent(); - LLVMContext &Ctx = F.getContext(); - +void emitRejectionRemarks(const BBPair &P, const RejectLog &Log, + OptimizationRemarkEmitter &ORE) { DebugLoc Begin, End; getDebugLocations(P, Begin, End); - emitOptimizationRemarkMissed( - Ctx, DEBUG_TYPE, F, Begin, - "The following errors keep this region from being a Scop."); + ORE.emit( + OptimizationRemarkMissed(DEBUG_TYPE, "RejectionErrors", Begin, P.first) + << "The following errors keep this region from being a Scop."); for (RejectReasonPtr RR : Log) { + if (const DebugLoc &Loc = RR->getDebugLoc()) - emitOptimizationRemarkMissed(Ctx, DEBUG_TYPE, F, Loc, - RR->getEndUserMessage()); + ORE.emit(OptimizationRemarkMissed(DEBUG_TYPE, RR->getRemarkName(), Loc, + RR->getRemarkBB()) + << RR->getEndUserMessage()); else - emitOptimizationRemarkMissed(Ctx, DEBUG_TYPE, F, Begin, - RR->getEndUserMessage()); + ORE.emit(OptimizationRemarkMissed(DEBUG_TYPE, RR->getRemarkName(), Begin, + RR->getRemarkBB()) + << RR->getEndUserMessage()); } - emitOptimizationRemarkMissed(Ctx, DEBUG_TYPE, F, End, - "Invalid Scop candidate ends here."); + /* Check to see if Region is a top level region, getExit = NULL*/ + if (P.second) + ORE.emit( + OptimizationRemarkMissed(DEBUG_TYPE, "InvalidScopEnd", End, P.second) + << "Invalid Scop candidate ends here."); + else + ORE.emit( + OptimizationRemarkMissed(DEBUG_TYPE, "InvalidScopEnd", End, P.first) + << "Invalid Scop candidate ends here."); } //===----------------------------------------------------------------------===// @@ -178,6 +187,12 @@ //===----------------------------------------------------------------------===// // ReportInvalidTerminator. +std::string ReportInvalidTerminator::getRemarkName() const { + return "InvalidTerminator"; +} + +const Value *ReportInvalidTerminator::getRemarkBB() const { return BB; } + std::string ReportInvalidTerminator::getMessage() const { return ("Invalid instruction terminates BB: " + BB->getName()).str(); } @@ -193,6 +208,12 @@ //===----------------------------------------------------------------------===// // UnreachableInExit. +std::string ReportUnreachableInExit::getRemarkName() const { + return "UnreachableInExit"; +} + +const Value *ReportUnreachableInExit::getRemarkBB() const { return BB; } + std::string ReportUnreachableInExit::getMessage() const { std::string BBName = BB->getName(); return "Unreachable in exit block" + BBName; @@ -211,6 +232,14 @@ //===----------------------------------------------------------------------===// // ReportIrreducibleRegion. +std::string ReportIrreducibleRegion::getRemarkName() const { + return "IrreducibleRegion"; +} + +const Value *ReportIrreducibleRegion::getRemarkBB() const { + return R->getEntry(); +} + std::string ReportIrreducibleRegion::getMessage() const { return "Irreducible region encountered: " + R->getNameStr(); } @@ -239,6 +268,10 @@ //===----------------------------------------------------------------------===// // ReportUndefCond. +std::string ReportUndefCond::getRemarkName() const { return "UndefCond"; } + +const Value *ReportUndefCond::getRemarkBB() const { return BB; } + std::string ReportUndefCond::getMessage() const { return ("Condition based on 'undef' value in BB: " + BB->getName()).str(); } @@ -250,6 +283,10 @@ //===----------------------------------------------------------------------===// // ReportInvalidCond. +std::string ReportInvalidCond::getRemarkName() const { return "InvalidCond"; } + +const Value *ReportInvalidCond::getRemarkBB() const { return BB; } + std::string ReportInvalidCond::getMessage() const { return ("Condition in BB '" + BB->getName()).str() + "' neither constant nor an icmp instruction"; @@ -262,6 +299,10 @@ //===----------------------------------------------------------------------===// // ReportUndefOperand. +std::string ReportUndefOperand::getRemarkName() const { return "UndefOperand"; } + +const Value *ReportUndefOperand::getRemarkBB() const { return BB; } + std::string ReportUndefOperand::getMessage() const { return ("undef operand in branch at BB: " + BB->getName()).str(); } @@ -273,6 +314,10 @@ //===----------------------------------------------------------------------===// // ReportNonAffBranch. +std::string ReportNonAffBranch::getRemarkName() const { return "NonAffBranch"; } + +const Value *ReportNonAffBranch::getRemarkBB() const { return BB; } + std::string ReportNonAffBranch::getMessage() const { return ("Non affine branch in BB '" + BB->getName()).str() + "' with LHS: " + *LHS + " and RHS: " + *RHS; @@ -285,6 +330,10 @@ //===----------------------------------------------------------------------===// // ReportNoBasePtr. +std::string ReportNoBasePtr::getRemarkName() const { return "NoBasePtr"; } + +const Value *ReportNoBasePtr::getRemarkBB() const { return Inst->getParent(); } + std::string ReportNoBasePtr::getMessage() const { return "No base pointer"; } bool ReportNoBasePtr::classof(const RejectReason *RR) { @@ -294,6 +343,12 @@ //===----------------------------------------------------------------------===// // ReportUndefBasePtr. +std::string ReportUndefBasePtr::getRemarkName() const { return "UndefBasePtr"; } + +const Value *ReportUndefBasePtr::getRemarkBB() const { + return Inst->getParent(); +} + std::string ReportUndefBasePtr::getMessage() const { return "Undefined base pointer"; } @@ -305,6 +360,14 @@ //===----------------------------------------------------------------------===// // ReportVariantBasePtr. +std::string ReportVariantBasePtr::getRemarkName() const { + return "VariantBasePtr"; +} + +const Value *ReportVariantBasePtr::getRemarkBB() const { + return Inst->getParent(); +} + std::string ReportVariantBasePtr::getMessage() const { return "Base address not invariant in current region:" + *BaseValue; } @@ -320,6 +383,14 @@ //===----------------------------------------------------------------------===// // ReportDifferentArrayElementSize +std::string ReportDifferentArrayElementSize::getRemarkName() const { + return "DifferentArrayElementSize"; +} + +const Value *ReportDifferentArrayElementSize::getRemarkBB() const { + return Inst->getParent(); +} + std::string ReportDifferentArrayElementSize::getMessage() const { return "Access to one array through data types of different size"; } @@ -339,6 +410,14 @@ //===----------------------------------------------------------------------===// // ReportNonAffineAccess. +std::string ReportNonAffineAccess::getRemarkName() const { + return "NonAffineAccess"; +} + +const Value *ReportNonAffineAccess::getRemarkBB() const { + return Inst->getParent(); +} + std::string ReportNonAffineAccess::getMessage() const { return "Non affine access function: " + *AccessFunction; } @@ -360,6 +439,10 @@ : RejectReason(RejectReasonKind::LoopBound), L(L), LoopCount(LoopCount), Loc(L->getStartLoc()) {} +std::string ReportLoopBound::getRemarkName() const { return "LoopBound"; } + +const Value *ReportLoopBound::getRemarkBB() const { return L->getHeader(); } + std::string ReportLoopBound::getMessage() const { return "Non affine loop bound '" + *LoopCount + "' in loop: " + L->getHeader()->getName(); @@ -378,6 +461,12 @@ //===----------------------------------------------------------------------===// // ReportLoopHasNoExit. +std::string ReportLoopHasNoExit::getRemarkName() const { + return "LoopHasNoExit"; +} + +const Value *ReportLoopHasNoExit::getRemarkBB() const { return L->getHeader(); } + std::string ReportLoopHasNoExit::getMessage() const { return "Loop " + L->getHeader()->getName() + " has no exit."; } @@ -398,6 +487,10 @@ ReportFuncCall::ReportFuncCall(Instruction *Inst) : RejectReason(RejectReasonKind::FuncCall), Inst(Inst) {} +std::string ReportFuncCall::getRemarkName() const { return "FuncCall"; } + +const Value *ReportFuncCall::getRemarkBB() const { return Inst->getParent(); } + std::string ReportFuncCall::getMessage() const { return "Call instruction: " + *Inst; } @@ -421,6 +514,14 @@ ReportNonSimpleMemoryAccess::ReportNonSimpleMemoryAccess(Instruction *Inst) : ReportOther(RejectReasonKind::NonSimpleMemoryAccess), Inst(Inst) {} +std::string ReportNonSimpleMemoryAccess::getRemarkName() const { + return "NonSimpleMemoryAccess"; +} + +const Value *ReportNonSimpleMemoryAccess::getRemarkBB() const { + return Inst->getParent(); +} + std::string ReportNonSimpleMemoryAccess::getMessage() const { return "Non-simple memory access: " + *Inst; } @@ -479,6 +580,10 @@ return OS.str(); } +std::string ReportAlias::getRemarkName() const { return "Alias"; } + +const Value *ReportAlias::getRemarkBB() const { return Inst->getParent(); } + std::string ReportAlias::getMessage() const { return formatInvalidAlias("Possible aliasing: "); } @@ -497,6 +602,8 @@ //===----------------------------------------------------------------------===// // ReportOther. +std::string ReportOther::getRemarkName() const { return "UnknownRejectReason"; } + std::string ReportOther::getMessage() const { return "Unknown reject reason"; } ReportOther::ReportOther(const RejectReasonKind K) : RejectReason(K) {} @@ -511,6 +618,12 @@ ReportIntToPtr::ReportIntToPtr(Instruction *BaseValue) : ReportOther(RejectReasonKind::IntToPtr), BaseValue(BaseValue) {} +std::string ReportIntToPtr::getRemarkName() const { return "IntToPtr"; } + +const Value *ReportIntToPtr::getRemarkBB() const { + return BaseValue->getParent(); +} + std::string ReportIntToPtr::getMessage() const { return "Find bad intToptr prt: " + *BaseValue; } @@ -529,6 +642,10 @@ ReportAlloca::ReportAlloca(Instruction *Inst) : ReportOther(RejectReasonKind::Alloca), Inst(Inst) {} +std::string ReportAlloca::getRemarkName() const { return "Alloca"; } + +const Value *ReportAlloca::getRemarkBB() const { return Inst->getParent(); } + std::string ReportAlloca::getMessage() const { return "Alloca instruction: " + *Inst; } @@ -547,6 +664,12 @@ ReportUnknownInst::ReportUnknownInst(Instruction *Inst) : ReportOther(RejectReasonKind::UnknownInst), Inst(Inst) {} +std::string ReportUnknownInst::getRemarkName() const { return "UnknownInst"; } + +const Value *ReportUnknownInst::getRemarkBB() const { + return Inst->getParent(); +} + std::string ReportUnknownInst::getMessage() const { return "Unknown instruction: " + *Inst; } @@ -564,6 +687,10 @@ ReportEntry::ReportEntry(BasicBlock *BB) : ReportOther(RejectReasonKind::Entry), BB(BB) {} +std::string ReportEntry::getRemarkName() const { return "Entry"; } + +const Value *ReportEntry::getRemarkBB() const { return BB; } + std::string ReportEntry::getMessage() const { return "Region containing entry block of function is invalid!"; } @@ -585,6 +712,10 @@ ReportUnprofitable::ReportUnprofitable(Region *R) : ReportOther(RejectReasonKind::Unprofitable), R(R) {} +std::string ReportUnprofitable::getRemarkName() const { return "Unprofitable"; } + +const Value *ReportUnprofitable::getRemarkBB() const { return R->getEntry(); } + std::string ReportUnprofitable::getMessage() const { return "Region can not profitably be optimized!"; } Index: lib/Analysis/ScopInfo.cpp =================================================================== --- lib/Analysis/ScopInfo.cpp +++ lib/Analysis/ScopInfo.cpp @@ -1616,7 +1616,8 @@ } if (TooComplex) { - S.invalidate(COMPLEXITY, TI ? TI->getDebugLoc() : DebugLoc()); + S.invalidate(COMPLEXITY, TI ? TI->getDebugLoc() : DebugLoc(), + TI ? TI->getParent() : nullptr /* BasicBlock */); isl_set_free(AlternativeCondSet); isl_set_free(ConsequenceCondSet); return false; @@ -2162,7 +2163,6 @@ void Scop::addUserAssumptions( AssumptionCache &AC, DominatorTree &DT, LoopInfo &LI, DenseMap &InvalidDomainMap) { - auto &F = getFunction(); for (auto &Assumption : AC.assumptions()) { auto *CI = dyn_cast_or_null(Assumption); if (!CI || CI->getNumArgOperands() != 1) @@ -2176,9 +2176,9 @@ auto *Val = CI->getArgOperand(0); ParameterSetTy DetectedParams; if (!isAffineConstraint(Val, &R, L, *SE, DetectedParams)) { - emitOptimizationRemarkAnalysis(F.getContext(), DEBUG_TYPE, F, - CI->getDebugLoc(), - "Non-affine user assumption ignored."); + ORE.emit( + OptimizationRemarkAnalysis(DEBUG_TYPE, "IgnoreUserAssumption", CI) + << "Non-affine user assumption ignored."); continue; } @@ -2226,10 +2226,8 @@ isl_set_project_out(AssumptionCtx, isl_dim_param, u--, 1); } } - - emitOptimizationRemarkAnalysis( - F.getContext(), DEBUG_TYPE, F, CI->getDebugLoc(), - "Use user assumption: " + stringFromIslObj(AssumptionCtx)); + ORE.emit(OptimizationRemarkAnalysis(DEBUG_TYPE, "UserAssumption", CI) + << "Use user assumption: " << stringFromIslObj(AssumptionCtx)); Context = isl_set_intersect(Context, AssumptionCtx); } } @@ -2830,7 +2828,7 @@ isl_set_free(InvalidDomain); InvalidDomainMap.erase(BB); - invalidate(COMPLEXITY, TI->getDebugLoc()); + invalidate(COMPLEXITY, TI->getDebugLoc(), TI->getParent()); return false; } @@ -3403,17 +3401,13 @@ SmallPtrSet ReadWriteArrays; SmallPtrSet ReadOnlyArrays; - auto &F = getFunction(); - if (AliasGroup.size() < 2) return true; for (MemoryAccess *Access : AliasGroup) { - emitOptimizationRemarkAnalysis( - F.getContext(), DEBUG_TYPE, F, - Access->getAccessInstruction()->getDebugLoc(), - "Possibly aliasing pointer, use restrict keyword."); - + ORE.emit(OptimizationRemarkAnalysis(DEBUG_TYPE, "PossibleAlias", + Access->getAccessInstruction()) + << "Possibly aliasing pointer, use restrict keyword."); const ScopArrayInfo *Array = Access->getScopArrayInfo(); if (HasWriteAccess.count(Array)) { ReadWriteArrays.insert(Array); @@ -3437,7 +3431,8 @@ // compute a sufficiently tight lower and upper bound: bail out. for (MemoryAccess *MA : AliasGroup) { if (!MA->isAffine()) { - invalidate(ALIASING, MA->getAccessInstruction()->getDebugLoc()); + invalidate(ALIASING, MA->getAccessInstruction()->getDebugLoc(), + MA->getAccessInstruction()->getParent()); return false; } } @@ -3512,10 +3507,10 @@ } Scop::Scop(Region &R, ScalarEvolution &ScalarEvolution, LoopInfo &LI, - ScopDetection::DetectionContext &DC) + ScopDetection::DetectionContext &DC, OptimizationRemarkEmitter &ORE) : SE(&ScalarEvolution), R(R), name(R.getNameStr()), IsOptimized(false), HasSingleExitEdge(R.getExitingBlock()), HasErrorBlock(false), - MaxLoopDepth(0), CopyStmtsNum(0), SkipScop(false), DC(DC), + MaxLoopDepth(0), CopyStmtsNum(0), SkipScop(false), DC(DC), ORE(ORE), IslCtx(isl_ctx_alloc(), isl_ctx_free), Context(nullptr), Affinator(this, LI), AssumedContext(nullptr), InvalidContext(nullptr), Schedule(nullptr), @@ -3860,7 +3855,7 @@ if (isl_set_n_basic_set(DomainCtx) >= MaxDisjunctsInDomain) { auto *AccInst = InvMAs.front().MA->getAccessInstruction(); - invalidate(COMPLEXITY, AccInst->getDebugLoc()); + invalidate(COMPLEXITY, AccInst->getDebugLoc(), AccInst->getParent()); isl_set_free(DomainCtx); for (auto &InvMA : InvMAs) isl_set_free(InvMA.NonHoistableCtx); @@ -4034,7 +4029,7 @@ return nullptr; addAssumption(INVARIANTLOAD, WrittenCtx.copy(), LI->getDebugLoc(), - AS_RESTRICTION); + AS_RESTRICTION, LI->getParent()); return WrittenCtx; } @@ -4044,7 +4039,7 @@ assert(LI && contains(LI)); ScopStmt *Stmt = getStmtFor(LI); if (Stmt && Stmt->getArrayAccessOrNULLFor(LI)) { - invalidate(INVARIANTLOAD, LI->getDebugLoc()); + invalidate(INVARIANTLOAD, LI->getDebugLoc(), LI->getParent()); return; } } @@ -4329,7 +4324,7 @@ } bool Scop::trackAssumption(AssumptionKind Kind, __isl_keep isl_set *Set, - DebugLoc Loc, AssumptionSign Sign) { + DebugLoc Loc, AssumptionSign Sign, BasicBlock *BB) { if (PollyRemarksMinimal && !isEffectiveAssumption(Set, Sign)) return false; @@ -4380,19 +4375,24 @@ break; } - auto &F = getFunction(); auto Suffix = Sign == AS_ASSUMPTION ? " assumption:\t" : " restriction:\t"; std::string Msg = toString(Kind) + Suffix + stringFromIslObj(Set); - emitOptimizationRemarkAnalysis(F.getContext(), DEBUG_TYPE, F, Loc, Msg); + if (BB) + ORE.emit(OptimizationRemarkAnalysis(DEBUG_TYPE, "AssumpRestrict", Loc, BB) + << Msg); + else + ORE.emit(OptimizationRemarkAnalysis(DEBUG_TYPE, "AssumpRestrict", Loc, + R.getEntry()) + << Msg); return true; } void Scop::addAssumption(AssumptionKind Kind, __isl_take isl_set *Set, - DebugLoc Loc, AssumptionSign Sign) { + DebugLoc Loc, AssumptionSign Sign, BasicBlock *BB) { // Simplify the assumptions/restrictions first. Set = isl_set_gist_params(Set, getContext()); - if (!trackAssumption(Kind, Set, Loc, Sign)) { + if (!trackAssumption(Kind, Set, Loc, Sign, BB)) { isl_set_free(Set); return; } @@ -4418,7 +4418,7 @@ const Assumption &AS = RecordedAssumptions.pop_back_val(); if (!AS.BB) { - addAssumption(AS.Kind, AS.Set, AS.Loc, AS.Sign); + addAssumption(AS.Kind, AS.Set, AS.Loc, AS.Sign, nullptr /* BasicBlock */); continue; } @@ -4444,12 +4444,12 @@ else /* (AS.Sign == AS_ASSUMPTION) */ S = isl_set_params(isl_set_subtract(Dom, S)); - addAssumption(AS.Kind, S, AS.Loc, AS_RESTRICTION); + addAssumption(AS.Kind, S, AS.Loc, AS_RESTRICTION, AS.BB); } } -void Scop::invalidate(AssumptionKind Kind, DebugLoc Loc) { - addAssumption(Kind, isl_set_empty(getParamSpace()), Loc, AS_ASSUMPTION); +void Scop::invalidate(AssumptionKind Kind, DebugLoc Loc, BasicBlock *BB) { + addAssumption(Kind, isl_set_empty(getParamSpace()), Loc, AS_ASSUMPTION, BB); } __isl_give isl_set *Scop::getInvalidContext() const { @@ -4581,7 +4581,7 @@ } auto DL = BB ? BB->getTerminator()->getDebugLoc() : DebugLoc(); - invalidate(COMPLEXITY, DL); + invalidate(COMPLEXITY, DL, BB); return Affinator.getPwAff(SE->getZero(E->getType()), BB); } Index: test/ScopDetectionDiagnostics/ReportUnprofitable.ll =================================================================== --- test/ScopDetectionDiagnostics/ReportUnprofitable.ll +++ test/ScopDetectionDiagnostics/ReportUnprofitable.ll @@ -1,13 +1,18 @@ ; RUN: opt %loadPolly -pass-remarks-missed="polly-detect" \ ; RUN: -polly-detect-track-failures -polly-detect -analyze \ ; RUN: -polly-process-unprofitable=false < %s 2>&1| FileCheck %s + +; RUN: opt %loadPolly -pass-remarks-missed="polly-detect" \ +; RUN: -polly-detect-track-failures -polly-detect -analyze \ +; RUN: -polly-process-unprofitable=false < %s 2>&1 -pass-remarks-output=%t.yaml +; RUN: cat %t.yaml | FileCheck -check-prefix=YAML %s target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" ; void onlyWrite(float *A) { ; for (long i = 0; i < 100; i++) ; A[i] = 0; ; } -; +; ; void onlyRead(float *A) { ; for (long i = 0; i < 100; i++) ; A[i]; @@ -21,6 +26,54 @@ ; CHECK: remark: /tmp/test.c:7:3: No profitable polyhedral optimization found ; CHECK: remark: /tmp/test.c:8:10: Invalid Scop candidate ends here. +; YAML: --- !Missed +; YAML: Pass: polly-detect +; YAML: Name: RejectionErrors +; YAML: DebugLoc: { File: /tmp/test.c, Line: 2, Column: 3 } +; YAML: Function: onlyWrite +; YAML: Args: +; YAML: - String: The following errors keep this region from being a Scop. +; YAML: ... +; YAML: --- !Missed +; YAML: Pass: polly-detect +; YAML: Name: Unprofitable +; YAML: DebugLoc: { File: /tmp/test.c, Line: 2, Column: 3 } +; YAML: Function: onlyWrite +; YAML: Args: +; YAML: - String: No profitable polyhedral optimization found +; YAML: ... +; YAML: --- !Missed +; YAML: Pass: polly-detect +; YAML: Name: InvalidScopEnd +; YAML: DebugLoc: { File: /tmp/test.c, Line: 3, Column: 10 } +; YAML: Function: onlyWrite +; YAML: Args: +; YAML: - String: Invalid Scop candidate ends here. +; YAML: ... +; YAML: --- !Missed +; YAML: Pass: polly-detect +; YAML: Name: RejectionErrors +; YAML: DebugLoc: { File: /tmp/test.c, Line: 7, Column: 3 } +; YAML: Function: onlyRead +; YAML: Args: +; YAML: - String: The following errors keep this region from being a Scop. +; YAML: ... +; YAML: --- !Missed +; YAML: Pass: polly-detect +; YAML: Name: Unprofitable +; YAML: DebugLoc: { File: /tmp/test.c, Line: 7, Column: 3 } +; YAML: Function: onlyRead +; YAML: Args: +; YAML: - String: No profitable polyhedral optimization found +; YAML: ... +; YAML: --- !Missed +; YAML: Pass: polly-detect +; YAML: Name: InvalidScopEnd +; YAML: DebugLoc: { File: /tmp/test.c, Line: 8, Column: 10 } +; YAML: Function: onlyRead +; YAML: Args: +; YAML: - String: Invalid Scop candidate ends here. + ; Function Attrs: nounwind uwtable define void @onlyWrite(float* %A) #0 !dbg !4 { Index: test/ScopInfo/user_provided_non_dominating_assumptions.ll =================================================================== --- test/ScopInfo/user_provided_non_dominating_assumptions.ll +++ test/ScopInfo/user_provided_non_dominating_assumptions.ll @@ -16,6 +16,41 @@ ; } ; } ; + + +; RUN: opt %loadPolly -pass-remarks-analysis="polly-scops" -polly-scops \ +; RUN: -polly-precise-inbounds -disable-output < %s 2>&1 -pass-remarks-output=%t.yaml +; RUN: cat %t.yaml | FileCheck -check-prefix=YAML %s +; YAML: --- !Analysis +; YAML: Pass: polly-scops +; YAML: Name: ScopEntry +; YAML: Function: f +; YAML: Args: +; YAML: - String: SCoP begins here. +; YAML: ... +; YAML: --- !Analysis +; YAML: Pass: polly-scops +; YAML: Name: UserAssumption +; YAML: Function: f +; YAML: Args: +; YAML: - String: 'Use user assumption: ' +; YAML: - String: '[i, N, M] -> { : N <= i or (N > i and N >= 0) }' +; YAML: ... +; YAML: --- !Analysis +; YAML: Pass: polly-scops +; YAML: Name: AssumpRestrict +; YAML: Function: f +; YAML: Args: +; YAML: - String: 'Inbounds assumption: [i, N, M] -> { : N <= i or (N > i and M <= 100) }' +; YAML: ... +; YAML: --- !Analysis +; YAML: Pass: polly-scops +; YAML: Name: ScopEnd +; YAML: Function: f +; YAML: Args: +; YAML: - String: SCoP ends here. +; YAML: ... + target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" define void @f(i32* noalias %A, i32* noalias %B, i32 %i, i32 %N, i32 %M, [100 x i32]* %C) {