Replace INVALID/INVALID_NOVERIFY with diagnostics.
authorAndreas Simbuerger <simbuerg@fim.uni-passau.de>
Wed, 2 Apr 2014 11:54:01 +0000 (11:54 +0000)
committerAndreas Simbuerger <simbuerg@fim.uni-passau.de>
Wed, 2 Apr 2014 11:54:01 +0000 (11:54 +0000)
This replaces the ancient INVALID/INVALID_NOVERIFY macros with a real
function.

The new invalid(..) function uses small diagnostic objects that are
generated on demand. We can store arbitrary additional information per
error type and generate useful debug/error messages on the fly.

Use it as follows:
  if (/* Some error condition (ReportFoo) */)
    invalid<ReportFoo>(Context, /*Assert=*/true/false,
      (/* List of helpful diagnostic objects */));

Where ReportFoo is a subclass of RejectReason that is able to take the
list of helpful diagnostic objects in its constructor.
The implementation of invalid will create the report and fire
an assertion, if necessary.

llvm-svn: 205414

polly/include/polly/ScopDetection.h
polly/include/polly/ScopDetectionDiagnostic.h [new file with mode: 0644]
polly/lib/Analysis/ScopDetection.cpp

index 8e41119..defc2f1 100644 (file)
@@ -154,13 +154,6 @@ class ScopDetection : public FunctionPass {
   /// @return True if the call instruction is valid, false otherwise.
   static bool isValidCallInst(CallInst &CI);
 
-  /// @brief Format the invalid alias message.
-  ///
-  /// @param AS The alias set.
-  ///
-  /// @return The failure message why the alias is invalid.
-  std::string formatInvalidAlias(AliasSet &AS) const;
-
   /// @brief Check if a value is invariant in the region Reg.
   ///
   /// @param Val Value to check for invariance.
@@ -233,6 +226,15 @@ class ScopDetection : public FunctionPass {
   /// @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) {}
diff --git a/polly/include/polly/ScopDetectionDiagnostic.h b/polly/include/polly/ScopDetectionDiagnostic.h
new file mode 100644 (file)
index 0000000..4900b78
--- /dev/null
@@ -0,0 +1,562 @@
+//=== 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/Statistic.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/Support/raw_ostream.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();
+}
+
+//===----------------------------------------------------------------------===//
+/// @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 {
+  //===--------------------------------------------------------------------===//
+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 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() { ++BadCFGForScop; }
+};
+
+class ReportNonBranchTerminator : public ReportCFG {
+  BasicBlock *BB;
+
+public:
+  ReportNonBranchTerminator(BasicBlock *BB) : BB(BB) {};
+
+  /// @name RejectReason interface
+  //@{
+  virtual std::string getMessage() const {
+    return ("Non branch instruction terminates BB: " + BB->getName()).str();
+  }
+  //@}
+};
+
+//===----------------------------------------------------------------------===//
+/// @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) {};
+
+  /// @name RejectReason interface
+  //@{
+  virtual std::string getMessage() const {
+    return ("Not well structured condition at BB: " + BB->getName()).str();
+  }
+  //@}
+};
+
+//===----------------------------------------------------------------------===//
+/// @brief Base class for non-affine reject reasons.
+///
+/// Scop candidates that violate restrictions to affinity are reported under
+/// this class.
+class ReportAffFunc : public RejectReason {
+  //===--------------------------------------------------------------------===//
+public:
+  ReportAffFunc() { ++BadAffFuncForScop; }
+};
+
+//===----------------------------------------------------------------------===//
+/// @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) {};
+
+  /// @name RejectReason interface
+  //@{
+  virtual std::string getMessage() const {
+    return ("Condition based on 'undef' value in BB: " + BB->getName()).str();
+  }
+  //@}
+};
+
+//===----------------------------------------------------------------------===//
+/// @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) {};
+
+  /// @name RejectReason interface
+  //@{
+  virtual std::string getMessage() const {
+    return ("Condition in BB '" + BB->getName()).str() +
+           "' neither constant nor an icmp instruction";
+  }
+  //@}
+};
+
+//===----------------------------------------------------------------------===//
+/// @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) {};
+
+  /// @name RejectReason interface
+  //@{
+  virtual std::string getMessage() const {
+    return ("undef operand in branch at BB: " + BB->getName()).str();
+  }
+  //@}
+};
+
+//===----------------------------------------------------------------------===//
+/// @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) {};
+
+  /// @name RejectReason interface
+  //@{
+  virtual std::string getMessage() const {
+    return ("Non affine branch in BB '" + BB->getName()).str() +
+           "' with LHS: " + *LHS + " and RHS: " + *RHS;
+  }
+  //@}
+};
+
+//===----------------------------------------------------------------------===//
+/// @brief Captures a missing base pointer.
+class ReportNoBasePtr : public ReportAffFunc {
+  //===--------------------------------------------------------------------===//
+public:
+  /// @name RejectReason interface
+  //@{
+  virtual std::string getMessage() const { return "No base pointer"; }
+  //@}
+};
+
+//===----------------------------------------------------------------------===//
+/// @brief Captures an undefined base pointer.
+class ReportUndefBasePtr : public ReportAffFunc {
+  //===--------------------------------------------------------------------===//
+public:
+  /// @name RejectReason interface
+  //@{
+  virtual std::string getMessage() const { return "Undefined base pointer"; }
+  //@}
+};
+
+//===----------------------------------------------------------------------===//
+/// @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) {};
+
+  /// @name RejectReason interface
+  //@{
+  virtual std::string getMessage() const {
+    return "Base address not invariant in current region:" + *BaseValue;
+  }
+  //@}
+};
+
+//===----------------------------------------------------------------------===//
+/// @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) {};
+
+  /// @name RejectReason interface
+  //@{
+  virtual std::string getMessage() const {
+    return "Non affine access function: " + *AccessFunction;
+  }
+  //@}
+};
+
+//===----------------------------------------------------------------------===//
+/// @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() { ++BadIndVarForScop; }
+};
+
+//===----------------------------------------------------------------------===//
+/// @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) {};
+
+  /// @name RejectReason interface
+  //@{
+  virtual std::string getMessage() const {
+    return "SCEV of PHI node refers to SSA names in region: " + *Inst;
+  }
+  //@}
+};
+
+//===----------------------------------------------------------------------===//
+/// @brief Captures a non canonical phi node.
+class ReportNonCanonicalPhiNode : public ReportIndVar {
+  //===--------------------------------------------------------------------===//
+
+  // The offending instruction.
+  Instruction *Inst;
+
+public:
+  ReportNonCanonicalPhiNode(Instruction *Inst) : Inst(Inst) {};
+
+  /// @name RejectReason interface
+  //@{
+  virtual std::string getMessage() const {
+    return "Non canonical PHI node: " + *Inst;
+  }
+  //@}
+};
+
+//===----------------------------------------------------------------------===//
+/// @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) {};
+
+  /// @name RejectReason interface
+  //@{
+  virtual std::string getMessage() const {
+    return ("No canonical IV at loop header: " + L->getHeader()->getName())
+        .str();
+  }
+  //@}
+};
+
+//===----------------------------------------------------------------------===//
+/// @brief Captures a region with invalid entering edges.
+class ReportIndEdge : public RejectReason {
+  //===--------------------------------------------------------------------===//
+public:
+  ReportIndEdge() { ++BadIndEdgeForScop; }
+
+  /// @name RejectReason interface
+  //@{
+  virtual std::string getMessage() const {
+    return "Region has invalid entering edges!";
+  }
+};
+
+//===----------------------------------------------------------------------===//
+/// @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) : L(L), LoopCount(LoopCount) {
+    ++BadLoopBoundForScop;
+  };
+
+  /// @name RejectReason interface
+  //@{
+  virtual std::string getMessage() const {
+    return "Non affine loop bound '" + *LoopCount + "' in loop: " +
+           L->getHeader()->getName();
+  }
+  //@}
+};
+
+//===----------------------------------------------------------------------===//
+/// @brief Captures errors with non-side-effect-known function calls.
+class ReportFuncCall : public RejectReason {
+  //===--------------------------------------------------------------------===//
+
+  // The offending call instruction.
+  Instruction *Inst;
+
+public:
+  ReportFuncCall(Instruction *Inst) : Inst(Inst) {
+    ++BadFuncCallForScop;
+  };
+
+  /// @name RejectReason interface
+  //@{
+  std::string getMessage() const { return "Call instruction: " + *Inst; }
+  //@}
+};
+
+//===----------------------------------------------------------------------===//
+/// @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 {
+    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();
+  }
+
+public:
+  ReportAlias(AliasSet *AS) : AS(AS) { ++BadAliasForScop; }
+
+  /// @name RejectReason interface
+  //@{
+  std::string getMessage() const { return formatInvalidAlias(*AS); }
+  //@}
+};
+
+//===----------------------------------------------------------------------===//
+/// @brief Captures errors with non simplified loops.
+class ReportSimpleLoop : public RejectReason {
+  //===--------------------------------------------------------------------===//
+public:
+  ReportSimpleLoop() { ++BadSimpleLoopForScop; }
+
+  /// @name RejectReason interface
+  //@{
+  std::string getMessage() const {
+    return "Loop not in simplify form is invalid!";
+  }
+  //@}
+};
+
+//===----------------------------------------------------------------------===//
+/// @brief Base class for otherwise ungrouped reject reasons.
+class ReportOther : public RejectReason {
+  //===--------------------------------------------------------------------===//
+public:
+  ReportOther() { ++BadOtherForScop; }
+
+  /// @name RejectReason interface
+  //@{
+  std::string getMessage() const { return "Unknown reject reason"; }
+  //@}
+};
+
+//===----------------------------------------------------------------------===//
+/// @brief Captures errors with bad IntToPtr instructions.
+class ReportIntToPtr : public ReportOther {
+  //===--------------------------------------------------------------------===//
+
+  // The offending base value.
+  Value *BaseValue;
+
+public:
+  ReportIntToPtr(Value *BaseValue) : BaseValue(BaseValue) {};
+
+  /// @name RejectReason interface
+  //@{
+  std::string getMessage() const {
+    return "Find bad intToptr prt: " + *BaseValue;
+  }
+  //@}
+};
+
+//===----------------------------------------------------------------------===//
+/// @brief Captures errors with alloca instructions.
+class ReportAlloca : public ReportOther {
+  //===--------------------------------------------------------------------===//
+  Instruction *Inst;
+
+public:
+  ReportAlloca(Instruction *Inst) : Inst(Inst) {};
+
+  /// @name RejectReason interface
+  //@{
+  std::string getMessage() const { return "Alloca instruction: " + *Inst; }
+  //@}
+};
+
+//===----------------------------------------------------------------------===//
+/// @brief Captures errors with unknown instructions.
+class ReportUnknownInst : public ReportOther {
+  //===--------------------------------------------------------------------===//
+  Instruction *Inst;
+
+public:
+  ReportUnknownInst(Instruction *Inst) : Inst(Inst) {};
+
+  /// @name RejectReason interface
+  //@{
+  std::string getMessage() const { return "Unknown instruction: " + *Inst; }
+  //@}
+};
+
+//===----------------------------------------------------------------------===//
+/// @brief Captures errors with phi nodes in exit BBs.
+class ReportPHIinExit : public ReportOther {
+  //===--------------------------------------------------------------------===//
+public:
+  /// @name RejectReason interface
+  //@{
+  std::string getMessage() const { return "PHI node in exit BB"; }
+  //@}
+};
+
+//===----------------------------------------------------------------------===//
+/// @brief Captures errors with regions containing the function entry block.
+class ReportEntry : public ReportOther {
+  //===--------------------------------------------------------------------===//
+public:
+  /// @name RejectReason interface
+  //@{
+  std::string getMessage() const {
+    return "Region containing entry block of function is invalid!";
+  }
+  //@}
+};
+
+} // namespace polly
+
+#endif // POLLY_SCOP_DETECTION_DIAGNOSTIC_H
index 912b395..dfc9362 100644 (file)
@@ -47,6 +47,7 @@
 #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"
