[polly] Support the new DiagnosticRemarks (v3)

Andreas Simbuerger simbuerg at googlemail.com
Tue Jun 17 01:43:26 PDT 2014


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" <...>

Diff:
http://reviews.llvm.org/D4171

---
 include/polly/ScopDetection.h                      |  17 ++
 include/polly/ScopDetectionDiagnostic.h            | 143 ++++++++++---
 lib/Analysis/ScopDetection.cpp                     |  79 +++++--
 lib/Analysis/ScopDetectionDiagnostic.cpp           | 234 ++++++++++++++++++++-
 test/ScopDetectionDiagnostics/ReportFuncCall-01.ll |  67 ++++++
 5 files changed, 478 insertions(+), 62 deletions(-)
 create mode 100644 test/ScopDetectionDiagnostics/ReportFuncCall-01.ll

diff --git a/include/polly/ScopDetection.h b/include/polly/ScopDetection.h
index 5bab520..34b0844 100644
--- a/include/polly/ScopDetection.h
+++ b/include/polly/ScopDetection.h
@@ -1,361 +1,378 @@
 //===--- ScopDetection.h - Detect Scops -------------------------*- C++ -*-===//
 //
 //                     The LLVM Compiler Infrastructure
 //
 // This file is distributed under the University of Illinois Open Source
 // License. See LICENSE.TXT for details.
 //
 //===----------------------------------------------------------------------===//
 //
 // Detect the maximal Scops of a function.
 //
 // A static control part (Scop) is a subgraph of the control flow graph (CFG)
 // that only has statically known control flow and can therefore be described
 // within the polyhedral model.
 //
 // Every Scop fullfills these restrictions:
 //
 // * It is a single entry single exit region
 //
 // * Only affine linear bounds in the loops
 //
 // Every natural loop in a Scop must have a number of loop iterations that can
 // be described as an affine linear function in surrounding loop iterators or
 // parameters. (A parameter is a scalar that does not change its value during
 // execution of the Scop).
 //
 // * Only comparisons of affine linear expressions in conditions
 //
 // * All loops and conditions perfectly nested
 //
 // The control flow needs to be structured such that it could be written using
 // just 'for' and 'if' statements, without the need for any 'goto', 'break' or
 // 'continue'.
 //
 // * Side effect free functions call
 //
 // Only function calls and intrinsics that do not have side effects are allowed
 // (readnone).
 //
 // The Scop detection finds the largest Scops by checking if the largest
 // region is a Scop. If this is not the case, its canonical subregions are
 // checked until a region is a Scop. It is now tried to extend this Scop by
 // creating a larger non canonical region.
 //
 //===----------------------------------------------------------------------===//
 
 #ifndef POLLY_SCOP_DETECTION_H
 #define POLLY_SCOP_DETECTION_H
 
 #include "llvm/Pass.h"
 #include "llvm/Analysis/AliasSetTracker.h"
 
 #include "polly/ScopDetectionDiagnostic.h"
 
 #include <set>
 #include <map>
 
 using namespace llvm;
 
 namespace llvm {
 class RegionInfo;
 class Region;
 class LoopInfo;
 class Loop;
 class ScalarEvolution;
 class SCEV;
 class SCEVAddRecExpr;
 class SCEVUnknown;
 class CallInst;
 class Instruction;
 class AliasAnalysis;
 class Value;
 }
 
 namespace polly {
 typedef std::set<const SCEV *> ParamSetType;
 
 // Description of the shape of an array.
 struct ArrayShape {
   // Base pointer identifying all accesses to this array.
   const SCEVUnknown *BasePointer;
 
   // Sizes of each delinearized dimension.
   SmallVector<const SCEV *, 4> DelinearizedSizes;
 
   ArrayShape(const SCEVUnknown *B) : BasePointer(B), DelinearizedSizes() {}
 };
 
 struct MemAcc {
   const Instruction *Insn;
 
   // A pointer to the shape description of the array.
   ArrayShape *Shape;
 
   // Subscripts computed by delinearization.
   SmallVector<const SCEV *, 4> DelinearizedSubscripts;
 
   MemAcc(const Instruction *I, ArrayShape *S)
       : Insn(I), Shape(S), DelinearizedSubscripts() {}
 };
 
 typedef std::map<const Instruction *, MemAcc *> MapInsnToMemAcc;
 typedef std::pair<const Instruction *, const SCEVAddRecExpr *> PairInsnAddRec;
 typedef std::vector<PairInsnAddRec> AFs;
 typedef std::map<const SCEVUnknown *, AFs> BaseToAFs;
 typedef std::map<const SCEVUnknown *, const SCEV *> BaseToElSize;
 
 extern bool PollyTrackFailures;
 extern bool PollyDelinearize;
 
 //===----------------------------------------------------------------------===//
 /// @brief Pass to detect the maximal static control parts (Scops) of a
 /// function.
 class ScopDetection : public FunctionPass {
   //===--------------------------------------------------------------------===//
   ScopDetection(const ScopDetection &) LLVM_DELETED_FUNCTION;
   const ScopDetection &operator=(const ScopDetection &) LLVM_DELETED_FUNCTION;
 
   /// @brief Analysis passes used.
   //@{
   ScalarEvolution *SE;
   LoopInfo *LI;
   RegionInfo *RI;
   AliasAnalysis *AA;
   //@}
 
   /// @brief Context variables for SCoP detection.
   struct DetectionContext {
     Region &CurRegion;   // The region to check.
     AliasSetTracker AST; // The AliasSetTracker to hold the alias information.
     bool Verifying;      // If we are in the verification phase?
     RejectLog Log;
 
     // Map a base pointer to all access functions accessing it.
     BaseToAFs NonAffineAccesses, AffineAccesses;
     BaseToElSize ElementSize;
 
     DetectionContext(Region &R, AliasAnalysis &AA, bool Verify)
         : CurRegion(R), AST(AA), Verifying(Verify), Log(&R) {}
   };
 
   // Remember the valid regions
   typedef std::set<const Region *> RegionSet;
   RegionSet ValidRegions;
 
   // Remember a list of errors for every region.
   mutable std::map<const Region *, RejectLog> RejectLogs;
 
   // Remember the invalid functions producted by backends;
   typedef std::set<const Function *> FunctionSet;
   FunctionSet InvalidFunctions;
 
   // Delinearize all non affine memory accesses and return false when there
   // exists a non affine memory access that cannot be delinearized. Return true
   // when all array accesses are affine after delinearization.
   bool hasAffineMemoryAccesses(DetectionContext &Context) const;
 
   // Try to expand the region R. If R can be expanded return the expanded
   // region, NULL otherwise.
   Region *expandRegion(Region &R);
 
   /// Find the Scops in this region tree.
   ///
   /// @param The region tree to scan for scops.
   void findScops(Region &R);
 
   /// @brief Check if all basic block in the region are valid.
   ///
   /// @param Context The context of scop detection.
   ///
   /// @return True if all blocks in R are valid, false otherwise.
   bool allBlocksValid(DetectionContext &Context) const;
 
   /// @brief Check the exit block of a region is valid.
   ///
   /// @param Context The context of scop detection.
   ///
   /// @return True if the exit of R is valid, false otherwise.
   bool isValidExit(DetectionContext &Context) const;
 
   /// @brief Check if a region is a Scop.
   ///
   /// @param Context The context of scop detection.
   ///
   /// @return True if R is a Scop, false otherwise.
   bool isValidRegion(DetectionContext &Context) const;
 
   /// @brief Check if a region is a Scop.
   ///
   /// @param Context The context of scop detection.
   ///
   /// @return True if R is a Scop, false otherwise.
   bool isValidRegion(Region &R) const;
 
   /// @brief Check if a call instruction can be part of a Scop.
   ///
   /// @param CI The call instruction to check.
   /// @return True if the call instruction is valid, false otherwise.
   static bool isValidCallInst(CallInst &CI);
 
   /// @brief Check if a value is invariant in the region Reg.
   ///
   /// @param Val Value to check for invariance.
   /// @param Reg The region to consider for the invariance of Val.
   ///
   /// @return True if the value represented by Val is invariant in the region
   ///         identified by Reg.
   bool isInvariant(const Value &Val, const Region &Reg) const;
 
   /// @brief Check if a memory access can be part of a Scop.
   ///
   /// @param Inst The instruction accessing the memory.
   /// @param Context The context of scop detection.
   ///
   /// @return True if the memory access is valid, false otherwise.
   bool isValidMemoryAccess(Instruction &Inst, DetectionContext &Context) const;
 
   /// @brief Check if an instruction has any non trivial scalar dependencies
   ///        as part of a Scop.
   ///
   /// @param Inst The instruction to check.
   /// @param RefRegion The region in respect to which we check the access
   ///                  function.
   ///
   /// @return True if the instruction has scalar dependences, false otherwise.
   bool hasScalarDependency(Instruction &Inst, Region &RefRegion) const;
 
   /// @brief Check if an instruction can be part of a Scop.
   ///
   /// @param Inst The instruction to check.
   /// @param Context The context of scop detection.
   ///
   /// @return True if the instruction is valid, false otherwise.
   bool isValidInstruction(Instruction &Inst, DetectionContext &Context) const;
 
   /// @brief Check if the control flow in a basic block is valid.
   ///
   /// @param BB The BB to check the control flow.
   /// @param Context The context of scop detection.
   ///
   /// @return True if the BB contains only valid control flow.
   bool isValidCFG(BasicBlock &BB, DetectionContext &Context) const;
 
   /// @brief Is a loop valid with respect to a given region.
   ///
   /// @param L The loop to check.
   /// @param Context The context of scop detection.
   ///
   /// @return True if the loop is valid in the region.
   bool isValidLoop(Loop *L, DetectionContext &Context) const;
 
   /// @brief Check if a function is an OpenMP subfunction.
   ///
   /// An OpenMP subfunction is not valid for Scop detection.
   ///
   /// @param F The function to check.
   ///
   /// @return True if the function is not an OpenMP subfunction.
   bool isValidFunction(llvm::Function &F);
 
   /// @brief Print the locations of all detected scops.
   void printLocations(llvm::Function &F);
 
   /// @brief Track diagnostics for invalid scops.
   ///
   /// @param Context The context of scop detection.
   /// @param Assert Throw an assert in verify mode or not.
   /// @param Args Argument list that gets passed to the constructor of RR.
   template <class RR, typename... Args>
   inline bool invalid(DetectionContext &Context, bool Assert,
                       Args &&... Arguments) const;
 
 public:
   static char ID;
   explicit ScopDetection() : FunctionPass(ID) {}
 
   /// @brief Get the RegionInfo stored in this pass.
   ///
   /// This was added to give the DOT printer easy access to this information.
   RegionInfo *getRI() const { return RI; }
 
   /// @brief Is the region is the maximum region of a Scop?
   ///
   /// @param R The Region to test if it is maximum.
   /// @param Verify Rerun the scop detection to verify SCoP was not invalidated
   ///               meanwhile.
   ///
   /// @return Return true if R is the maximum Region in a Scop, false otherwise.
   bool isMaxRegionInScop(const Region &R, bool Verify = true) const;
 
   /// @brief Get a message why a region is invalid
   ///
   /// @param R The region for which we get the error message
   ///
   /// @return The error or "" if no error appeared.
   std::string regionIsInvalidBecause(const Region *R) const;
 
   /// @name Maximum Region In Scops Iterators
   ///
   /// These iterators iterator over all maximum region in Scops of this
   /// function.
   //@{
   typedef RegionSet::iterator iterator;
   typedef RegionSet::const_iterator const_iterator;
 
   iterator begin() { return ValidRegions.begin(); }
   iterator end() { return ValidRegions.end(); }
 
   const_iterator begin() const { return ValidRegions.begin(); }
   const_iterator end() const { return ValidRegions.end(); }
   //@}
 
   /// @name Reject log iterators
   ///
   /// These iterators iterate over the logs of all rejected regions of this
   //  function.
   //@{
   typedef std::map<const Region *, RejectLog>::iterator reject_iterator;
   typedef std::map<const Region *, RejectLog>::const_iterator
   const_reject_iterator;
 
   reject_iterator reject_begin() { return RejectLogs.begin(); }
   reject_iterator reject_end() { return RejectLogs.end(); }
 
   const_reject_iterator reject_begin() const { return RejectLogs.begin(); }
   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.
   ///
   /// @param F The function to mark as invalid.
   void markFunctionAsInvalid(const Function *F) { InvalidFunctions.insert(F); }
 
   /// @brief Verify if all valid Regions in this Function are still valid
   /// after some transformations.
   void verifyAnalysis() const;
 
   /// @brief Verify if R is still a valid part of Scop after some
   /// transformations.
   ///
   /// @param R The Region to verify.
   void verifyRegion(const Region &R) const;
 
   /// @name FunctionPass interface
   //@{
   virtual void getAnalysisUsage(AnalysisUsage &AU) const;
   virtual void releaseMemory();
   virtual bool runOnFunction(Function &F);
   virtual void print(raw_ostream &OS, const Module *) const;
   //@}
 };
 
 } // end namespace polly
 
 namespace llvm {
 class PassRegistry;
 void initializeScopDetectionPass(llvm::PassRegistry &);
 }
 
 #endif
