Implement basic block extraction for the miscompilation debugger. This still needs
authorChris Lattner <sabre@nondot.org>
Tue, 11 May 2004 21:54:13 +0000 (21:54 +0000)
committerChris Lattner <sabre@nondot.org>
Tue, 11 May 2004 21:54:13 +0000 (21:54 +0000)
two things: the FIXME in ExtractBlocks needs to be implemented, and the basic block
extractor itself needs to have enough bugs fixed for this to be more or less
useful.

Until the time that this is generally useful, it is hidden behind the new bugpoint
-enable-block-extraction option.  I hope to get the FIXME done tonight.

Also of note, this patch adds a -extract-bbs option to bugpoint which can be used
to debug the block extractor.  (hint hint Misha :)

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@13471 91177308-0d34-0410-b5e6-96231b3b80d8

tools/bugpoint/BugDriver.h
tools/bugpoint/ExtractFunction.cpp
tools/bugpoint/Miscompilation.cpp

index 92fdb7c0a1c9cec9fd5721f8a162f84350664b17..5e78145b6f8769be35cb1885a91b3de3f969622a 100644 (file)
@@ -24,6 +24,7 @@ namespace llvm {
 class PassInfo;
 class Module;
 class Function;
+class BasicBlock;
 class AbstractInterpreter;
 class Instruction;
 
@@ -200,6 +201,14 @@ public:
   /// program or if the loop extractor crashes.
   Module *ExtractLoop(Module *M);
 
+  /// ExtractMappedBlocksFromModule - Extract all but the specified basic blocks
+  /// into their own functions.  The only detail is that M is actually a module
+  /// cloned from the one the BBs are in, so some mapping needs to be performed.
+  /// If this operation fails for some reason (ie the implementation is buggy),
+  /// this function should return null, otherwise it returns a new Module.
+  Module *ExtractMappedBlocksFromModule(const std::vector<BasicBlock*> &BBs,
+                                        Module *M);
+
   /// runPassesOn - Carefully run the specified set of pass on the specified
   /// module, returning the transformed module on success, or a null pointer on
   /// failure.  If AutoDebugCrashes is set to true, then bugpoint will
index 9f8dca8abd0e0e3a2a5b85d51c43be707c6941d6..ecc2652556eb342aa5c20d0f5927a621f1aa440c 100644 (file)
@@ -22,6 +22,7 @@
 #include "llvm/Transforms/IPO.h"
 #include "llvm/Transforms/Scalar.h"
 #include "llvm/Transforms/Utils/Cloning.h"
+#include "llvm/Transforms/Utils/FunctionUtils.h"
 #include "llvm/Target/TargetData.h"
 #include "Support/CommandLine.h"
 #include "Support/Debug.h"
@@ -199,3 +200,69 @@ Module *llvm::SplitFunctionsOutOfModule(Module *M,
       DeleteFunctionBody(I);
   return New;
 }
+
+//===----------------------------------------------------------------------===//
+// Basic Block Extraction Code
+//===----------------------------------------------------------------------===//
+
+namespace {
+  std::vector<BasicBlock*> BlocksToNotExtract;
+
+  /// BlockExtractorPass - This pass is used by bugpoint to extract all blocks
+  /// from the module into their own functions except for those specified by the
+  /// BlocksToNotExtract list.
+  class BlockExtractorPass : public Pass {
+    bool run(Module &M);
+  };
+  RegisterOpt<BlockExtractorPass>
+  XX("extract-bbs", "Extract Basic Blocks From Module (for bugpoint use)");
+}
+
+bool BlockExtractorPass::run(Module &M) {
+  std::set<BasicBlock*> TranslatedBlocksToNotExtract;
+  for (unsigned i = 0, e = BlocksToNotExtract.size(); i != e; ++i) {
+    BasicBlock *BB = BlocksToNotExtract[i];
+    Function *F = BB->getParent();
+
+    // Map the corresponding function in this module.
+    Function *MF = M.getFunction(F->getName(), F->getFunctionType());
+
+    // Figure out which index the basic block is in its function.
+    Function::iterator BBI = MF->begin();
+    std::advance(BBI, std::distance(F->begin(), Function::iterator(BB)));
+    TranslatedBlocksToNotExtract.insert(BBI);
+  }
+
+  // Now that we know which blocks to not extract, figure out which ones we WANT
+  // to extract.
+  std::vector<BasicBlock*> BlocksToExtract;
+  for (Module::iterator F = M.begin(), E = M.end(); F != E; ++F)
+    for (Function::iterator BB = F->begin(), E = F->end(); BB != E; ++BB)
+      if (!TranslatedBlocksToNotExtract.count(BB))
+        BlocksToExtract.push_back(BB);
+
+  for (unsigned i = 0, e = BlocksToExtract.size(); i != e; ++i)
+    ExtractBasicBlock(BlocksToExtract[i]);
+  
+  return !BlocksToExtract.empty();
+}
+
+/// ExtractMappedBlocksFromModule - Extract all but the specified basic blocks
+/// into their own functions.  The only detail is that M is actually a module
+/// cloned from the one the BBs are in, so some mapping needs to be performed.
+/// If this operation fails for some reason (ie the implementation is buggy),
+/// this function should return null, otherwise it returns a new Module.
+Module *BugDriver::ExtractMappedBlocksFromModule(const
+                                                 std::vector<BasicBlock*> &BBs,
+                                                 Module *M) {
+  // Set the global list so that pass will be able to access it.
+  BlocksToNotExtract = BBs;
+
+  std::vector<const PassInfo*> PI;
+  PI.push_back(getPI(new BlockExtractorPass()));
+  Module *Ret = runPassesOn(M, PI);
+  BlocksToNotExtract.clear();
+  if (Ret == 0)
+    std::cout << "*** Basic Block extraction failed, please report a bug!\n";
+  return Ret;
+}
index 3e532226b951301eb2d62a2651e8b5a9d8332141..adbc62d3eb97f3cc83bad91240a223f2381e6c3d 100644 (file)
@@ -29,6 +29,10 @@ using namespace llvm;
 
 namespace llvm {
   extern cl::list<std::string> InputArgv;
+  cl::opt<bool>
+  EnableBlockExtraction("enable-block-extraction",
+                        cl::desc("Enable basic block extraction for "
+                                 "miscompilation debugging (experimental)"));
 }
 
 namespace {
@@ -320,6 +324,95 @@ static bool ExtractLoops(BugDriver &BD,
   }
 }
 
+namespace {
+  class ReduceMiscompiledBlocks : public ListReducer<BasicBlock*> {
+    BugDriver &BD;
+    bool (*TestFn)(BugDriver &, Module *, Module *);
+    std::vector<Function*> FunctionsBeingTested;
+  public:
+    ReduceMiscompiledBlocks(BugDriver &bd,
+                            bool (*F)(BugDriver &, Module *, Module *),
+                            const std::vector<Function*> &Fns)
+      : BD(bd), TestFn(F), FunctionsBeingTested(Fns) {}
+    
+    virtual TestResult doTest(std::vector<BasicBlock*> &Prefix,
+                              std::vector<BasicBlock*> &Suffix) {
+      if (!Suffix.empty() && TestFuncs(Suffix))
+        return KeepSuffix;
+      if (TestFuncs(Prefix))
+        return KeepPrefix;
+      return NoFailure;
+    }
+    
+    bool TestFuncs(const std::vector<BasicBlock*> &Prefix);
+  };
+}
+
+/// TestFuncs - Extract all blocks for the miscompiled functions except for the
+/// specified blocks.  If the problem still exists, return true.
+///
+bool ReduceMiscompiledBlocks::TestFuncs(const std::vector<BasicBlock*> &BBs) {
+  // Test to see if the function is misoptimized if we ONLY run it on the
+  // functions listed in Funcs.
+  std::cout << "Checking to see if the program is misoptimized when all but "
+            << "these " << BBs.size() << " blocks are extracted: ";
+  for (unsigned i = 0, e = BBs.size() < 10 ? BBs.size() : 10; i != e; ++i)
+    std::cout << BBs[i]->getName() << " ";
+  if (BBs.size() > 10) std::cout << "...";
+  std::cout << "\n";
+
+  // Split the module into the two halves of the program we want.
+  Module *ToNotOptimize = CloneModule(BD.getProgram());
+  Module *ToOptimize = SplitFunctionsOutOfModule(ToNotOptimize,
+                                                 FunctionsBeingTested);
+
+  // Try the extraction.  If it doesn't work, then the block extractor crashed
+  // or something, in which case bugpoint can't chase down this possibility.
+  if (Module *New = BD.ExtractMappedBlocksFromModule(BBs, ToOptimize)) {
+    delete ToOptimize;
+    // Run the predicate, not that the predicate will delete both input modules.
+    return TestFn(BD, New, ToNotOptimize);
+  }
+  delete ToOptimize;
+  delete ToNotOptimize;
+  return false;
+}
+
+
+/// ExtractBlocks - Given a reduced list of functions that still expose the bug,
+/// extract as many basic blocks from the region as possible without obscuring
+/// the bug.
+///
+static bool ExtractBlocks(BugDriver &BD,
+                          bool (*TestFn)(BugDriver &, Module *, Module *),
+                          std::vector<Function*> &MiscompiledFunctions) {
+  // Not enabled??
+  if (!EnableBlockExtraction) return false;
+
+  std::vector<BasicBlock*> Blocks;
+  for (unsigned i = 0, e = MiscompiledFunctions.size(); i != e; ++i)
+    for (Function::iterator I = MiscompiledFunctions[i]->begin(),
+           E = MiscompiledFunctions[i]->end(); I != E; ++I)
+      Blocks.push_back(I);
+
+  // Use the list reducer to identify blocks that can be extracted without
+  // obscuring the bug.  The Blocks list will end up containing blocks that must
+  // be retained from the original program.
+  unsigned OldSize = Blocks.size();
+  ReduceMiscompiledBlocks(BD, TestFn, MiscompiledFunctions).reduceList(Blocks);
+  if (Blocks.size() == OldSize)
+    return false;
+
+
+
+  // FIXME: This should actually update the module in the bugdriver!
+
+
+
+  return false;
+}
+
+
 /// DebugAMiscompilation - This is a generic driver to narrow down
 /// miscompilations, either in an optimization or a code generator.
 ///
@@ -366,6 +459,25 @@ DebugAMiscompilation(BugDriver &BD,
     std::cout << "\n";
   }
 
+  if (ExtractBlocks(BD, TestFn, MiscompiledFunctions)) {
+    // Okay, we extracted some blocks and the problem still appears.  See if we
+    // can eliminate some of the created functions from being candidates.
+
+    // Block extraction can introduce functions with the same name (foo_code).
+    // Make sure to disambiguate the symbols so that when the program is split
+    // apart that we can link it back together again.
+    DisambiguateGlobalSymbols(BD.getProgram());
+
+    // Do the reduction...
+    ReduceMiscompilingFunctions(BD, TestFn).reduceList(MiscompiledFunctions);
+    
+    std::cout << "\n*** The following function"
+              << (MiscompiledFunctions.size() == 1 ? " is" : "s are")
+              << " being miscompiled: ";
+    PrintFunctionList(MiscompiledFunctions);
+    std::cout << "\n";
+  }
+
   return MiscompiledFunctions;
 }