X-Git-Url: http://demsky.eecs.uci.edu/git/?a=blobdiff_plain;f=tools%2Fbugpoint%2FCodeGeneratorBug.cpp;h=8569bb9337d92c1fe1dd0bf5fa6f39d4c09c5e77;hb=91ef460285021b5bf43b3850f0f8958a09b8939c;hp=10e2186df28a765a8e14c2645c47609250d232f9;hpb=c648dabf65c67d20c208ed0b39b9622387e636c7;p=oota-llvm.git diff --git a/tools/bugpoint/CodeGeneratorBug.cpp b/tools/bugpoint/CodeGeneratorBug.cpp index 10e2186df28..8569bb9337d 100644 --- a/tools/bugpoint/CodeGeneratorBug.cpp +++ b/tools/bugpoint/CodeGeneratorBug.cpp @@ -1,11 +1,17 @@ //===- CodeGeneratorBug.cpp - Debug code generation bugs ------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file was developed by the LLVM research group and is distributed under +// the University of Illinois Open Source License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// // // This file implements program code generation debugging support. // //===----------------------------------------------------------------------===// #include "BugDriver.h" -#include "SystemUtils.h" #include "ListReducer.h" #include "llvm/Constants.h" #include "llvm/DerivedTypes.h" @@ -23,72 +29,49 @@ #include "Support/CommandLine.h" #include "Support/Debug.h" #include "Support/StringExtras.h" +#include "Support/FileUtilities.h" #include #include +using namespace llvm; -extern cl::list InputArgv; - -class ReduceMisCodegenFunctions : public ListReducer { - BugDriver &BD; -public: - ReduceMisCodegenFunctions(BugDriver &bd) : BD(bd) {} - - virtual TestResult doTest(std::vector &Prefix, - std::vector &Suffix) { - if (!Prefix.empty() && TestFuncs(Prefix)) - return KeepPrefix; - if (!Suffix.empty() && TestFuncs(Suffix)) - return KeepSuffix; - return NoFailure; - } - - bool TestFuncs(const std::vector &CodegenTest, - bool KeepFiles = false); -}; +namespace llvm { + extern cl::list InputArgv; + class ReduceMisCodegenFunctions : public ListReducer { + BugDriver &BD; + public: + ReduceMisCodegenFunctions(BugDriver &bd) : BD(bd) {} + + virtual TestResult doTest(std::vector &Prefix, + std::vector &Suffix) { + if (!Prefix.empty() && TestFuncs(Prefix)) + return KeepPrefix; + if (!Suffix.empty() && TestFuncs(Suffix)) + return KeepSuffix; + return NoFailure; + } + + bool TestFuncs(const std::vector &CodegenTest, + bool KeepFiles = false); + }; +} bool ReduceMisCodegenFunctions::TestFuncs(const std::vector &Funcs, - bool KeepFiles) -{ + bool KeepFiles) { std::cout << "Testing functions: "; - BD.PrintFunctionList(Funcs); + PrintFunctionList(Funcs); std::cout << "\t"; // 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); - - 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 - for (unsigned i = 0, e = Funcs.size(); i != e; ++i) { - Function *TNOF = SafeModule->getFunction(Funcs[i]->getName(), - Funcs[i]->getFunctionType()); - DEBUG(std::cerr << "Removing function " << Funcs[i]->getName() << "\n"); - assert(TNOF && "Function doesn't exist in module!"); - DeleteFunctionBody(TNOF); // Function is now external in this module! - } + Module *SafeModule = CloneModule(BD.getProgram()); - // Remove the Safe functions from the Test module - for (Module::iterator I=TestModule->begin(),E=TestModule->end(); I!=E; ++I) { - bool funcFound = false; - for (std::vector::const_iterator F=Funcs.begin(),Fe=Funcs.end(); - F != Fe; ++F) - if (I->getName() == (*F)->getName()) funcFound = true; - - if (!funcFound && !(BD.isExecutingJIT() && I->getName() == "main")) - DeleteFunctionBody(I); + // The JIT must extract the 'main' function. + std::vector RealFuncs(Funcs); + if (BD.isExecutingJIT()) { + if (Function *F = BD.Program->getMainFunction()) + RealFuncs.push_back(F); } + Module *TestModule = SplitFunctionsOutOfModule(SafeModule, RealFuncs); // This is only applicable if we are debugging the JIT: // Find all external functions in the Safe modules that are actually used @@ -113,8 +96,10 @@ bool ReduceMisCodegenFunctions::TestFuncs(const std::vector &Funcs, // Use the function we just added to get addresses of functions we need // Iterate over the global declarations in the Safe module for (Module::iterator F=SafeModule->begin(),E=SafeModule->end(); F!=E; ++F){ - if (F->isExternal() && !F->use_empty() && &(*F) != resolverFunc && - F->getIntrinsicID() == 0 /* ignore intrinsics */) { + if (F->isExternal() && !F->use_empty() && &*F != resolverFunc && + F->getIntrinsicID() == 0 /* ignore intrinsics */ && + // Don't forward functions which are external in the test module too. + !TestModule->getNamedFunction(F->getName())->isExternal()) { // If it has a non-zero use list, // 1. Add a string constant with its name to the global file // The correct type is `const [ NUM x sbyte ]' where NUM is length of @@ -145,8 +130,8 @@ bool ReduceMisCodegenFunctions::TestFuncs(const std::vector &Funcs, ResolverArgs.push_back(GEP); // Insert code at the beginning of the function - for (Value::use_iterator i=F->use_begin(), e=F->use_end(); i!=e; ++i) { - if (Instruction* Inst = dyn_cast(*i)) { + while (!F->use_empty()) + if (Instruction *Inst = dyn_cast(F->use_back())) { // call resolver(GetElementPtr...) CallInst *resolve = new CallInst(resolverFunc, ResolverArgs, "resolver", Inst); @@ -157,12 +142,13 @@ bool ReduceMisCodegenFunctions::TestFuncs(const std::vector &Funcs, // actually use the resolved function Inst->replaceUsesOfWith(F, castResolver); } else { - // FIXME: need to take care of cases where a function is used that - // is not an instruction, e.g. global variable initializer... - std::cerr << "Non-instruction is using an external function!\n"; + // FIXME: need to take care of cases where a function is used by + // something other than an instruction; e.g., global variable + // initializers and constant expressions. + std::cerr << "UNSUPPORTED: Non-instruction is using an external " + << "function, " << F->getName() << "().\n"; abort(); } - } } } } @@ -172,10 +158,6 @@ bool ReduceMisCodegenFunctions::TestFuncs(const std::vector &Funcs, abort(); } - // Clean up the modules, removing extra cruft that we don't need anymore... - SafeModule = BD.performFinalCleanups(SafeModule); - TestModule = BD.performFinalCleanups(TestModule); - DEBUG(std::cerr << "Safe module:\n"; typedef Module::iterator MI; typedef Module::giterator MGI; @@ -200,10 +182,6 @@ bool ReduceMisCodegenFunctions::TestFuncs(const std::vector &Funcs, 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. @@ -222,26 +200,53 @@ bool ReduceMisCodegenFunctions::TestFuncs(const std::vector &Funcs, std::cerr << "Bytecode file corrupted!\n"; exit(1); } + + // Clean up the modules, removing extra cruft that we don't need anymore... + SafeModule = BD.performFinalCleanups(SafeModule); + TestModule = BD.performFinalCleanups(TestModule); + if (BD.writeProgramToFile(TestModuleBC, TestModule)) { std::cerr << "Error writing bytecode to `" << SafeModuleBC << "'\nExiting."; exit(1); } + // Make a shared library + std::string SharedObject = BD.compileSharedObject(SafeModuleBC); + delete SafeModule; delete TestModule; // Run the code generator on the `Test' code, loading the shared library. // The function returns whether or not the new output differs from reference. - int Result = BD.diffProgram(TestModuleBC, SharedObject, false); + int Result = BD.diffProgram(TestModuleBC, SharedObject, false); + + if (Result) + std::cerr << ": still failing!\n"; + else + std::cerr << ": didn't fail.\n"; + if (KeepFiles) { - std::cout << "You can reproduce the problem with the command line: \n" - << (BD.isExecutingJIT() ? "lli" : "llc") - << " -load " << SharedObject << " " << TestModuleBC; + std::cout << "You can reproduce the problem with the command line: \n"; + if (BD.isExecutingJIT()) { + std::cout << " lli -load " << SharedObject << " " << TestModuleBC; + } else { + std::cout << " llc " << TestModuleBC << " -o " << TestModuleBC << ".s\n"; + std::cout << " gcc " << SharedObject << " " << TestModuleBC + << ".s -o " << TestModuleBC << ".exe -Wl,-R.\n"; + std::cout << " " << TestModuleBC << ".exe"; + } for (unsigned i=0, e = InputArgv.size(); i != e; ++i) std::cout << " " << InputArgv[i]; std::cout << "\n"; - std::cout << "The shared object " << SharedObject << " was created from " - << SafeModuleBC << ", using `dis -c'.\n"; + std::cout << "The shared object was created with:\n llc -march=c " + << SafeModuleBC << " -o temporary.c\n" + << " gcc -xc temporary.c -O2 -o " << SharedObject +#if defined(sparc) || defined(__sparc__) || defined(__sparcv9) + << " -G" // Compile a shared library, `-G' for Sparc +#else + << " -shared" // `-shared' for Linux/X86, maybe others +#endif + << " -fno-strict-aliasing\n"; } else { removeFile(TestModuleBC); removeFile(SafeModuleBC); @@ -299,7 +304,7 @@ namespace { }; } -void DisambiguateGlobalSymbols(Module *M) { +static void 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; @@ -319,8 +324,19 @@ void DisambiguateGlobalSymbols(Module *M) { bool BugDriver::debugCodeGenerator() { + if ((void*)cbe == (void*)Interpreter) { + std::string Result = executeProgramWithCBE("bugpoint.cbe.out"); + std::cout << "\n*** The C backend cannot match the reference diff, but it " + << "is used as the 'known good'\n code generator, so I can't" + << " debug it. Perhaps you have a front-end problem?\n As a" + << " sanity check, I left the result of executing the program " + << "with the C backend\n in this file for you: '" + << Result << "'.\n"; + return true; + } + // 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. + // First, build a list of all of the non-external functions in the program. std::vector MisCodegenFunctions; for (Module::iterator I = Program->begin(), E = Program->end(); I != E; ++I) if (!I->isExternal()) @@ -335,7 +351,7 @@ bool BugDriver::debugCodeGenerator() { Function *oldMain = Program->getNamedFunction("main"); assert(oldMain && "`main' function not found in program!"); // Rename it - oldMain->setName("old_main"); + oldMain->setName("llvm_old_main"); // Create a NEW `main' function with same type Function *newMain = new Function(oldMain->getFunctionType(), GlobalValue::ExternalLinkage, @@ -343,29 +359,28 @@ bool BugDriver::debugCodeGenerator() { // Call the old main function and return its result BasicBlock *BB = new BasicBlock("entry", newMain); std::vector args; - for (Function::aiterator I=newMain->abegin(), E=newMain->aend(); I!=E; ++I) + for (Function::aiterator I = newMain->abegin(), E = newMain->aend(), + OI = oldMain->abegin(); I != E; ++I, ++OI) { + I->setName(OI->getName()); // Copy argument names from oldMain args.push_back(I); + } CallInst *call = new CallInst(oldMain, args); BB->getInstList().push_back(call); // if the type of old function wasn't void, return value of call - ReturnInst *ret; if (oldMain->getReturnType() != Type::VoidTy) { - ret = new ReturnInst(call); + new ReturnInst(call, BB); } else { - ret = new ReturnInst(); + new ReturnInst(0, BB); } - - // Add the return instruction to the BasicBlock - BB->getInstList().push_back(ret); } DisambiguateGlobalSymbols(Program); // Do the reduction... if (!ReduceMisCodegenFunctions(*this).reduceList(MisCodegenFunctions)) { - std::cerr << "*** Execution matches reference output! No problem " - << "detected...\nbugpoint can't help you with your problem!\n"; + std::cerr << "*** Execution matches reference output! " + << "bugpoint can't help you with your problem!\n"; return false; }