diff --git a/include/polly/ScopDetectionDiagnostic.h b/include/polly/ScopDetectionDiagnostic.h
index 1006770..964bd88 100644
--- a/include/polly/ScopDetectionDiagnostic.h
+++ b/include/polly/ScopDetectionDiagnostic.h
@@ -1,515 +1,588 @@
 //=== ScopDetectionDiagnostic.h -- Diagnostic for ScopDetection -*- C++ -*-===//
 //
 //                     The LLVM Compiler Infrastructure
 //
 // This file is distributed under the University of Illinois Open Source
 // License. See LICENSE.TXT for details.
 //
 //===----------------------------------------------------------------------===//
 //
 // Small set of diagnostic helper classes to encapsulate any errors occurred
 // during the detection of Scops.
 //
 // The ScopDetection defines a set of error classes (via Statistic variables)
 // that groups a number of individual errors into a group, e.g. non-affinity
 // related errors.
 // On error we generate an object that carries enough additional information
 // to diagnose the error and generate a helpful error message.
 //
 //===----------------------------------------------------------------------===//
 #ifndef POLLY_SCOP_DETECTION_DIAGNOSTIC_H
 #define POLLY_SCOP_DETECTION_DIAGNOSTIC_H
 
 #include "llvm/Analysis/LoopInfo.h"
 #include "llvm/Analysis/AliasSetTracker.h"
 #include "llvm/IR/BasicBlock.h"
 #include "llvm/IR/Value.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/Statistic.h"
 #include "llvm/ADT/Twine.h"
 #include "llvm/Analysis/ScalarEvolutionExpressions.h"
 
 #include <string>
 #include <memory>
 
 using namespace llvm;
 
 namespace llvm {
 class SCEV;
 class BasicBlock;
 class Value;
 class Region;
 }
 
 namespace polly {
 
 /// @brief Get the location of a region from the debug info.
 ///
 /// @param R The region to get debug info for.
 /// @param LineBegin The first line in the region.
 /// @param LineEnd The last line in the region.
 /// @param FileName The filename where the region was defined.
 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.
 ///
 /// Subclasses of RejectReason should provide means to capture enough
 /// diagnostic information to help clients figure out what and where something
 /// went wrong in the Scop detection.
 class RejectReason {
   //===--------------------------------------------------------------------===//
+  static const llvm::DebugLoc Unknown;
 public:
   virtual ~RejectReason() {}
 
   /// @brief Generate a reasonable diagnostic message describing this error.
   ///
   /// @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<RejectReason> RejectReasonPtr;
 
 /// @brief Stores all errors that ocurred during the detection.
 class RejectLog {
   Region *R;
   llvm::SmallVector<RejectReasonPtr, 1> ErrorReports;
 
 public:
   explicit RejectLog(Region *R) : R(R) {}
 
-  typedef llvm::SmallVector<RejectReasonPtr, 1>::iterator iterator;
+  typedef llvm::SmallVector<RejectReasonPtr, 1>::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; }
   void report(RejectReasonPtr Reject) { ErrorReports.push_back(Reject); }
 };
 
 //===----------------------------------------------------------------------===//
 /// @brief Base class for CFG related reject reasons.
 ///
 /// Scop candidates that violate structural restrictions can be grouped under
 /// this reject reason class.
 class ReportCFG : public RejectReason {
   //===--------------------------------------------------------------------===//
 public:
   ReportCFG();
 };
 
 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 const DebugLoc &getDebugLoc() const;
   //@}
 };
 
 //===----------------------------------------------------------------------===//
 /// @brief Captures a not well-structured condition within the CFG.
 class ReportCondition : public ReportCFG {
   //===--------------------------------------------------------------------===//
 
   // The BasicBlock we found the broken condition in.
   BasicBlock *BB;
 
 public:
-  ReportCondition(BasicBlock *BB) : BB(BB) {}
+  ReportCondition(BasicBlock *BB) : ReportCFG(), BB(BB) {}
 
   /// @name RejectReason interface
   //@{
   virtual std::string getMessage() const;
+  virtual const DebugLoc &getDebugLoc() const;
   //@}
 };
 
 //===----------------------------------------------------------------------===//
 /// @brief Base class for non-affine reject reasons.
 ///
 /// Scop candidates that violate restrictions to affinity are reported under
 /// 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 { return Inst->getDebugLoc(); };
 };
 
 //===----------------------------------------------------------------------===//
 /// @brief Captures a condition that is based on an 'undef' value.
 class ReportUndefCond : public ReportAffFunc {
   //===--------------------------------------------------------------------===//
 
   // The BasicBlock we found the broken condition in.
   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;
   //@}
 };
 
 //===----------------------------------------------------------------------===//
 /// @brief Captures an invalid condition
 ///
 /// Conditions have to be either constants or icmp instructions.
 class ReportInvalidCond : public ReportAffFunc {
   //===--------------------------------------------------------------------===//
 
   // The BasicBlock we found the broken condition in.
   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;
   //@}
 };
 
 //===----------------------------------------------------------------------===//
 /// @brief Captures an undefined operand.
 class ReportUndefOperand : public ReportAffFunc {
   //===--------------------------------------------------------------------===//
 
   // The BasicBlock we found the undefined operand in.
   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;
   //@}
 };
 
 //===----------------------------------------------------------------------===//
 /// @brief Captures a non-affine branch.
 class ReportNonAffBranch : public ReportAffFunc {
   //===--------------------------------------------------------------------===//
 
   // The BasicBlock we found the non-affine branch in.
   BasicBlock *BB;
 
   /// @brief LHS & RHS of the failed condition.
   //@{
   const SCEV *LHS;
   const SCEV *RHS;
   //@}
 
 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;
   //@}
 };
 
 //===----------------------------------------------------------------------===//
 /// @brief Captures a missing base pointer.
 class ReportNoBasePtr : public ReportAffFunc {
   //===--------------------------------------------------------------------===//
 public:
+  ReportNoBasePtr(const Instruction *Inst) : ReportAffFunc(Inst) {}
+
   /// @name RejectReason interface
   //@{
   virtual std::string getMessage() const;
   //@}
 };
 
 //===----------------------------------------------------------------------===//
 /// @brief Captures an undefined base pointer.
 class ReportUndefBasePtr : public ReportAffFunc {
   //===--------------------------------------------------------------------===//
 public:
+  ReportUndefBasePtr(const Instruction *Inst) : ReportAffFunc(Inst) {}
+
   /// @name RejectReason interface
   //@{
   virtual std::string getMessage() const;
   //@}
 };
 
 //===----------------------------------------------------------------------===//
 /// @brief Captures a base pointer that is not invariant in the region.
 class ReportVariantBasePtr : public ReportAffFunc {
   //===--------------------------------------------------------------------===//
 
   // The variant base pointer.
   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;
   //@}
 };
 
 //===----------------------------------------------------------------------===//
 /// @brief Captures a non-affine access function.
 class ReportNonAffineAccess : public ReportAffFunc {
   //===--------------------------------------------------------------------===//
 
   // The non-affine access function.
   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;
   //@}
 };
 
 //===----------------------------------------------------------------------===//
 /// @brief Base class for reject reasons related to induction variables.
 ///
 //  ReportIndVar reject reasons are generated when the ScopDetection finds
 /// errors in the induction variable(s) of the Scop candidate.
 class ReportIndVar : public RejectReason {
   //===--------------------------------------------------------------------===//
 public:
   ReportIndVar();
 };
 
 //===----------------------------------------------------------------------===//
 /// @brief Captures a phi node that refers to SSA names in the current region.
 class ReportPhiNodeRefInRegion : public ReportIndVar {
   //===--------------------------------------------------------------------===//
 
   // The offending instruction.
   Instruction *Inst;
 
 public:
-  ReportPhiNodeRefInRegion(Instruction *Inst) : Inst(Inst) {}
+  ReportPhiNodeRefInRegion(Instruction *Inst);
 
   /// @name RejectReason interface
   //@{
   virtual std::string getMessage() const;
+  virtual const DebugLoc &getDebugLoc() const;
   //@}
 };
 
 //===----------------------------------------------------------------------===//
 /// @brief Captures a non canonical phi node.
 class ReportNonCanonicalPhiNode : public ReportIndVar {
   //===--------------------------------------------------------------------===//
 
   // The offending instruction.
   Instruction *Inst;
 
 public:
-  ReportNonCanonicalPhiNode(Instruction *Inst) : Inst(Inst) {}
+  ReportNonCanonicalPhiNode(Instruction *Inst);
 
   /// @name RejectReason interface
   //@{
   virtual std::string getMessage() const;
+  virtual const DebugLoc &getDebugLoc() const;
   //@}
 };
 
 //===----------------------------------------------------------------------===//
 /// @brief Captures a non canonical induction variable in the loop header.
 class ReportLoopHeader : public ReportIndVar {
   //===--------------------------------------------------------------------===//
 
   // The offending loop.
   Loop *L;
 
 public:
-  ReportLoopHeader(Loop *L) : L(L) {}
+  ReportLoopHeader(Loop *L);
 
   /// @name RejectReason interface
   //@{
   virtual std::string getMessage() const;
+  virtual const DebugLoc &getDebugLoc() const;
   //@}
 };
 
 //===----------------------------------------------------------------------===//
 /// @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 const DebugLoc &getDebugLoc() const;
   //@}
 };
 
 //===----------------------------------------------------------------------===//
 /// @brief Captures errors with non affine loop bounds.
 class ReportLoopBound : public RejectReason {
   //===--------------------------------------------------------------------===//
 
   // The offending loop.
   Loop *L;
 
   // The non-affine loop bound.
   const SCEV *LoopCount;
 
 public:
   ReportLoopBound(Loop *L, const SCEV *LoopCount);
 
   const SCEV *loopCount() { return LoopCount; }
 
   /// @name RejectReason interface
   //@{
   virtual std::string getMessage() const;
+  virtual const DebugLoc &getDebugLoc() const;
   //@}
 };
 
 //===----------------------------------------------------------------------===//
 /// @brief Captures errors with non-side-effect-known function calls.
 class ReportFuncCall : public RejectReason {
   //===--------------------------------------------------------------------===//
 
   // The offending call instruction.
   Instruction *Inst;
 
 public:
   ReportFuncCall(Instruction *Inst);
 
   /// @name RejectReason interface
   //@{
-  std::string getMessage() const;
+  virtual std::string getMessage() const;
+  virtual const DebugLoc &getDebugLoc() const;
+  virtual std::string getEndUserMessage() const;
   //@}
 };
 
 //===----------------------------------------------------------------------===//
 /// @brief Captures errors with aliasing.
 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;
