LTO: Verify the input even if optimize() isn't called
authorDuncan P. N. Exon Smith <dexonsmith@apple.com>
Wed, 20 Apr 2016 17:48:22 +0000 (17:48 +0000)
committerDuncan P. N. Exon Smith <dexonsmith@apple.com>
Wed, 20 Apr 2016 17:48:22 +0000 (17:48 +0000)
Clients may call writeMergedModules before calling optimize, or call
compileOptimized without calling optimize.  Make sure they don't sneak
past the verifier.  This adds LTOCodeGenerator::verifyMergedModuleOnce,
and calls it from writeMergedModule, optimize, and codegenOptimized.

I couldn't find a good way to test this.  I tried writing broken IR to
send into llvm-lto, but LTOCodeGenerator doesn't understand textual IR,
and assembler runs the verifier itself anyway.  Checking in
valid-but-doesn't-verify bitcode here doesn't seem valuable.

llvm-svn: 266894

llvm/include/llvm/LTO/LTOCodeGenerator.h
llvm/lib/LTO/LTOCodeGenerator.cpp

index 16605da..4f78d27 100644 (file)
@@ -68,9 +68,13 @@ struct LTOCodeGenerator {
   ~LTOCodeGenerator();
 
   /// Merge given module.  Return true on success.
+  ///
+  /// Resets \a HasVerifiedInput.
   bool addModule(struct LTOModule *);
 
   /// Set the destination module.
+  ///
+  /// Resets \a HasVerifiedInput.
   void setModule(std::unique_ptr<LTOModule> M);
 
   void setTargetOptions(TargetOptions Options);
@@ -123,6 +127,8 @@ struct LTOCodeGenerator {
 
   /// Write the merged module to the file specified by the given path.  Return
   /// true on success.
+  ///
+  /// Calls \a verifyMergedModuleOnce().
   bool writeMergedModules(const char *Path);
 
   /// Compile the merged module into a *single* output file; the path to output
@@ -147,6 +153,8 @@ struct LTOCodeGenerator {
                                         bool DisableVectorization);
 
   /// Optimizes the merged module.  Returns true on success.
+  ///
+  /// Calls \a verifyMergedModuleOnce().
   bool optimize(bool DisableVerify, bool DisableInline, bool DisableGVNLoadPRE,
                 bool DisableVectorization);
 
@@ -160,6 +168,8 @@ struct LTOCodeGenerator {
   /// than one element, code generation is done in parallel with out.size()
   /// threads.  Output files will be written to members of out. Returns true on
   /// success.
+  ///
+  /// Calls \a verifyMergedModuleOnce().
   bool compileOptimized(ArrayRef<raw_pwrite_stream *> Out);
 
   void setDiagnosticHandler(lto_diagnostic_handler_t, void *);
@@ -171,6 +181,12 @@ struct LTOCodeGenerator {
 private:
   void initializeLTOPasses();
 
+  /// Verify the merged module on first call.
+  ///
+  /// Sets \a HasVerifiedInput on first call and doesn't run again on the same
+  /// input.
+  void verifyMergedModuleOnce();
+
   bool compileOptimizedToFile(const char **Name);
   void restoreLinkageForExternals();
   void applyScopeRestrictions();
@@ -189,6 +205,7 @@ private:
   std::unique_ptr<TargetMachine> TargetMach;
   bool EmitDwarfDebugInfo = false;
   bool ScopeRestrictionsDone = false;
+  bool HasVerifiedInput = false;
   Reloc::Model RelocModel = Reloc::Default;
   StringSet<> MustPreserveSymbols;
   StringSet<> AsmUndefinedRefs;
index e06903c..64d708e 100644 (file)
@@ -131,6 +131,9 @@ bool LTOCodeGenerator::addModule(LTOModule *Mod) {
   for (int i = 0, e = undefs.size(); i != e; ++i)
     AsmUndefinedRefs[undefs[i]] = 1;
 
+  // We've just changed the input, so let's make sure we verify it.
+  HasVerifiedInput = false;
+
   return !ret;
 }
 
@@ -146,6 +149,9 @@ void LTOCodeGenerator::setModule(std::unique_ptr<LTOModule> Mod) {
   const std::vector<const char*> &Undefs = Mod->getAsmUndefinedRefs();
   for (int I = 0, E = Undefs.size(); I != E; ++I)
     AsmUndefinedRefs[Undefs[I]] = 1;
+
+  // We've just changed the input, so let's make sure we verify it.
+  HasVerifiedInput = false;
 }
 
 void LTOCodeGenerator::setTargetOptions(TargetOptions Options) {
@@ -187,6 +193,9 @@ bool LTOCodeGenerator::writeMergedModules(const char *Path) {
   if (!determineTarget())
     return false;
 
+  // We always run the verifier once on the merged module.
+  verifyMergedModuleOnce();
+
   // mark which symbols can not be internalized
   applyScopeRestrictions();
 
@@ -413,6 +422,16 @@ void LTOCodeGenerator::restoreLinkageForExternals() {
                 externalize);
 }
 
+void LTOCodeGenerator::verifyMergedModuleOnce() {
+  // Only run on the first call.
+  if (HasVerifiedInput)
+    return;
+  HasVerifiedInput = true;
+
+  if (verifyModule(*MergedModule, &dbgs()))
+    report_fatal_error("Broken module found, compilation aborted!");
+}
+
 /// Optimize merged modules using various IPO passes
 bool LTOCodeGenerator::optimize(bool DisableVerify, bool DisableInline,
                                 bool DisableGVNLoadPRE,
@@ -422,8 +441,7 @@ bool LTOCodeGenerator::optimize(bool DisableVerify, bool DisableInline,
 
   // We always run the verifier once on the merged module, the `DisableVerify`
   // parameter only applies to subsequent verify.
-  if (verifyModule(*MergedModule, &dbgs()))
-    report_fatal_error("Broken module found, compilation aborted!");
+  verifyMergedModuleOnce();
 
   // Mark which symbols can not be internalized
   this->applyScopeRestrictions();
@@ -461,6 +479,10 @@ bool LTOCodeGenerator::compileOptimized(ArrayRef<raw_pwrite_stream *> Out) {
   if (!this->determineTarget())
     return false;
 
+  // We always run the verifier once on the merged module.  If it has already
+  // been called in optimize(), this call will return early.
+  verifyMergedModuleOnce();
+
   legacy::PassManager preCodeGenPasses;
 
   // If the bitcode files contain ARC code and were compiled with optimization,