Add support for a verifier to the driver. Currently only verifies debug
output on darwin so is hard coded there.

As a note this will need a little bit of refactoring in the class
hierarchy to separate it out for different verifiers based on input type.

Fixes rdar://8256258.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@138343 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/Driver/Action.h b/include/clang/Driver/Action.h
index f51d8d9..a33c33b 100644
--- a/include/clang/Driver/Action.h
+++ b/include/clang/Driver/Action.h
@@ -44,9 +44,10 @@
     LinkJobClass,
     LipoJobClass,
     DsymutilJobClass,
+    VerifyJobClass,
 
     JobClassFirst=PreprocessJobClass,
-    JobClassLast=DsymutilJobClass
+    JobClassLast=VerifyJobClass
   };
 
   static const char *getClassName(ActionClass AC);
@@ -214,6 +215,15 @@
   static bool classof(const DsymutilJobAction *) { return true; }
 };
 
+class VerifyJobAction : public JobAction {
+public:
+  VerifyJobAction(ActionList &Inputs, types::ID Type);
+  static bool classof(const Action *A) {
+    return A->getKind() == VerifyJobClass;
+  }
+  static bool classof(const VerifyJobAction *) { return true; }
+};
+
 } // end namespace driver
 } // end namespace clang
 
diff --git a/include/clang/Driver/Options.td b/include/clang/Driver/Options.td
index 5294fe0..f97afb8 100644
--- a/include/clang/Driver/Options.td
+++ b/include/clang/Driver/Options.td
@@ -693,6 +693,8 @@
 def use_gold_plugin : Flag<"-use-gold-plugin">;
 def v : Flag<"-v">,
   HelpText<"Show commands to run and use verbose output">;
+def verify : Flag<"-verify">, Flags<[DriverOption]>,
+  HelpText<"Verify output using a verifier.">;
 def weak_l : Joined<"-weak-l">, Flags<[LinkerInput]>;
 def weak__framework : Separate<"-weak_framework">, Flags<[LinkerInput]>;
 def weak__library : Separate<"-weak_library">, Flags<[LinkerInput]>;
diff --git a/lib/Driver/Action.cpp b/lib/Driver/Action.cpp
index 549ce0a..ac95446 100644
--- a/lib/Driver/Action.cpp
+++ b/lib/Driver/Action.cpp
@@ -31,6 +31,7 @@
   case LinkJobClass: return "linker";
   case LipoJobClass: return "lipo";
   case DsymutilJobClass: return "dsymutil";
+  case VerifyJobClass: return "verify";
   }
 
   assert(0 && "invalid class");
@@ -84,3 +85,7 @@
 DsymutilJobAction::DsymutilJobAction(ActionList &Inputs, types::ID Type)
   : JobAction(DsymutilJobClass, Inputs, Type) {
 }
+
+VerifyJobAction::VerifyJobAction(ActionList &Inputs, types::ID Type)
+  : JobAction(VerifyJobClass, Inputs, Type) {
+}
diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp
index fee601d..12ad1b7 100644
--- a/lib/Driver/Driver.cpp
+++ b/lib/Driver/Driver.cpp
@@ -829,6 +829,19 @@
         Actions.pop_back();
 
         Actions.push_back(new DsymutilJobAction(Inputs, types::TY_dSYM));
+
+	// Verify the debug output if we're in assert mode.
+	// TODO: The verifier is noisy by default so put this under an
+	// option for now.
+	#ifndef NDEBUG
+	if (Args.hasArg(options::OPT_verify)) {
+	  ActionList VerifyInputs;
+	  VerifyInputs.push_back(Actions.back());
+	  Actions.pop_back();
+	  Actions.push_back(new VerifyJobAction(VerifyInputs,
+						types::TY_Nothing));
+	}
+        #endif
       }
     }
   }
@@ -1297,6 +1310,11 @@
     if (AtTopLevel && isa<DsymutilJobAction>(A))
       SubJobAtTopLevel = true;
 
+    // Also treat verify sub-jobs as being at the top-level. They don't
+    // produce any output and so don't need temporary output names.
+    if (AtTopLevel && isa<VerifyJobAction>(A))
+      SubJobAtTopLevel = true;
+
     InputInfo II;
     BuildJobsForAction(C, *it, TC, BoundArch,
                        SubJobAtTopLevel, LinkingOutput, II);