@@ -129,51 +130,6 @@ bool polly::PollyTrackFailures = false;
 
 STATISTIC(ValidRegion, "Number of regions that a valid part of Scop");
 
-#define BADSCOP_STAT(NAME, DESC)                                               \
-  STATISTIC(Bad##NAME##ForScop, "Number of bad regions for Scop: " DESC)
-
-#define INVALID(NAME, MESSAGE)                                                 \
-  do {                                                                         \
-    if (PollyTrackFailures) {                                                  \
-      std::string Buf;                                                         \
-      raw_string_ostream fmt(Buf);                                             \
-      fmt << MESSAGE;                                                          \
-      fmt.flush();                                                             \
-      LastFailure = Buf;                                                       \
-    }                                                                          \
-    DEBUG(dbgs() << MESSAGE);                                                  \
-    DEBUG(dbgs() << "\n");                                                     \
-    assert(!Context.Verifying && #NAME);                                       \
-    if (!Context.Verifying)                                                    \
-      ++Bad##NAME##ForScop;                                                    \
-  } while (0)
-
-#define INVALID_NOVERIFY(NAME, MESSAGE)                                        \
-  do {                                                                         \
-    if (PollyTrackFailures) {                                                  \
-      std::string Buf;                                                         \
-      raw_string_ostream fmt(Buf);                                             \
-      fmt << MESSAGE;                                                          \
-      fmt.flush();                                                             \
-      LastFailure = Buf;                                                       \
-    }                                                                          \
-    DEBUG(dbgs() << MESSAGE);                                                  \
-    DEBUG(dbgs() << "\n");                                                     \
-    /* DISABLED: assert(!Context.Verifying && #NAME); */                       \
-    if (!Context.Verifying)                                                    \
-      ++Bad##NAME##ForScop;                                                    \
-  } while (0)
-
-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");
-
 class DiagnosticScopFound : public DiagnosticInfo {
 private:
   static int PluginDiagnosticKind;
@@ -213,6 +169,25 @@ void DiagnosticScopFound::print(DiagnosticPrinter &DP) const {
 
 //===----------------------------------------------------------------------===//
 // ScopDetection.
+
+template <class RR, typename... Args>
+inline bool ScopDetection::invalid(DetectionContext &Context, bool Assert,
+                                   Args &&... Arguments) const {
+
+  if (!Context.Verifying) {
+    RR RejectReason = RR(Arguments...);
+    if (PollyTrackFailures)
+      LastFailure = RejectReason.getMessage();
+
+    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;
@@ -241,10 +216,8 @@ bool ScopDetection::isValidCFG(BasicBlock &BB,
 
   BranchInst *Br = dyn_cast<BranchInst>(TI);
 
-  if (!Br) {
-    INVALID(CFG, "Non branch instruction terminates BB: " + BB.getName());
-    return false;
-  }
+  if (!Br)
+    return invalid<ReportNonBranchTerminator>(Context, /*Assert=*/true, &BB);
 
   if (Br->isUnconditional())
     return true;
@@ -252,17 +225,12 @@ bool ScopDetection::isValidCFG(BasicBlock &BB,
   Value *Condition = Br->getCondition();
 
   // UndefValue is not allowed as condition.
-  if (isa<UndefValue>(Condition)) {
-    INVALID(AffFunc, "Condition based on 'undef' value in BB: " + BB.getName());
-    return false;
-  }
+  if (isa<UndefValue>(Condition))
+    return invalid<ReportUndefCond>(Context, /*Assert=*/true, &BB);
 
   // Only Constant and ICmpInst are allowed as condition.
-  if (!(isa<Constant>(Condition) || isa<ICmpInst>(Condition))) {
-    INVALID(AffFunc, "Condition in BB '" + BB.getName() +
-                         "' neither constant nor an icmp instruction");
-    return false;
-  }
+  if (!(isa<Constant>(Condition) || isa<ICmpInst>(Condition)))
+    return invalid<ReportInvalidCond>(Context, /*Assert=*/true, &BB);
 
   // Allow perfectly nested conditions.
   assert(Br->getNumSuccessors() == 2 && "Unexpected number of successors");
@@ -278,22 +246,17 @@ bool ScopDetection::isValidCFG(BasicBlock &BB,
 
     // Are both operands of the ICmp affine?
     if (isa<UndefValue>(ICmp->getOperand(0)) ||
-        isa<UndefValue>(ICmp->getOperand(1))) {
-      INVALID(AffFunc, "undef operand in branch at BB: " + BB.getName());
-      return false;
-    }
+        isa<UndefValue>(ICmp->getOperand(1)))
+      return invalid<ReportUndefOperand>(Context, /*Assert=*/true, &BB);
 
     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)) {
-      INVALID(AffFunc, "Non affine branch in BB '" << BB.getName()
-                                                   << "' with LHS: " << *LHS
-                                                   << " and RHS: " << *RHS);
-      return false;
-    }
+        !isAffineExpr(&Context.CurRegion, RHS, *SE))
+      return invalid<ReportNonAffBranch>(Context, /*Assert=*/true, &BB, LHS,
+                                         RHS);
   }
 
   // Allow loop exit conditions.
@@ -303,10 +266,8 @@ bool ScopDetection::isValidCFG(BasicBlock &BB,
 
   // Allow perfectly nested conditions.
   Region *R = RI->getRegionFor(&BB);
-  if (R->getEntry() != &BB) {
-    INVALID(CFG, "Not well structured condition at BB: " + BB.getName());
-    return false;
-  }
+  if (R->getEntry() != &BB)
+    return invalid<ReportCondition>(Context, /*Assert=*/true, &BB);
 
   return true;
 }
@@ -328,40 +289,6 @@ bool ScopDetection::isValidCallInst(CallInst &CI) {
   return false;
 }
 
-std::string ScopDetection::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();
-}
-
 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))
@@ -413,43 +340,33 @@ bool ScopDetection::isValidMemoryAccess(Instruction &Inst,
 
   BasePointer = dyn_cast<SCEVUnknown>(SE->getPointerBase(AccessFunction));
 
-  if (!BasePointer) {
-    INVALID(AffFunc, "No base pointer");
-    return false;
-  }
+  if (!BasePointer)
+    return invalid<ReportNoBasePtr>(Context, /*Assert=*/true);
 
   BaseValue = BasePointer->getValue();
 
-  if (isa<UndefValue>(BaseValue)) {
-    INVALID(AffFunc, "Undefined base pointer");
-    return false;
-  }
+  if (isa<UndefValue>(BaseValue))
+    return invalid<ReportUndefBasePtr>(Context, /*Assert=*/true);
 
   // Check that the base address of the access is invariant in the current
   // region.
-  if (!isInvariant(*BaseValue, Context.CurRegion)) {
+  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.
-    INVALID_NOVERIFY(
-        AffFunc, "Base address not invariant in current region:" << *BaseValue);
-    return false;
-  }
+    return invalid<ReportVariantBasePtr>(Context, /*Assert=*/false, BaseValue);
 
   AccessFunction = SE->getMinusSCEV(AccessFunction, BasePointer);
 
   if (!AllowNonAffine &&
-      !isAffineExpr(&Context.CurRegion, AccessFunction, *SE, BaseValue)) {
-    INVALID(AffFunc, "Non affine access function: " << *AccessFunction);
-    return false;
-  }
+      !isAffineExpr(&Context.CurRegion, AccessFunction, *SE, BaseValue))
+    return invalid<ReportNonAffineAccess>(Context, /*Assert=*/true,
+                                          AccessFunction);
 
   // FIXME: Alias Analysis thinks IntToPtrInst aliases with alloca instructions
   // created by IndependentBlocks Pass.
-  if (isa<IntToPtrInst>(BaseValue)) {
-    INVALID(Other, "Find bad intToptr prt: " << *BaseValue);
-    return false;
-  }
+  if (isa<IntToPtrInst>(BaseValue))
+    return invalid<ReportIntToPtr>(Context, /*Assert=*/true, BaseValue);
 
   if (IgnoreAliasing)
     return true;
@@ -467,10 +384,8 @@ bool ScopDetection::isValidMemoryAccess(Instruction &Inst,
   // 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()) {
-    INVALID_NOVERIFY(Alias, formatInvalidAlias(AS));
-    return false;
-  }
+  if (!AS.isMustAlias())
+    return invalid<ReportAlias>(Context, /*Assert=*/true, &AS);
 
   return true;
 }