+  virtual const DebugLoc &getDebugLoc() const;
   //@}
 };
 
 //===----------------------------------------------------------------------===//
 /// @brief Captures errors with non simplified loops.
 class ReportSimpleLoop : public RejectReason {
   //===--------------------------------------------------------------------===//
 public:
   ReportSimpleLoop();
 
   /// @name RejectReason interface
   //@{
-  std::string getMessage() const;
+  virtual std::string getMessage() const;
   //@}
 };
 
 //===----------------------------------------------------------------------===//
 /// @brief Base class for otherwise ungrouped reject reasons.
 class ReportOther : public RejectReason {
   //===--------------------------------------------------------------------===//
 public:
   ReportOther();
 
   /// @name RejectReason interface
   //@{
-  std::string getMessage() const { return "Unknown reject reason"; }
+  virtual std::string getMessage() const;
   //@}
 };
 
 //===----------------------------------------------------------------------===//
 /// @brief Captures errors with bad IntToPtr instructions.
 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;
+  virtual const DebugLoc &getDebugLoc() const;
   //@}
 };
 
 //===----------------------------------------------------------------------===//
 /// @brief Captures errors with alloca instructions.
 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;
+  virtual const DebugLoc &getDebugLoc() const;
   //@}
 };
 
 //===----------------------------------------------------------------------===//
 /// @brief Captures errors with unknown instructions.
 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;
+  virtual const DebugLoc &getDebugLoc() const;
   //@}
 };
 
 //===----------------------------------------------------------------------===//
 /// @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;
+  virtual const DebugLoc &getDebugLoc() const;
   //@}
 };
 
 //===----------------------------------------------------------------------===//
 /// @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;
+  virtual const DebugLoc &getDebugLoc() const;
   //@}
 };
 
 } // namespace polly
 
 #endif // POLLY_SCOP_DETECTION_DIAGNOSTIC_H