@@ -1340,7 +1358,8 @@
                                        bool AtTopLevel) const {
   llvm::PrettyStackTraceString CrashInfo("Computing output path");
   // Output to a user requested destination?
-  if (AtTopLevel && !isa<DsymutilJobAction>(JA)) {
+  if (AtTopLevel && !isa<DsymutilJobAction>(JA) &&
+      !isa<VerifyJobAction>(JA)) {
     if (Arg *FinalOutput = C.getArgs().getLastArg(options::OPT_o))
       return C.addResultFile(FinalOutput->getValue(C.getArgs()));
   }
@@ -1361,7 +1380,7 @@
   StringRef BaseName;
 
   // Dsymutil actions should use the full path.
-  if (isa<DsymutilJobAction>(JA))
+  if (isa<DsymutilJobAction>(JA) || isa<VerifyJobAction>(JA))
     BaseName = BasePath;
   else
     BaseName = llvm::sys::path::filename(BasePath);
diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp
index 821b07b..079de9a 100644
--- a/lib/Driver/ToolChains.cpp
+++ b/lib/Driver/ToolChains.cpp
@@ -255,6 +255,8 @@
       T = new tools::darwin::Lipo(*this); break;
     case Action::DsymutilJobClass:
       T = new tools::darwin::Dsymutil(*this); break;
+    case Action::VerifyJobClass:
+      T = new tools::darwin::VerifyDebug(*this); break;
     }
   }
 
@@ -362,8 +364,8 @@
 
 void DarwinClang::AddLinkARCArgs(const ArgList &Args,
                                  ArgStringList &CmdArgs) const {
-  
-  CmdArgs.push_back("-force_load");    
+
+  CmdArgs.push_back("-force_load");
   llvm::sys::Path P(getDriver().ClangExecutable);
   P.eraseComponent(); // 'clang'
   P.eraseComponent(); // 'bin'
@@ -385,13 +387,13 @@
 }
 
 void DarwinClang::AddLinkRuntimeLib(const ArgList &Args,
-                                    ArgStringList &CmdArgs, 
+                                    ArgStringList &CmdArgs,
                                     const char *DarwinStaticLib) const {
   llvm::sys::Path P(getDriver().ResourceDir);
   P.appendComponent("lib");
   P.appendComponent("darwin");
   P.appendComponent(DarwinStaticLib);
-  
+
   // For now, allow missing resource libraries to support developers who may
   // not have compiler-rt checked out or integrated into their build.
   bool Exists;
@@ -1008,6 +1010,8 @@
       T = new tools::darwin::Lipo(*this); break;
     case Action::DsymutilJobClass:
       T = new tools::darwin::Dsymutil(*this); break;
+    case Action::VerifyJobClass:
+      T = new tools::darwin::VerifyDebug(*this); break;
     }
   }
 
@@ -1371,7 +1375,7 @@
   }
   if (Arch == llvm::Triple::ppc64)
     return true;
-  if ((Arch == llvm::Triple::x86 || Arch == llvm::Triple::ppc) && 
+  if ((Arch == llvm::Triple::x86 || Arch == llvm::Triple::ppc) &&
       IsDebianBased(Distro))
     return true;
   return false;
@@ -1596,14 +1600,14 @@
                                Exists) && Exists)
       GccTriple = "powerpc64-unknown-linux-gnu";
     else if (!llvm::sys::fs::exists("/usr/lib64/gcc/"
-                                    "powerpc64-unknown-linux-gnu", Exists) && 
+                                    "powerpc64-unknown-linux-gnu", Exists) &&
              Exists)
       GccTriple = "powerpc64-unknown-linux-gnu";
   }
 
   std::string Base = findGCCBaseLibDir(GccTriple);
   path_list &Paths = getFilePaths();
-  bool Is32Bits = (getArch() == llvm::Triple::x86 || 
+  bool Is32Bits = (getArch() == llvm::Triple::x86 ||
                    getArch() == llvm::Triple::ppc);
 
   std::string Suffix;
@@ -1776,6 +1780,7 @@
     case Action::BindArchClass:
     case Action::LipoJobClass:
     case Action::DsymutilJobClass:
+    case Action::VerifyJobClass:
       assert(0 && "Invalid tool kind.");
     case Action::PreprocessJobClass:
     case Action::PrecompileJobClass:
diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp
index e147c05..33e11fb 100644
--- a/lib/Driver/Tools.cpp
+++ b/lib/Driver/Tools.cpp
@@ -3482,6 +3482,26 @@
   C.addCommand(new Command(JA, *this, Exec, CmdArgs));
 }
 
