//===- Miscompilation.cpp - Debug program miscompilations -----------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This file implements optimizer and code generation miscompilation debugging // support. // //===----------------------------------------------------------------------===// #include "BugDriver.h" #include "ListReducer.h" #include "ToolRunner.h" #include "llvm/Config/config.h" // for HAVE_LINK_R #include "llvm/IR/Constants.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/Module.h" #include "llvm/IR/Verifier.h" #include "llvm/Linker/Linker.h" #include "llvm/Pass.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/FileUtilities.h" #include "llvm/Transforms/Utils/Cloning.h" usingnamespacellvm; namespace llvm { extern cl::opt<std::string> OutputPrefix; extern cl::list<std::string> InputArgv; } // end namespace llvm namespace { static llvm::cl::opt<bool> DisableLoopExtraction( "disable-loop-extraction", cl::desc("Don't extract loops when searching for miscompilations"), cl::init(false)); static llvm::cl::opt<bool> DisableBlockExtraction( "disable-block-extraction", cl::desc("Don't extract blocks when searching for miscompilations"), cl::init(false)); class ReduceMiscompilingPasses : public ListReducer<std::string> { … }; } // end anonymous namespace /// TestResult - After passes have been split into a test group and a control /// group, see if they still break the program. /// Expected<ReduceMiscompilingPasses::TestResult> ReduceMiscompilingPasses::doTest(std::vector<std::string> &Prefix, std::vector<std::string> &Suffix) { … } namespace { class ReduceMiscompilingFunctions : public ListReducer<Function *> { … }; } // end anonymous namespace /// Given two modules, link them together and run the program, checking to see /// if the program matches the diff. If there is an error, return NULL. If not, /// return the merged module. The Broken argument will be set to true if the /// output is different. If the DeleteInputs argument is set to true then this /// function deletes both input modules before it returns. /// static Expected<std::unique_ptr<Module>> testMergedProgram(const BugDriver &BD, const Module &M1, const Module &M2, bool &Broken) { … } /// split functions in a Module into two groups: those that are under /// consideration for miscompilation vs. those that are not, and test /// accordingly. Each group of functions becomes a separate Module. Expected<bool> ReduceMiscompilingFunctions::TestFuncs(const std::vector<Function *> &Funcs) { … } /// Give anonymous global values names. static void DisambiguateGlobalSymbols(Module &M) { … } /// Given a reduced list of functions that still exposed the bug, check to see /// if we can extract the loops in the region without obscuring the bug. If so, /// it reduces the amount of code identified. /// static Expected<bool> ExtractLoops(BugDriver &BD, Expected<bool> (*TestFn)(BugDriver &, std::unique_ptr<Module>, std::unique_ptr<Module>), std::vector<Function *> &MiscompiledFunctions) { … } namespace { class ReduceMiscompiledBlocks : public ListReducer<BasicBlock *> { … }; } // end anonymous namespace /// TestFuncs - Extract all blocks for the miscompiled functions except for the /// specified blocks. If the problem still exists, return true. /// Expected<bool> ReduceMiscompiledBlocks::TestFuncs(const std::vector<BasicBlock *> &BBs) { … } /// 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 Expected<bool> ExtractBlocks(BugDriver &BD, Expected<bool> (*TestFn)(BugDriver &, std::unique_ptr<Module>, std::unique_ptr<Module>), std::vector<Function *> &MiscompiledFunctions) { … } /// This is a generic driver to narrow down miscompilations, either in an /// optimization or a code generator. /// static Expected<std::vector<Function *>> DebugAMiscompilation( BugDriver &BD, Expected<bool> (*TestFn)(BugDriver &, std::unique_ptr<Module>, std::unique_ptr<Module>)) { … } /// This is the predicate function used to check to see if the "Test" portion of /// the program is misoptimized. If so, return true. In any case, both module /// arguments are deleted. /// static Expected<bool> TestOptimizer(BugDriver &BD, std::unique_ptr<Module> Test, std::unique_ptr<Module> Safe) { … } /// debugMiscompilation - This method is used when the passes selected are not /// crashing, but the generated output is semantically different from the /// input. /// Error BugDriver::debugMiscompilation() { … } /// Get the specified modules ready for code generator testing. /// static std::unique_ptr<Module> CleanupAndPrepareModules(BugDriver &BD, std::unique_ptr<Module> Test, Module *Safe) { … } /// This is the predicate function used to check to see if the "Test" portion of /// the program is miscompiled by the code generator under test. If so, return /// true. In any case, both module arguments are deleted. /// static Expected<bool> TestCodeGenerator(BugDriver &BD, std::unique_ptr<Module> Test, std::unique_ptr<Module> Safe) { … } /// debugCodeGenerator - debug errors in LLC, LLI, or CBE. /// Error BugDriver::debugCodeGenerator() { … }