1*0b57cec5SDimitry Andric //===-- FindBugs.cpp - Run Many Different Optimizations -------------------===// 2*0b57cec5SDimitry Andric // 3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*0b57cec5SDimitry Andric // 7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 8*0b57cec5SDimitry Andric // 9*0b57cec5SDimitry Andric // This file defines an interface that allows bugpoint to choose different 10*0b57cec5SDimitry Andric // combinations of optimizations to run on the selected input. Bugpoint will 11*0b57cec5SDimitry Andric // run these optimizations and record the success/failure of each. This way 12*0b57cec5SDimitry Andric // we can hopefully spot bugs in the optimizations. 13*0b57cec5SDimitry Andric // 14*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 15*0b57cec5SDimitry Andric 16*0b57cec5SDimitry Andric #include "BugDriver.h" 17*0b57cec5SDimitry Andric #include "llvm/Support/FileSystem.h" 18*0b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h" 19*0b57cec5SDimitry Andric #include <random> 20*0b57cec5SDimitry Andric using namespace llvm; 21*0b57cec5SDimitry Andric 22*0b57cec5SDimitry Andric Error 23*0b57cec5SDimitry Andric BugDriver::runManyPasses(const std::vector<std::string> &AllPasses) { 24*0b57cec5SDimitry Andric setPassesToRun(AllPasses); 25*0b57cec5SDimitry Andric outs() << "Starting bug finding procedure...\n\n"; 26*0b57cec5SDimitry Andric 27*0b57cec5SDimitry Andric // Creating a reference output if necessary 28*0b57cec5SDimitry Andric if (Error E = initializeExecutionEnvironment()) 29*0b57cec5SDimitry Andric return E; 30*0b57cec5SDimitry Andric 31*0b57cec5SDimitry Andric outs() << "\n"; 32*0b57cec5SDimitry Andric if (ReferenceOutputFile.empty()) { 33*0b57cec5SDimitry Andric outs() << "Generating reference output from raw program: \n"; 34*0b57cec5SDimitry Andric if (Error E = createReferenceFile(*Program)) 35*0b57cec5SDimitry Andric return E; 36*0b57cec5SDimitry Andric } 37*0b57cec5SDimitry Andric 38*0b57cec5SDimitry Andric std::mt19937 randomness(std::random_device{}()); 39*0b57cec5SDimitry Andric unsigned num = 1; 40*0b57cec5SDimitry Andric while (1) { 41*0b57cec5SDimitry Andric // 42*0b57cec5SDimitry Andric // Step 1: Randomize the order of the optimizer passes. 43*0b57cec5SDimitry Andric // 44*0b57cec5SDimitry Andric std::shuffle(PassesToRun.begin(), PassesToRun.end(), randomness); 45*0b57cec5SDimitry Andric 46*0b57cec5SDimitry Andric // 47*0b57cec5SDimitry Andric // Step 2: Run optimizer passes on the program and check for success. 48*0b57cec5SDimitry Andric // 49*0b57cec5SDimitry Andric outs() << "Running selected passes on program to test for crash: "; 50*0b57cec5SDimitry Andric for (int i = 0, e = PassesToRun.size(); i != e; i++) { 51*0b57cec5SDimitry Andric outs() << "-" << PassesToRun[i] << " "; 52*0b57cec5SDimitry Andric } 53*0b57cec5SDimitry Andric 54*0b57cec5SDimitry Andric std::string Filename; 55*0b57cec5SDimitry Andric if (runPasses(*Program, PassesToRun, Filename, false)) { 56*0b57cec5SDimitry Andric outs() << "\n"; 57*0b57cec5SDimitry Andric outs() << "Optimizer passes caused failure!\n\n"; 58*0b57cec5SDimitry Andric return debugOptimizerCrash(); 59*0b57cec5SDimitry Andric } else { 60*0b57cec5SDimitry Andric outs() << "Combination " << num << " optimized successfully!\n"; 61*0b57cec5SDimitry Andric } 62*0b57cec5SDimitry Andric 63*0b57cec5SDimitry Andric // 64*0b57cec5SDimitry Andric // Step 3: Compile the optimized code. 65*0b57cec5SDimitry Andric // 66*0b57cec5SDimitry Andric outs() << "Running the code generator to test for a crash: "; 67*0b57cec5SDimitry Andric if (Error E = compileProgram(*Program)) { 68*0b57cec5SDimitry Andric outs() << "\n*** compileProgram threw an exception: "; 69*0b57cec5SDimitry Andric outs() << toString(std::move(E)); 70*0b57cec5SDimitry Andric return debugCodeGeneratorCrash(); 71*0b57cec5SDimitry Andric } 72*0b57cec5SDimitry Andric outs() << '\n'; 73*0b57cec5SDimitry Andric 74*0b57cec5SDimitry Andric // 75*0b57cec5SDimitry Andric // Step 4: Run the program and compare its output to the reference 76*0b57cec5SDimitry Andric // output (created above). 77*0b57cec5SDimitry Andric // 78*0b57cec5SDimitry Andric outs() << "*** Checking if passes caused miscompliation:\n"; 79*0b57cec5SDimitry Andric Expected<bool> Diff = diffProgram(*Program, Filename, "", false); 80*0b57cec5SDimitry Andric if (Error E = Diff.takeError()) { 81*0b57cec5SDimitry Andric errs() << toString(std::move(E)); 82*0b57cec5SDimitry Andric return debugCodeGeneratorCrash(); 83*0b57cec5SDimitry Andric } 84*0b57cec5SDimitry Andric if (*Diff) { 85*0b57cec5SDimitry Andric outs() << "\n*** diffProgram returned true!\n"; 86*0b57cec5SDimitry Andric Error E = debugMiscompilation(); 87*0b57cec5SDimitry Andric if (!E) 88*0b57cec5SDimitry Andric return Error::success(); 89*0b57cec5SDimitry Andric } 90*0b57cec5SDimitry Andric outs() << "\n*** diff'd output matches!\n"; 91*0b57cec5SDimitry Andric 92*0b57cec5SDimitry Andric sys::fs::remove(Filename); 93*0b57cec5SDimitry Andric 94*0b57cec5SDimitry Andric outs() << "\n\n"; 95*0b57cec5SDimitry Andric num++; 96*0b57cec5SDimitry Andric } // end while 97*0b57cec5SDimitry Andric 98*0b57cec5SDimitry Andric // Unreachable. 99*0b57cec5SDimitry Andric } 100