diff --git a/lib/Analysis/ScopDetection.cpp b/lib/Analysis/ScopDetection.cpp
index f1fafaa..af8eeab 100644
--- a/lib/Analysis/ScopDetection.cpp
+++ b/lib/Analysis/ScopDetection.cpp
@@ -1,862 +1,905 @@
 //===----- ScopDetection.cpp  - Detect Scops --------------------*- C++ -*-===//
 //
 //                     The LLVM Compiler Infrastructure
 //
 // This file is distributed under the University of Illinois Open Source
 // License. See LICENSE.TXT for details.
 //
 //===----------------------------------------------------------------------===//
 //
 // Detect the maximal Scops of a function.
 //
 // A static control part (Scop) is a subgraph of the control flow graph (CFG)
 // that only has statically known control flow and can therefore be described
 // within the polyhedral model.
 //
 // Every Scop fullfills these restrictions:
 //
 // * It is a single entry single exit region
 //
 // * Only affine linear bounds in the loops
 //
 // Every natural loop in a Scop must have a number of loop iterations that can
 // be described as an affine linear function in surrounding loop iterators or
 // parameters. (A parameter is a scalar that does not change its value during
 // execution of the Scop).
 //
 // * Only comparisons of affine linear expressions in conditions
 //
 // * All loops and conditions perfectly nested
 //
 // The control flow needs to be structured such that it could be written using
 // just 'for' and 'if' statements, without the need for any 'goto', 'break' or
 // 'continue'.
 //
 // * Side effect free functions call
 //
 // Only function calls and intrinsics that do not have side effects are allowed
 // (readnone).
 //
 // The Scop detection finds the largest Scops by checking if the largest
 // region is a Scop. If this is not the case, its canonical subregions are
 // checked until a region is a Scop. It is now tried to extend this Scop by
 // creating a larger non canonical region.
 //
 //===----------------------------------------------------------------------===//
 
 #include "polly/CodeGen/BlockGenerators.h"
 #include "polly/LinkAllPasses.h"
 #include "polly/Options.h"
 #include "polly/ScopDetectionDiagnostic.h"
 #include "polly/ScopDetection.h"
 #include "polly/Support/SCEVValidator.h"
 #include "polly/Support/ScopHelper.h"
 #include "llvm/ADT/Statistic.h"
 #include "llvm/Analysis/AliasAnalysis.h"
 #include "llvm/Analysis/LoopInfo.h"
 #include "llvm/Analysis/RegionIterator.h"
 #include "llvm/Analysis/ScalarEvolution.h"
 #include "llvm/Analysis/ScalarEvolutionExpressions.h"
 #include "llvm/IR/DebugInfo.h"
 #include "llvm/IR/DiagnosticInfo.h"
 #include "llvm/IR/DiagnosticPrinter.h"
 #include "llvm/IR/LLVMContext.h"
 #include "llvm/Support/Debug.h"
 #include <set>
 
 using namespace llvm;
 using namespace polly;
 
 #define DEBUG_TYPE "polly-detect"
 
 static cl::opt<bool>
 DetectScopsWithoutLoops("polly-detect-scops-in-functions-without-loops",
                         cl::desc("Detect scops in functions without loops"),
                         cl::Hidden, cl::init(false), cl::ZeroOrMore,
                         cl::cat(PollyCategory));
 
 static cl::opt<bool>
 DetectRegionsWithoutLoops("polly-detect-scops-in-regions-without-loops",
                           cl::desc("Detect scops in regions without loops"),
                           cl::Hidden, cl::init(false), cl::ZeroOrMore,
                           cl::cat(PollyCategory));
 
 static cl::opt<std::string>
 OnlyFunction("polly-only-func",
              cl::desc("Only run on functions that contain a certain string"),
              cl::value_desc("string"), cl::ValueRequired, cl::init(""),
              cl::cat(PollyCategory));
 
 static cl::opt<std::string>
 OnlyRegion("polly-only-region",
            cl::desc("Only run on certain regions (The provided identifier must "
                     "appear in the name of the region's entry block"),
            cl::value_desc("identifier"), cl::ValueRequired, cl::init(""),
            cl::cat(PollyCategory));
 
 static cl::opt<bool>
 IgnoreAliasing("polly-ignore-aliasing",
                cl::desc("Ignore possible aliasing of the array bases"),
                cl::Hidden, cl::init(false), cl::ZeroOrMore,
                cl::cat(PollyCategory));
 
 static cl::opt<bool>
 ReportLevel("polly-report",
             cl::desc("Print information about the activities of Polly"),
             cl::init(false), cl::ZeroOrMore, cl::cat(PollyCategory));
 
 static cl::opt<bool>
 AllowNonAffine("polly-allow-nonaffine",
                cl::desc("Allow non affine access functions in arrays"),
                cl::Hidden, cl::init(false), cl::ZeroOrMore,
                cl::cat(PollyCategory));
 
 static cl::opt<bool, true>
 TrackFailures("polly-detect-track-failures",
               cl::desc("Track failure strings in detecting scop regions"),
               cl::location(PollyTrackFailures), cl::Hidden, cl::ZeroOrMore,
               cl::init(false), cl::cat(PollyCategory));
 
 static cl::opt<bool> KeepGoing("polly-detect-keep-going",
                                cl::desc("Do not fail on the first error."),
                                cl::Hidden, cl::ZeroOrMore, cl::init(false),
                                cl::cat(PollyCategory));
 
 static cl::opt<bool, true>
 PollyDelinearizeX("polly-delinearize",
                   cl::desc("Delinearize array access functions"),
                   cl::location(PollyDelinearize), cl::Hidden, cl::ZeroOrMore,
                   cl::init(false), cl::cat(PollyCategory));
 
 static cl::opt<bool>
 VerifyScops("polly-detect-verify",
             cl::desc("Verify the detected SCoPs after each transformation"),
             cl::Hidden, cl::init(false), cl::ZeroOrMore,
             cl::cat(PollyCategory));
 
 bool polly::PollyTrackFailures = false;
 bool polly::PollyDelinearize = false;
 
 //===----------------------------------------------------------------------===//
 // Statistics.
 
 STATISTIC(ValidRegion, "Number of regions that a valid part of Scop");
 
 class DiagnosticScopFound : public DiagnosticInfo {
 private:
   static int PluginDiagnosticKind;
 
   Function &F;
   std::string FileName;
   unsigned EntryLine, ExitLine;
 
 public:
   DiagnosticScopFound(Function &F, std::string FileName, unsigned EntryLine,
                       unsigned ExitLine)
       : DiagnosticInfo(PluginDiagnosticKind, DS_Note), F(F), FileName(FileName),
         EntryLine(EntryLine), ExitLine(ExitLine) {}
 
   virtual void print(DiagnosticPrinter &DP) const;
 
   static bool classof(const DiagnosticInfo *DI) {
     return DI->getKind() == PluginDiagnosticKind;
   }
 };
 
 int DiagnosticScopFound::PluginDiagnosticKind = 10;
 
 void DiagnosticScopFound::print(DiagnosticPrinter &DP) const {
   DP << "Polly detected an optimizable loop region (scop) in function '" << F
      << "'\n";
 
   if (FileName.empty()) {
     DP << "Scop location is unknown. Compile with debug info "
           "(-g) to get more precise information. ";
     return;
   }
 
   DP << FileName << ":" << EntryLine << ": Start of scop\n";
   DP << FileName << ":" << ExitLine << ": End of scop";
 }
 
 //===----------------------------------------------------------------------===//
 // ScopDetection.
 
 template <class RR, typename... Args>
 inline bool ScopDetection::invalid(DetectionContext &Context, bool Assert,
                                    Args &&... Arguments) const {
 
   if (!Context.Verifying) {
     RejectLog &Log = Context.Log;
     std::shared_ptr<RR> RejectReason = std::make_shared<RR>(Arguments...);
 
     if (PollyTrackFailures)
       Log.report(RejectReason);
 
     DEBUG(dbgs() << RejectReason->getMessage());
     DEBUG(dbgs() << "\n");
   } else {
     assert(!Assert && "Verification of detected scop failed");
   }
 
   return false;
 }
 
 bool ScopDetection::isMaxRegionInScop(const Region &R, bool Verify) const {
   if (!ValidRegions.count(&R))
     return false;
 
   if (Verify)
     return isValidRegion(const_cast<Region &>(R));
 
   return true;
 }
 
 std::string ScopDetection::regionIsInvalidBecause(const Region *R) const {
   if (!RejectLogs.count(R))
     return "";
 
   // Get the first error we found. Even in keep-going mode, this is the first
   // reason that caused the candidate to be rejected.
   RejectLog Errors = RejectLogs.at(R);
 
   // This can happen when we marked a region invalid, but didn't track
   // an error for it.
   if (Errors.size() == 0)
     return "";
 
   RejectReasonPtr RR = *Errors.begin();
   return RR->getMessage();
 }
 
 bool ScopDetection::isValidCFG(BasicBlock &BB,
                                DetectionContext &Context) const {
   Region &RefRegion = Context.CurRegion;
   TerminatorInst *TI = BB.getTerminator();
 
   // Return instructions are only valid if the region is the top level region.
   if (isa<ReturnInst>(TI) && !RefRegion.getExit() && TI->getNumOperands() == 0)
     return true;
 
   BranchInst *Br = dyn_cast<BranchInst>(TI);
 
   if (!Br)
     return invalid<ReportNonBranchTerminator>(Context, /*Assert=*/true, &BB);
 
   if (Br->isUnconditional())
     return true;
 
   Value *Condition = Br->getCondition();
 
   // UndefValue is not allowed as condition.
   if (isa<UndefValue>(Condition))
-    return invalid<ReportUndefCond>(Context, /*Assert=*/true, &BB);
+    return invalid<ReportUndefCond>(Context, /*Assert=*/true, Br, &BB);
 
   // Only Constant and ICmpInst are allowed as condition.
   if (!(isa<Constant>(Condition) || isa<ICmpInst>(Condition)))
-    return invalid<ReportInvalidCond>(Context, /*Assert=*/true, &BB);
+    return invalid<ReportInvalidCond>(Context, /*Assert=*/true, Br, &BB);
 
   // Allow perfectly nested conditions.
   assert(Br->getNumSuccessors() == 2 && "Unexpected number of successors");
 
   if (ICmpInst *ICmp = dyn_cast<ICmpInst>(Condition)) {
     // Unsigned comparisons are not allowed. They trigger overflow problems
     // in the code generation.
     //
     // TODO: This is not sufficient and just hides bugs. However it does pretty
     // well.
     if (ICmp->isUnsigned())
       return false;
 
     // Are both operands of the ICmp affine?
     if (isa<UndefValue>(ICmp->getOperand(0)) ||
         isa<UndefValue>(ICmp->getOperand(1)))
-      return invalid<ReportUndefOperand>(Context, /*Assert=*/true, &BB);
+      return invalid<ReportUndefOperand>(Context, /*Assert=*/true, &BB, ICmp);
 
     Loop *L = LI->getLoopFor(ICmp->getParent());
     const SCEV *LHS = SE->getSCEVAtScope(ICmp->getOperand(0), L);
     const SCEV *RHS = SE->getSCEVAtScope(ICmp->getOperand(1), L);
 
     if (!isAffineExpr(&Context.CurRegion, LHS, *SE) ||
         !isAffineExpr(&Context.CurRegion, RHS, *SE))
       return invalid<ReportNonAffBranch>(Context, /*Assert=*/true, &BB, LHS,
-                                         RHS);
+                                         RHS, ICmp);
   }
 
   // Allow loop exit conditions.
   Loop *L = LI->getLoopFor(&BB);
   if (L && L->getExitingBlock() == &BB)
     return true;
 
   // Allow perfectly nested conditions.
   Region *R = RI->getRegionFor(&BB);
   if (R->getEntry() != &BB)
     return invalid<ReportCondition>(Context, /*Assert=*/true, &BB);
 
   return true;
 }
 
 bool ScopDetection::isValidCallInst(CallInst &CI) {
   if (CI.mayHaveSideEffects() || CI.doesNotReturn())
     return false;
 
   if (CI.doesNotAccessMemory())
     return true;
 
   Function *CalledFunction = CI.getCalledFunction();
 
   // Indirect calls are not supported.
   if (CalledFunction == 0)
     return false;
 
   // TODO: Intrinsics.
   return false;
 }
 
 bool ScopDetection::isInvariant(const Value &Val, const Region &Reg) const {
   // A reference to function argument or constant value is invariant.
   if (isa<Argument>(Val) || isa<Constant>(Val))
     return true;
 
   const Instruction *I = dyn_cast<Instruction>(&Val);
   if (!I)
     return false;
 
   if (!Reg.contains(I))
     return true;
 
   if (I->mayHaveSideEffects())
     return false;
 
   // When Val is a Phi node, it is likely not invariant. We do not check whether
   // Phi nodes are actually invariant, we assume that Phi nodes are usually not
   // invariant. Recursively checking the operators of Phi nodes would lead to
   // infinite recursion.
   if (isa<PHINode>(*I))
     return false;
 
   for (const Use &Operand : I->operands())
     if (!isInvariant(*Operand, Reg))
       return false;
 
   // When the instruction is a load instruction, check that no write to memory
   // in the region aliases with the load.
   if (const LoadInst *LI = dyn_cast<LoadInst>(I)) {
     AliasAnalysis::Location Loc = AA->getLocation(LI);
     const Region::const_block_iterator BE = Reg.block_end();
     // Check if any basic block in the region can modify the location pointed to
     // by 'Loc'.  If so, 'Val' is (likely) not invariant in the region.
     for (const BasicBlock *BB : Reg.blocks())
       if (AA->canBasicBlockModify(*BB, Loc))
         return false;
   }
 
   return true;
 }
 
 MapInsnToMemAcc InsnToMemAcc;
 
 bool ScopDetection::hasAffineMemoryAccesses(DetectionContext &Context) const {
   for (auto P : Context.NonAffineAccesses) {
     const SCEVUnknown *BasePointer = P.first;
     Value *BaseValue = BasePointer->getValue();
     ArrayShape *Shape = new ArrayShape(BasePointer);
 
     // First step: collect parametric terms in all array references.
     SmallVector<const SCEV *, 4> Terms;
     for (PairInsnAddRec PIAF : Context.NonAffineAccesses[BasePointer])
       PIAF.second->collectParametricTerms(*SE, Terms);
 
     // Also collect terms from the affine memory accesses.
     for (PairInsnAddRec PIAF : Context.AffineAccesses[BasePointer])
       PIAF.second->collectParametricTerms(*SE, Terms);
 
     // Second step: find array shape.
     SE->findArrayDimensions(Terms, Shape->DelinearizedSizes,
                             Context.ElementSize[BasePointer]);
 
     // Third step: compute the access functions for each subscript.
     for (PairInsnAddRec PIAF : Context.NonAffineAccesses[BasePointer]) {
       const SCEVAddRecExpr *AF = PIAF.second;
       const Instruction *Insn = PIAF.first;
       if (Shape->DelinearizedSizes.empty())
-        return invalid<ReportNonAffineAccess>(Context, /*Assert=*/true,
-                                              PIAF.second);
+        return invalid<ReportNonAffineAccess>(Context, /*Assert=*/true, AF,
+                                              Insn);
 
       MemAcc *Acc = new MemAcc(Insn, Shape);
       InsnToMemAcc.insert({Insn, Acc});
       AF->computeAccessFunctions(*SE, Acc->DelinearizedSubscripts,
                                  Shape->DelinearizedSizes);
       if (Shape->DelinearizedSizes.empty() ||
           Acc->DelinearizedSubscripts.empty())
-        return invalid<ReportNonAffineAccess>(Context, /*Assert=*/true, AF);
+        return invalid<ReportNonAffineAccess>(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<ReportNonAffineAccess>(Context, /*Assert=*/true, AF);
+          return invalid<ReportNonAffineAccess>(Context, /*Assert=*/true, AF,
+                                                Insn);
     }
   }
   return true;
 }
 
 bool ScopDetection::isValidMemoryAccess(Instruction &Inst,
                                         DetectionContext &Context) const {
   Value *Ptr = getPointerOperand(Inst);
   Loop *L = LI->getLoopFor(Inst.getParent());
   const SCEV *AccessFunction = SE->getSCEVAtScope(Ptr, L);
   const SCEVUnknown *BasePointer;
   Value *BaseValue;
 
   BasePointer = dyn_cast<SCEVUnknown>(SE->getPointerBase(AccessFunction));
 
   if (!BasePointer)
-    return invalid<ReportNoBasePtr>(Context, /*Assert=*/true);
+    return invalid<ReportNoBasePtr>(Context, /*Assert=*/true, &Inst);
 
   BaseValue = BasePointer->getValue();
 
   if (isa<UndefValue>(BaseValue))
-    return invalid<ReportUndefBasePtr>(Context, /*Assert=*/true);
+    return invalid<ReportUndefBasePtr>(Context, /*Assert=*/true, &Inst);
 
   // Check that the base address of the access is invariant in the current
   // region.
   if (!isInvariant(*BaseValue, Context.CurRegion))
     // 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<ReportVariantBasePtr>(Context, /*Assert=*/false, BaseValue);
+    return invalid<ReportVariantBasePtr>(Context, /*Assert=*/false, BaseValue,
+                                         &Inst);
 
   AccessFunction = SE->getMinusSCEV(AccessFunction, BasePointer);
 
   if (AllowNonAffine) {
     // Do not check whether AccessFunction is affine.
   } else if (!isAffineExpr(&Context.CurRegion, AccessFunction, *SE,
                            BaseValue)) {
     const SCEVAddRecExpr *AF = dyn_cast<SCEVAddRecExpr>(AccessFunction);
 
     if (!PollyDelinearize || !AF)
       return invalid<ReportNonAffineAccess>(Context, /*Assert=*/true,
-                                            AccessFunction);
+                                            AccessFunction, &Inst);
 
     const SCEV *ElementSize = SE->getElementSize(&Inst);
     Context.ElementSize[BasePointer] = ElementSize;
 
     // Collect all non affine memory accesses, and check whether they are linear
     // at the end of scop detection. That way we can delinearize all the memory
     // accesses to the same array in a unique step.
     if (Context.NonAffineAccesses[BasePointer].size() == 0)
       Context.NonAffineAccesses[BasePointer] = AFs();
     Context.NonAffineAccesses[BasePointer].push_back({&Inst, AF});
   } else if (const SCEVAddRecExpr *AF =
                  dyn_cast<SCEVAddRecExpr>(AccessFunction)) {
     if (Context.AffineAccesses[BasePointer].size() == 0)
       Context.AffineAccesses[BasePointer] = AFs();
     Context.AffineAccesses[BasePointer].push_back({&Inst, AF});
   }
 
   // FIXME: Alias Analysis thinks IntToPtrInst aliases with alloca instructions
   // created by IndependentBlocks Pass.
-  if (isa<IntToPtrInst>(BaseValue))
-    return invalid<ReportIntToPtr>(Context, /*Assert=*/true, BaseValue);
+  if (IntToPtrInst *Inst = dyn_cast<IntToPtrInst>(BaseValue))
+    return invalid<ReportIntToPtr>(Context, /*Assert=*/true, Inst);
 
   if (IgnoreAliasing)
     return true;
 
   // Check if the base pointer of the memory access does alias with
   // any other pointer. This cannot be handled at the moment.
   AliasSet &AS =
       Context.AST.getAliasSetForPointer(BaseValue, AliasAnalysis::UnknownSize,
                                         Inst.getMetadata(LLVMContext::MD_tbaa));
 
   // INVALID triggers an assertion in verifying mode, if it detects that a
   // SCoP was detected by SCoP detection and that this SCoP was invalidated by
   // a pass that stated it would preserve the SCoPs. We disable this check as
   // the independent blocks pass may create memory references which seem to
   // alias, if -basicaa is not available. They actually do not, but as we can
   // not proof this without -basicaa we would fail. We disable this check to
   // not cause irrelevant verification failures.
   if (!AS.isMustAlias())
-    return invalid<ReportAlias>(Context, /*Assert=*/true, &AS);
+    return invalid<ReportAlias>(Context, /*Assert=*/true, &Inst, &AS);
 
   return true;
 }
 
 bool ScopDetection::isValidInstruction(Instruction &Inst,
                                        DetectionContext &Context) const {
   if (PHINode *PN = dyn_cast<PHINode>(&Inst))
     if (!canSynthesize(PN, LI, SE, &Context.CurRegion)) {
       if (SCEVCodegen)
         return invalid<ReportPhiNodeRefInRegion>(Context, /*Assert=*/true,
                                                  &Inst);
       else
         return invalid<ReportNonCanonicalPhiNode>(Context, /*Assert=*/true,
                                                   &Inst);
     }
 
   // We only check the call instruction but not invoke instruction.
   if (CallInst *CI = dyn_cast<CallInst>(&Inst)) {
     if (isValidCallInst(*CI))
       return true;
 
     return invalid<ReportFuncCall>(Context, /*Assert=*/true, &Inst);
   }
 
   if (!Inst.mayWriteToMemory() && !Inst.mayReadFromMemory()) {
     if (!isa<AllocaInst>(Inst))
       return true;
 
     return invalid<ReportAlloca>(Context, /*Assert=*/true, &Inst);
   }
 
   // Check the access function.
   if (isa<LoadInst>(Inst) || isa<StoreInst>(Inst))
     return isValidMemoryAccess(Inst, Context);
 
   // We do not know this instruction, therefore we assume it is invalid.
   return invalid<ReportUnknownInst>(Context, /*Assert=*/true, &Inst);
 }
 
 bool ScopDetection::isValidLoop(Loop *L, DetectionContext &Context) const {
   if (!SCEVCodegen) {
     // If code generation is not in scev based mode, we need to ensure that
     // each loop has a canonical induction variable.
     PHINode *IndVar = L->getCanonicalInductionVariable();
     if (!IndVar)
       return invalid<ReportLoopHeader>(Context, /*Assert=*/true, L);
   }
 
   // Is the loop count affine?
   const SCEV *LoopCount = SE->getBackedgeTakenCount(L);
   if (!isAffineExpr(&Context.CurRegion, LoopCount, *SE))
     return invalid<ReportLoopBound>(Context, /*Assert=*/true, L, LoopCount);
 
   return true;
 }
 
 Region *ScopDetection::expandRegion(Region &R) {
   // Initial no valid region was found (greater than R)
   Region *LastValidRegion = nullptr;
   Region *ExpandedRegion = R.getExpandedRegion();
 
   DEBUG(dbgs() << "\tExpanding " << R.getNameStr() << "\n");
 
   while (ExpandedRegion) {
     DetectionContext Context(*ExpandedRegion, *AA, false /* verifying */);
     DEBUG(dbgs() << "\t\tTrying " << ExpandedRegion->getNameStr() << "\n");
 
     // Check the exit first (cheap)
     if (isValidExit(Context)) {
       // If the exit is valid check all blocks
       //  - if true, a valid region was found => store it + keep expanding
       //  - if false, .tbd. => stop  (should this really end the loop?)
       if (!allBlocksValid(Context))
         break;
 
       // Delete unnecessary regions (allocated by getExpandedRegion)
       if (LastValidRegion)
         delete LastValidRegion;
 
       // Store this region, because it is the greatest valid (encountered so
       // far).
       LastValidRegion = ExpandedRegion;
 
       // Create and test the next greater region (if any)
       ExpandedRegion = ExpandedRegion->getExpandedRegion();
 
     } else {
       // Create and test the next greater region (if any)
       Region *TmpRegion = ExpandedRegion->getExpandedRegion();
 
       // Delete unnecessary regions (allocated by getExpandedRegion)
       delete ExpandedRegion;
 
       ExpandedRegion = TmpRegion;
     }
   }
 
   DEBUG({
     if (LastValidRegion)
       dbgs() << "\tto " << LastValidRegion->getNameStr() << "\n";
     else
       dbgs() << "\tExpanding " << R.getNameStr() << " failed\n";
   });
 
   return LastValidRegion;
 }
 static bool regionWithoutLoops(Region &R, LoopInfo *LI) {
   for (const BasicBlock *BB : R.blocks())
     if (R.contains(LI->getLoopFor(BB)))
       return false;
 
   return true;
 }
 
 // Remove all direct and indirect children of region R from the region set Regs,
 // but do not recurse further if the first child has been found.
 //
 // Return the number of regions erased from Regs.
 static unsigned eraseAllChildren(std::set<const Region *> &Regs,
                                  const Region &R) {
   unsigned Count = 0;
   for (auto &SubRegion : R) {
     if (Regs.find(SubRegion.get()) != Regs.end()) {
       ++Count;
       Regs.erase(SubRegion.get());
     } else {
       Count += eraseAllChildren(Regs, *SubRegion);
     }
   }
   return Count;
 }
 
 void ScopDetection::findScops(Region &R) {
   if (!DetectRegionsWithoutLoops && regionWithoutLoops(R, LI))
     return;
 
   bool IsValidRegion = isValidRegion(R);
   bool HasErrors = RejectLogs.count(&R) > 0;
 
   if (IsValidRegion && !HasErrors) {
     ++ValidRegion;
     ValidRegions.insert(&R);
     return;
   }
 
   for (auto &SubRegion : R)
     findScops(*SubRegion);
 
   // Do not expand when we had errors. Bad things may happen.
   if (IsValidRegion && HasErrors)
     return;
 
   // Try to expand regions.
   //
   // As the region tree normally only contains canonical regions, non canonical
   // regions that form a Scop are not found. Therefore, those non canonical
   // regions are checked by expanding the canonical ones.
 
   std::vector<Region *> ToExpand;
 
   for (auto &SubRegion : R)
     ToExpand.push_back(SubRegion.get());
 
   for (Region *CurrentRegion : ToExpand) {
     // Skip invalid regions. Regions may become invalid, if they are element of
     // an already expanded region.
     if (ValidRegions.find(CurrentRegion) == ValidRegions.end())
       continue;
 
     Region *ExpandedR = expandRegion(*CurrentRegion);
 
     if (!ExpandedR)
       continue;
 
     R.addSubRegion(ExpandedR, true);
     ValidRegions.insert(ExpandedR);
     ValidRegions.erase(CurrentRegion);
 
     // Erase all (direct and indirect) children of ExpandedR from the valid
     // regions and update the number of valid regions.
     ValidRegion -= eraseAllChildren(ValidRegions, *ExpandedR);
   }
 }
 
 bool ScopDetection::allBlocksValid(DetectionContext &Context) const {
   Region &R = Context.CurRegion;
 
   for (const BasicBlock *BB : R.blocks()) {
     Loop *L = LI->getLoopFor(BB);
     if (L && L->getHeader() == BB && (!isValidLoop(L, Context) && !KeepGoing))
       return false;
   }
 
   for (BasicBlock *BB : R.blocks())
     if (!isValidCFG(*BB, Context) && !KeepGoing)
       return false;
 
   for (BasicBlock *BB : R.blocks())
     for (BasicBlock::iterator I = BB->begin(), E = --BB->end(); I != E; ++I)
       if (!isValidInstruction(*I, Context) && !KeepGoing)
         return false;
 
   if (!hasAffineMemoryAccesses(Context))
     return false;
 
   return true;
 }
 
 bool ScopDetection::isValidExit(DetectionContext &Context) const {
   Region &R = Context.CurRegion;
 
   // PHI nodes are not allowed in the exit basic block.
   if (BasicBlock *Exit = R.getExit()) {
     BasicBlock::iterator I = Exit->begin();
     if (I != Exit->end() && isa<PHINode>(*I))
-      return invalid<ReportPHIinExit>(Context, /*Assert=*/true);
+      return invalid<ReportPHIinExit>(Context, /*Assert=*/true, I);
   }
 
   return true;
 }
 
 bool ScopDetection::isValidRegion(Region &R) const {
   DetectionContext Context(R, *AA, false /*verifying*/);
 
   bool RegionIsValid = isValidRegion(Context);
   bool HasErrors = !RegionIsValid || Context.Log.size() > 0;
 
   if (PollyTrackFailures && HasErrors) {
     // std::map::insert does not replace.
     std::pair<reject_iterator, bool> InsertedValue =
         RejectLogs.insert(std::make_pair(&R, Context.Log));
     assert(InsertedValue.second && "Two logs generated for the same Region.");
   }
 
   return RegionIsValid;
 }
 
 bool ScopDetection::isValidRegion(DetectionContext &Context) const {
   Region &R = Context.CurRegion;
 
   DEBUG(dbgs() << "Checking region: " << R.getNameStr() << "\n\t");
 
   if (R.isTopLevelRegion()) {
     DEBUG(dbgs() << "Top level region is invalid"; dbgs() << "\n");
     return false;
   }
 
   if (!R.getEntry()->getName().count(OnlyRegion)) {
     DEBUG({
       dbgs() << "Region entry does not match -polly-region-only";
       dbgs() << "\n";
     });
     return false;
   }
 
   if (!R.getEnteringBlock()) {
     BasicBlock *entry = R.getEntry();
     Loop *L = LI->getLoopFor(entry);
 
     if (L) {
       if (!L->isLoopSimplifyForm())
         return invalid<ReportSimpleLoop>(Context, /*Assert=*/true);
 
       for (pred_iterator PI = pred_begin(entry), PE = pred_end(entry); PI != PE;
            ++PI) {
         // Region entering edges come from the same loop but outside the region
         // are not allowed.
         if (L->contains(*PI) && !R.contains(*PI))
-          return invalid<ReportIndEdge>(Context, /*Assert=*/true);
+          return invalid<ReportIndEdge>(Context, /*Assert=*/true, *PI);
       }
     }
   }
 
   // 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<ReportEntry>(Context, /*Assert=*/true);
+    return invalid<ReportEntry>(Context, /*Assert=*/true, R.getEntry());
 
   if (!isValidExit(Context))
     return false;
 
   if (!allBlocksValid(Context))
     return false;
 
   DEBUG(dbgs() << "OK\n");
   return true;
 }
 
 bool ScopDetection::isValidFunction(llvm::Function &F) {
   return !InvalidFunctions.count(&F);
 }
 
 void ScopDetection::printLocations(llvm::Function &F) {
   for (const Region *R : *this) {
     unsigned LineEntry, LineExit;
     std::string FileName;
 
     getDebugLocation(R, LineEntry, LineExit, FileName);
     DiagnosticScopFound Diagnostic(F, FileName, LineEntry, LineExit);
     F.getContext().diagnose(Diagnostic);
   }
 }
 