@@ -479,15 +394,12 @@ bool ScopDetection::isValidInstruction(Instruction &Inst,
                                        DetectionContext &Context) const {
   if (PHINode *PN = dyn_cast<PHINode>(&Inst))
     if (!canSynthesize(PN, LI, SE, &Context.CurRegion)) {
-      if (SCEVCodegen) {
-        INVALID(IndVar,
-                "SCEV of PHI node refers to SSA names in region: " << Inst);
-        return false;
-
-      } else {
-        INVALID(IndVar, "Non canonical PHI node: " << Inst);
-        return false;
-      }
+      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.
@@ -495,16 +407,14 @@ bool ScopDetection::isValidInstruction(Instruction &Inst,
     if (isValidCallInst(*CI))
       return true;
 
-    INVALID(FuncCall, "Call instruction: " << Inst);
-    return false;
+    return invalid<ReportFuncCall>(Context, /*Assert=*/true, &Inst);
   }
 
   if (!Inst.mayWriteToMemory() && !Inst.mayReadFromMemory()) {
     if (!isa<AllocaInst>(Inst))
       return true;
 
-    INVALID(Other, "Alloca instruction: " << Inst);
-    return false;
+    return invalid<ReportAlloca>(Context, /*Assert=*/true, &Inst);
   }
 
   // Check the access function.
@@ -512,8 +422,7 @@ bool ScopDetection::isValidInstruction(Instruction &Inst,
     return isValidMemoryAccess(Inst, Context);
 
   // We do not know this instruction, therefore we assume it is invalid.
-  INVALID(Other, "Unknown instruction: " << Inst);
-  return false;
+  return invalid<ReportUnknownInst>(Context, /*Assert=*/true, &Inst);
 }
 
 bool ScopDetection::isValidLoop(Loop *L, DetectionContext &Context) const {
@@ -521,20 +430,14 @@ bool ScopDetection::isValidLoop(Loop *L, DetectionContext &Context) const {
     // 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) {
-      INVALID(IndVar,
-              "No canonical IV at loop header: " << L->getHeader()->getName());
-      return false;
-    }
+    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)) {
-    INVALID(LoopBound, "Non affine loop bound '" << *LoopCount << "' in loop: "
-                                                 << L->getHeader()->getName());
-    return false;
-  }
+  if (!isAffineExpr(&Context.CurRegion, LoopCount, *SE))
+    return invalid<ReportLoopBound>(Context, /*Assert=*/true, L, LoopCount);
 
   return true;
 }
