aboutsummaryrefslogtreecommitdiff
path: root/tools/bugpoint/CodeGeneratorBug.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tools/bugpoint/CodeGeneratorBug.cpp')
-rw-r--r--tools/bugpoint/CodeGeneratorBug.cpp176
1 files changed, 176 insertions, 0 deletions
diff --git a/tools/bugpoint/CodeGeneratorBug.cpp b/tools/bugpoint/CodeGeneratorBug.cpp
new file mode 100644
index 0000000000..772b4fdf75
--- /dev/null
+++ b/tools/bugpoint/CodeGeneratorBug.cpp
@@ -0,0 +1,176 @@
+//===- CodeGeneratorBug.cpp - Debug code generation bugs ------------------===//
+//
+// This file implements program code generation debugging support.
+//
+//===----------------------------------------------------------------------===//
+
+#include "BugDriver.h"
+#include "SystemUtils.h"
+#include "ListReducer.h"
+#include "llvm/Pass.h"
+#include "llvm/Module.h"
+#include "llvm/Transforms/Utils/Cloning.h"
+#include "llvm/Transforms/Utils/Linker.h"
+#include "Support/CommandLine.h"
+#include "Support/Statistic.h"
+#include "Support/StringExtras.h"
+#include <algorithm>
+#include <set>
+
+// Passed as a command-line argument to Bugpoint
+extern cl::opt<std::string> Output;
+
+class ReduceMisCodegenFunctions : public ListReducer<Function*> {
+ BugDriver &BD;
+public:
+ ReduceMisCodegenFunctions(BugDriver &bd) : BD(bd) {}
+
+ virtual TestResult doTest(std::vector<Function*> &Prefix,
+ std::vector<Function*> &Suffix) {
+ if (!Prefix.empty() && TestFuncs(Prefix))
+ return KeepPrefix;
+ if (!Suffix.empty() && TestFuncs(Suffix))
+ return KeepSuffix;
+ return NoFailure;
+ }
+
+ bool TestFuncs(const std::vector<Function*> &CodegenTest);
+
+ void DisambiguateGlobalSymbols(Module *M);
+};
+
+
+bool ReduceMisCodegenFunctions::TestFuncs(const std::vector<Function*> &Funcs)
+{
+ // Clone the module for the two halves of the program we want.
+ Module *SafeModule = CloneModule(BD.Program);
+
+ // Make sure functions & globals are all external so that linkage
+ // between the two modules will work.
+ for (Module::iterator I = SafeModule->begin(), E = SafeModule->end();I!=E;++I)
+ I->setLinkage(GlobalValue::ExternalLinkage);
+ for (Module::giterator I=SafeModule->gbegin(),E = SafeModule->gend();I!=E;++I)
+ I->setLinkage(GlobalValue::ExternalLinkage);
+
+ DisambiguateGlobalSymbols(SafeModule);
+ Module *TestModule = CloneModule(SafeModule);
+
+ // Make sure global initializers exist only in the safe module (CBE->.so)
+ for (Module::giterator I=TestModule->gbegin(),E = TestModule->gend();I!=E;++I)
+ I->setInitializer(0); // Delete the initializer to make it external
+
+ // Remove the Test functions from the Safe module, and
+ // all of the global variables.
+ for (unsigned i = 0, e = Funcs.size(); i != e; ++i) {
+ Function *TNOF = SafeModule->getFunction(Funcs[i]->getName(),
+ Funcs[i]->getFunctionType());
+ assert(TNOF && "Function doesn't exist in module!");
+ DeleteFunctionBody(TNOF); // Function is now external in this module!
+ }
+
+ // Write out the bytecode to be sent to CBE
+ std::string SafeModuleBC = "bugpoint.safe.bc";
+ if (BD.writeProgramToFile(SafeModuleBC, SafeModule)) {
+ std::cerr << "Error writing bytecode to `" << SafeModuleBC << "'\nExiting.";
+ exit(1);
+ }
+
+ // Make a shared library
+ std::string SharedObject;
+ BD.compileSharedObject(SafeModuleBC, SharedObject);
+
+ // Remove all functions from the Test module EXCEPT for the ones specified in
+ // Funcs. We know which ones these are because they are non-external in
+ // ToOptimize, but external in ToNotOptimize.
+ //
+ for (Module::iterator I = TestModule->begin(), E = TestModule->end();I!=E;++I)
+ if (!I->isExternal()) {
+ Function *TNOF = SafeModule->getFunction(I->getName(),
+ I->getFunctionType());
+ assert(TNOF && "Function doesn't exist in ToNotOptimize module??");
+ if (!TNOF->isExternal())
+ DeleteFunctionBody(I);
+ }
+
+ std::string TestModuleBC = "bugpoint.test.bc";
+ if (BD.writeProgramToFile(TestModuleBC, TestModule)) {
+ std::cerr << "Error writing bytecode to `" << SafeModuleBC << "'\nExiting.";
+ exit(1);
+ }
+
+ // Run the code generator on the `Test' code, loading the shared library.
+ // The function returns whether or not the new output differs from reference.
+ return BD.diffProgram(TestModuleBC, SharedObject, false);
+}
+
+namespace {
+ struct Disambiguator /*: public unary_function<GlobalValue&, void>*/ {
+ std::set<std::string> SymbolNames;
+ std::set<Value*> Symbols;
+ uint64_t uniqueCounter;
+ bool externalOnly;
+
+ Disambiguator() : uniqueCounter(0), externalOnly(true) {}
+ void setExternalOnly(bool value) { externalOnly = value; }
+ void operator() (GlobalValue &V) {
+ if (externalOnly && !V.isExternal()) return;
+
+ if (SymbolNames.count(V.getName()) == 0) {
+ DEBUG(std::cerr << "Disambiguator: adding " << V.getName()
+ << ", no conflicts.\n");
+ Symbols.insert(&V);
+ SymbolNames.insert(V.getName());
+ } else {
+ // Mangle name before adding
+ std::string newName;
+ do {
+ newName = V.getName() + "_" + utostr(uniqueCounter);
+ if (SymbolNames.count(newName) == 0) break;
+ else ++uniqueCounter;
+ } while (1);
+ //while (SymbolNames.count(V->getName()+utostr(uniqueCounter++))==0);
+ DEBUG(std::cerr << "Disambiguator: conflict: " << V.getName()
+ << ", adding: " << newName << "\n");
+ V.setName(newName);
+ SymbolNames.insert(newName);
+ Symbols.insert(&V);
+ }
+ }
+ };
+}
+
+void ReduceMisCodegenFunctions::DisambiguateGlobalSymbols(Module *M) {
+ // First, try not to cause collisions by minimizing chances of renaming an
+ // already-external symbol, so take in external globals and functions as-is.
+ Disambiguator D = std::for_each(M->gbegin(), M->gend(), Disambiguator());
+ std::for_each(M->begin(), M->end(), D);
+
+ // Now just rename functions and globals as necessary, keeping what's already
+ // in the set unique.
+ D.setExternalOnly(false);
+ std::for_each(M->gbegin(), M->gend(), D);
+ std::for_each(M->begin(), M->end(), D);
+}
+
+
+bool BugDriver::debugCodeGenerator() {
+ // See if we can pin down which functions are being miscompiled...
+ //First, build a list of all of the non-external functions in the program.
+ std::vector<Function*> MisCodegenFunctions;
+ for (Module::iterator I = Program->begin(), E = Program->end(); I != E; ++I)
+ if (!I->isExternal())
+ MisCodegenFunctions.push_back(I);
+
+ // Do the reduction...
+ ReduceMisCodegenFunctions(*this).reduceList(MisCodegenFunctions);
+
+ std::cout << "\n*** The following functions are being miscompiled: ";
+ PrintFunctionList(MisCodegenFunctions);
+ std::cout << "\n";
+
+ // Output a bunch of bytecode files for the user...
+ ReduceMisCodegenFunctions(*this).TestFuncs(MisCodegenFunctions);
+
+ return false;
+}
+