+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 (Region::const_iterator ChildIt = R->begin(), End = R->end();
+       ChildIt != End; ++ChildIt) {
+    const std::unique_ptr<Region> &Child = *ChildIt;
+
+    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<LoopInfo>();
   RI = &getAnalysis<RegionInfo>();
   if (!DetectScopsWithoutLoops && LI->empty())
     return false;
 
   AA = &getAnalysis<AliasAnalysis>();
   SE = &getAnalysis<ScalarEvolution>();
   Region *TopRegion = RI->getTopLevelRegion();
 
   releaseMemory();
 
   if (OnlyFunction != "" && !F.getName().count(OnlyFunction))
     return false;
 
   if (!isValidFunction(F))
     return false;
 
   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);
 
   return false;
 }
 
 void polly::ScopDetection::verifyRegion(const Region &R) const {
   assert(isMaxRegionInScop(R) && "Expect R is a valid region.");
   DetectionContext Context(const_cast<Region &>(R), *AA, true /*verifying*/);
   isValidRegion(Context);
 }
 
 void polly::ScopDetection::verifyAnalysis() const {
   if (!VerifyScops)
     return;
 
   for (const Region *R : ValidRegions)
     verifyRegion(*R);
 }
 
 void ScopDetection::getAnalysisUsage(AnalysisUsage &AU) const {
   AU.addRequired<DominatorTreeWrapperPass>();
   AU.addRequired<PostDominatorTree>();
   AU.addRequired<LoopInfo>();
   AU.addRequired<ScalarEvolution>();
   // We also need AA and RegionInfo when we are verifying analysis.
   AU.addRequiredTransitive<AliasAnalysis>();
   AU.addRequiredTransitive<RegionInfo>();
   AU.setPreservesAll();
 }
 
 void ScopDetection::print(raw_ostream &OS, const Module *) const {
   for (const Region *R : ValidRegions)
     OS << "Valid Region for Scop: " << R->getNameStr() << '\n';
 
   OS << "\n";
 }
 
 void ScopDetection::releaseMemory() {
   ValidRegions.clear();
   RejectLogs.clear();
 
   // Do not clear the invalid function set.
 }
 
 char ScopDetection::ID = 0;
 
 Pass *polly::createScopDetectionPass() { return new ScopDetection(); }
 
 INITIALIZE_PASS_BEGIN(ScopDetection, "polly-detect",
                       "Polly - Detect static control parts (SCoPs)", false,
                       false);
 INITIALIZE_AG_DEPENDENCY(AliasAnalysis);
 INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass);
 INITIALIZE_PASS_DEPENDENCY(LoopInfo);
 INITIALIZE_PASS_DEPENDENCY(PostDominatorTree);
 INITIALIZE_PASS_DEPENDENCY(RegionInfo);
 INITIALIZE_PASS_DEPENDENCY(ScalarEvolution);
 INITIALIZE_PASS_END(ScopDetection, "polly-detect",
                     "Polly - Detect static control parts (SCoPs)", false, false)