+void darwin::VerifyDebug::ConstructJob(Compilation &C, const JobAction &JA,
+				       const InputInfo &Output,
+				       const InputInfoList &Inputs,
+				       const ArgList &Args,
+				       const char *LinkingOutput) const {
+  ArgStringList CmdArgs;
+  CmdArgs.push_back("--verify");
+
+  assert(Inputs.size() == 1 && "Unable to handle multiple inputs.");
+  const InputInfo &Input = Inputs[0];
+  assert(Input.isFilename() && "Unexpected verify input");
+
+  // Grabbing the output of the earlier dsymutil run.
+  CmdArgs.push_back(Input.getFilename());
+
+  const char *Exec =
+    Args.MakeArgString(getToolChain().GetProgramPath("dwarfdump"));
+  C.addCommand(new Command(JA, *this, Exec, CmdArgs));
+}
+
 void auroraux::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
                                       const InputInfo &Output,
                                       const InputInfoList &Inputs,
diff --git a/lib/Driver/Tools.h b/lib/Driver/Tools.h
index 702fc9d..a4f732e 100644
--- a/lib/Driver/Tools.h
+++ b/lib/Driver/Tools.h
@@ -277,6 +277,21 @@
                               const ArgList &TCArgs,
                               const char *LinkingOutput) const;
   };
+
+  class LLVM_LIBRARY_VISIBILITY VerifyDebug : public DarwinTool  {
+  public:
+    VerifyDebug(const ToolChain &TC) : DarwinTool("darwin::VerifyDebug",
+						  "dwarfdump", TC) {}
+
+    virtual bool hasIntegratedCPP() const { return false; }
+
+    virtual void ConstructJob(Compilation &C, const JobAction &JA,
+			      const InputInfo &Output,
+			      const InputInfoList &Inputs,
+			      const ArgList &TCArgs,
+			      const char *LinkingOutput) const;
+  };
+
 }
 
   /// openbsd -- Directly call GNU Binutils assembler and linker
diff --git a/test/Driver/darwin-verify-debug.c b/test/Driver/darwin-verify-debug.c
new file mode 100644
index 0000000..85445e9
--- /dev/null
+++ b/test/Driver/darwin-verify-debug.c
@@ -0,0 +1,33 @@
+// Check that we verify debug output properly with multiple -arch options.
+//
+// RUN: %clang -ccc-host-triple x86_64-apple-darwin10 -ccc-print-phases \
+// RUN:   -verify -arch i386 -arch x86_64 %s -g 2> %t
+// RUN: FileCheck -check-prefix=CHECK-MULTIARCH-ACTIONS < %t %s
+//
+// CHECK-MULTIARCH-ACTIONS: 0: input, "{{.*}}darwin-verify-debug.c", c
+// CHECK-MULTIARCH-ACTIONS: 8: dsymutil, {7}, dSYM
+// CHECK-MULTIARCH-ACTIONS: 9: verify, {8}, none
+//
+// RUN: %clang -ccc-host-triple x86_64-apple-darwin10 -ccc-print-bindings \
+// RUN:   -verify -arch i386 -arch x86_64 %s -g 2> %t
+// RUN: FileCheck -check-prefix=CHECK-MULTIARCH-BINDINGS < %t %s
+//
+// CHECK-MULTIARCH-BINDINGS: # "x86_64-apple-darwin10" - "darwin::Dsymutil", inputs: ["a.out"], output: "a.out.dSYM"
+// CHECK-MULTIARCH-BINDINGS: # "x86_64-apple-darwin10" - "darwin::VerifyDebug", inputs: ["a.out.dSYM"], output: (nothing)
+
+// Check output name derivation.
+//
+// RUN: %clang -ccc-host-triple x86_64-apple-darwin10 -ccc-print-bindings \
+// RUN:   -verify -o foo %s -g 2> %t
+// RUN: FileCheck -check-prefix=CHECK-OUTPUT-NAME < %t %s
+//
+// CHECK-OUTPUT-NAME: "x86_64-apple-darwin10" - "darwin::Link", inputs: [{{.*}}], output: "foo"
+// CHECK-OUTPUT-NAME: "x86_64-apple-darwin10" - "darwin::Dsymutil", inputs: ["foo"], output: "foo.dSYM"
+// CHECK-OUTPUT-NAME: "x86_64-apple-darwin10" - "darwin::VerifyDebug", inputs: ["foo.dSYM"], output: (nothing)
+
+// Check that we only verify when needed.
+//
+// RUN: touch %t.o
+// RUN: %clang -ccc-host-triple x86_64-apple-darwin10 -ccc-print-bindings \
+// RUN:   -verify -o foo %t.o -g 2> %t
+// RUN: grep "Verify" %t | count 0