[llvm-commits] CVS: llvm/tools/bugpoint/BugDriver.h ExtractFunction.cpp Miscompilation.cpp

Chris Lattner lattner at cs.uiuc.edu
Tue May 11 16:54:02 PDT 2004


Changes in directory llvm/tools/bugpoint:

BugDriver.h updated: 1.37 -> 1.38
ExtractFunction.cpp updated: 1.33 -> 1.34
Miscompilation.cpp updated: 1.44 -> 1.45

---
Log message:

Implement basic block extraction for the miscompilation debugger.  This still needs
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 :)



---
Diffs of the changes:  (+188 -0)

Index: llvm/tools/bugpoint/BugDriver.h
diff -u llvm/tools/bugpoint/BugDriver.h:1.37 llvm/tools/bugpoint/BugDriver.h:1.38
--- llvm/tools/bugpoint/BugDriver.h:1.37	Mon Apr  5 17:58:16 2004
+++ llvm/tools/bugpoint/BugDriver.h	Tue May 11 16:54:12 2004
@@ -24,6 +24,7 @@
 class PassInfo;
 class Module;
 class Function;
+class BasicBlock;
 class AbstractInterpreter;
 class Instruction;
 
@@ -199,6 +200,14 @@
   /// function.  This returns null if there are no extractable loops in the
   /// 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


Index: llvm/tools/bugpoint/ExtractFunction.cpp
diff -u llvm/tools/bugpoint/ExtractFunction.cpp:1.33 llvm/tools/bugpoint/ExtractFunction.cpp:1.34
--- llvm/tools/bugpoint/ExtractFunction.cpp:1.33	Fri Apr  2 10:28:32 2004
+++ llvm/tools/bugpoint/ExtractFunction.cpp	Tue May 11 16:54:13 2004
@@ -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"
@@ -198,4 +199,70 @@
     if (!TestFunctions.count(std::make_pair(I->getName(), I->getType())))
       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: llvm/tools/bugpoint/Miscompilation.cpp
diff -u llvm/tools/bugpoint/Miscompilation.cpp:1.44 llvm/tools/bugpoint/Miscompilation.cpp:1.45
--- llvm/tools/bugpoint/Miscompilation.cpp:1.44	Fri Apr 23 15:36:51 2004
+++ llvm/tools/bugpoint/Miscompilation.cpp	Tue May 11 16:54:13 2004
@@ -29,6 +29,10 @@
 
 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 @@
   }
 }
 
+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.
 ///
@@ -352,6 +445,25 @@
     // can eliminate some of the created functions from being candidates.
 
     // Loop 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";
+  }
+
+  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());





More information about the llvm-commits mailing list