diff --git a/lib/Analysis/ScopDetectionDiagnostic.cpp b/lib/Analysis/ScopDetectionDiagnostic.cpp
index 0fa7ba7..2467000 100644
--- a/lib/Analysis/ScopDetectionDiagnostic.cpp
+++ b/lib/Analysis/ScopDetectionDiagnostic.cpp
@@ -1,234 +1,450 @@
 //=== ScopDetectionDiagnostic.cpp - Error diagnostics --------- -*- C++ -*-===//
 //
 //                     The LLVM Compiler Infrastructure
 //
 // This file is distributed under the University of Illinois Open Source
 // License. See LICENSE.TXT for details.
 //
 //===----------------------------------------------------------------------===//
 //
 // Small set of diagnostic helper classes to encapsulate any errors occurred
 // during the detection of Scops.
 //
 // The ScopDetection defines a set of error classes (via Statistic variables)
 // that groups a number of individual errors into a group, e.g. non-affinity
 // related errors.
 // On error we generate an object that carries enough additional information
 // to diagnose the error and generate a helpful error message.
 //
 //===----------------------------------------------------------------------===//
 #include "polly/ScopDetectionDiagnostic.h"
 
 #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"
 
 #include <string>
 
 #define BADSCOP_STAT(NAME, DESC)                                               \
   STATISTIC(Bad##NAME##ForScop, "Number of bad regions for Scop: " DESC)
 
 BADSCOP_STAT(CFG, "CFG too complex");
 BADSCOP_STAT(IndVar, "Non canonical induction variable in loop");
 BADSCOP_STAT(IndEdge, "Found invalid region entering edges");
 BADSCOP_STAT(LoopBound, "Loop bounds can not be computed");
 BADSCOP_STAT(FuncCall, "Function call with side effects appeared");
 BADSCOP_STAT(AffFunc, "Expression not affine");
 BADSCOP_STAT(Alias, "Found base address alias");
 BADSCOP_STAT(SimpleLoop, "Loop not in -loop-simplify form");
 BADSCOP_STAT(Other, "Others");
 
 namespace polly {
 /// @brief Small string conversion via raw_string_stream.
 template <typename T> std::string operator+(Twine LHS, const T &RHS) {
   std::string Buf;
   raw_string_ostream fmt(Buf);
   fmt << RHS;
   fmt.flush();
 
   return LHS.concat(Buf).str();
 }
 
 void getDebugLocation(const Region *R, unsigned &LineBegin, unsigned &LineEnd,
                       std::string &FileName) {
   LineBegin = -1;
   LineEnd = 0;
 
   for (const BasicBlock *BB : R->blocks())
     for (const Instruction &Inst : *BB) {
       DebugLoc DL = Inst.getDebugLoc();
       if (DL.isUnknown())
         continue;
 
       DIScope Scope(DL.getScope(Inst.getContext()));
 
       if (FileName.empty())
         FileName = Scope.getFilename();
 
       unsigned NewLine = DL.getLine();
 
       LineBegin = std::min(LineBegin, NewLine);
       LineEnd = std::max(LineEnd, NewLine);
     }
 }
 
+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.
+
+static const llvm::DebugLoc Unknown = DebugLoc();
+
+const llvm::DebugLoc &RejectReason::getDebugLoc() const {
+  // Allocate an empty DebugLoc and return it a reference to it.
+  return Unknown;
+}
+
 //===----------------------------------------------------------------------===//
 // 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;
 }
 
 std::string ReportLoopBound::getMessage() const {
   return "Non affine loop bound '" + *LoopCount + "' in loop: " +
          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;
 }
 
 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;
   raw_string_ostream OS(Message);
 
   OS << "Possible aliasing: ";
 
   std::vector<Value *> Pointers;
 
   for (const auto &I : AS)
     Pointers.push_back(I.getValue());
 
   std::sort(Pointers.begin(), Pointers.end());
 
   for (std::vector<Value *>::iterator PI = Pointers.begin(),
                                       PE = Pointers.end();
        ;) {
     Value *V = *PI;
 
     if (V->getName().size() == 0)
       OS << "\"" << *V << "\"";
     else
       OS << "\"" << V->getName() << "\"";
 
     ++PI;
 
     if (PI != PE)
       OS << ", ";
     else
       break;
   }
 
   return OS.str();
 }
 
 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/test/ScopDetectionDiagnostics/ReportFuncCall-01.ll b/test/ScopDetectionDiagnostics/ReportFuncCall-01.ll