@@ -691,10 +594,8 @@ bool ScopDetection::isValidExit(DetectionContext &Context) const {
   // 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)) {
-      INVALID(Other, "PHI node in exit BB");
-      return false;
-    }
+    if (I != Exit->end() && isa<PHINode>(*I))
+      return invalid<ReportPHIinExit>(Context, /*Assert=*/true);
   }
 
   return true;
@@ -728,29 +629,23 @@ bool ScopDetection::isValidRegion(DetectionContext &Context) const {
     Loop *L = LI->getLoopFor(entry);
 
     if (L) {
-      if (!L->isLoopSimplifyForm()) {
-        INVALID(SimpleLoop, "Loop not in simplify form is invalid!");
-        return false;
-      }
+      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)) {
-          INVALID(IndEdge, "Region has invalid entering edges!");
-          return false;
-        }
+        if (L->contains(*PI) && !R.contains(*PI))
+          return invalid<ReportIndEdge>(Context, /*Assert=*/true);
       }
     }
   }
 
   // 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())) {
-    INVALID(Other, "Region containing entry block of function is invalid!");
-    return false;
-  }
+  if (R.getEntry() == &(R.getEntry()->getParent()->getEntryBlock()))
+    return invalid<ReportEntry>(Context, /*Assert=*/true);
 
   if (!isValidExit(Context))
     return false;