new file mode 100644
index 0000000..045335a
--- /dev/null
+++ b/test/ScopDetectionDiagnostics/ReportFuncCall-01.ll
@@ -0,0 +1,67 @@
+; RUN: opt %loadPolly -pass-remarks="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<n; ++i) {
+;     A[i] = invalidCall(A);
+;   }
+; }
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define void @a(double* %A, i32 %n) #0 {
+entry:
+  %cmp1 = icmp sgt i32 %n, 0, !dbg !10
+  br i1 %cmp1, label %for.body.lr.ph, label %for.end, !dbg !10
+
+for.body.lr.ph:                                   ; preds = %entry
+  %0 = zext i32 %n to i64
+  br label %for.body, !dbg !10
+
+for.body:                                         ; preds = %for.body, %for.body.lr.ph
+  %indvar = phi i64 [ 0, %for.body.lr.ph ], [ %indvar.next, %for.body ]
+  %arrayidx = getelementptr double* %A, i64 %indvar, !dbg !12
+  %call = tail call double @invalidCall(double* %A) #2, !dbg !12
+  store double %call, double* %arrayidx, align 8, !dbg !12, !tbaa !14
+  %indvar.next = add i64 %indvar, 1, !dbg !10
+  %exitcond = icmp eq i64 %indvar.next, %0, !dbg !10
+  br i1 %exitcond, label %for.end.loopexit, label %for.body, !dbg !10
+
+for.end.loopexit:                                 ; preds = %for.body
+  br label %for.end
+
+for.end:                                          ; preds = %for.end.loopexit, %entry
+  ret void, !dbg !18
+}
+
+declare double @invalidCall(double*) #1
+
+; CHECK: remark: ReportFuncCall.c:4:8: The following errors keep this region from being a Scop.
+; CHECK: remark: ReportFuncCall.c:5:12: This function call cannot be handeled. Try to inline it.
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!7, !8}
+!llvm.ident = !{!9}
+
+!0 = metadata !{i32 786449, metadata !1, i32 12, metadata !"clang version 3.5.0 ", i1 true, metadata !"", i32 0, metadata !2, metadata !2, metadata !3, metadata !2, metadata !2, metadata !"", i32 2} ; [ DW_TAG_compile_unit ] [test/ScopDetectionDiagnostics/ReportFuncCall.c] [DW_LANG_C99]
+!1 = metadata !{metadata !"ReportFuncCall.c", metadata !"test/ScopDetectionDiagnostics"}
+!2 = metadata !{}
+!3 = metadata !{metadata !4}
+!4 = metadata !{i32 786478, metadata !1, metadata !5, metadata !"a", metadata !"a", metadata !"", i32 3, metadata !6, i1 false, i1 true, i32 0, i32 0, null, i32 256, i1 true, void (double*, i32)* @a, null, null, metadata !2, i32 3} ; [ DW_TAG_subprogram ] [line 3] [def] [a]
+!5 = metadata !{i32 786473, metadata !1}          ; [ DW_TAG_file_type ] [test/ScopDetectionDiagnostics/ReportFuncCall.c]
+!6 = metadata !{i32 786453, i32 0, null, metadata !"", i32 0, i64 0, i64 0, i64 0, i32 0, null, metadata !2, i32 0, null, null, null} ; [ DW_TAG_subroutine_type ] [line 0, size 0, align 0, offset 0] [from ]
+!7 = metadata !{i32 2, metadata !"Dwarf Version", i32 4}
+!8 = metadata !{i32 2, metadata !"Debug Info Version", i32 1}
+!9 = metadata !{metadata !"clang version 3.5.0 "}
+!10 = metadata !{i32 4, i32 8, metadata !11, null}
+!11 = metadata !{i32 786443, metadata !1, metadata !4, i32 4, i32 3, i32 0, i32 0} ; [ DW_TAG_lexical_block ] [test/ScopDetectionDiagnostics/ReportFuncCall.c]
+!12 = metadata !{i32 5, i32 12, metadata !13, null}
+!13 = metadata !{i32 786443, metadata !1, metadata !11, i32 4, i32 27, i32 0, i32 1} ; [ DW_TAG_lexical_block ] [test/ScopDetectionDiagnostics/ReportFuncCall.c]
+!14 = metadata !{metadata !15, metadata !15, i64 0}
+!15 = metadata !{metadata !"double", metadata !16, i64 0}
+!16 = metadata !{metadata !"omnipotent char", metadata !17, i64 0}
+!17 = metadata !{metadata !"Simple C/C++ TBAA"}
+!18 = metadata !{i32 7, i32 1, metadata !4, null}
-- 
2.0.0




More information about the llvm-commits mailing list