10b57cec5SDimitry Andric //===-- FindBugs.cpp - Run Many Different Optimizations -------------------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // This file defines an interface that allows bugpoint to choose different 100b57cec5SDimitry Andric // combinations of optimizations to run on the selected input. Bugpoint will 110b57cec5SDimitry Andric // run these optimizations and record the success/failure of each. This way 120b57cec5SDimitry Andric // we can hopefully spot bugs in the optimizations. 130b57cec5SDimitry Andric // 140b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 150b57cec5SDimitry Andric 160b57cec5SDimitry Andric #include "BugDriver.h" 170b57cec5SDimitry Andric #include "llvm/Support/FileSystem.h" 180b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h" 190b57cec5SDimitry Andric #include <random> 200b57cec5SDimitry Andric using namespace llvm; 210b57cec5SDimitry Andric 220b57cec5SDimitry Andric Error 230b57cec5SDimitry Andric BugDriver::runManyPasses(const std::vector<std::string> &AllPasses) { 240b57cec5SDimitry Andric setPassesToRun(AllPasses); 250b57cec5SDimitry Andric outs() << "Starting bug finding procedure...\n\n"; 260b57cec5SDimitry Andric 270b57cec5SDimitry Andric // Creating a reference output if necessary 280b57cec5SDimitry Andric if (Error E = initializeExecutionEnvironment()) 290b57cec5SDimitry Andric return E; 300b57cec5SDimitry Andric 310b57cec5SDimitry Andric outs() << "\n"; 320b57cec5SDimitry Andric if (ReferenceOutputFile.empty()) { 330b57cec5SDimitry Andric outs() << "Generating reference output from raw program: \n"; 340b57cec5SDimitry Andric if (Error E = createReferenceFile(*Program)) 350b57cec5SDimitry Andric return E; 360b57cec5SDimitry Andric } 370b57cec5SDimitry Andric 380b57cec5SDimitry Andric std::mt19937 randomness(std::random_device{}()); 390b57cec5SDimitry Andric unsigned num = 1; 400b57cec5SDimitry Andric while (1) { 410b57cec5SDimitry Andric // 420b57cec5SDimitry Andric // Step 1: Randomize the order of the optimizer passes. 430b57cec5SDimitry Andric // 44*fe6060f1SDimitry Andric llvm::shuffle(PassesToRun.begin(), PassesToRun.end(), randomness); 450b57cec5SDimitry Andric 460b57cec5SDimitry Andric // 470b57cec5SDimitry Andric // Step 2: Run optimizer passes on the program and check for success. 480b57cec5SDimitry Andric // 490b57cec5SDimitry Andric outs() << "Running selected passes on program to test for crash: "; 500b57cec5SDimitry Andric for (int i = 0, e = PassesToRun.size(); i != e; i++) { 510b57cec5SDimitry Andric outs() << "-" << PassesToRun[i] << " "; 520b57cec5SDimitry Andric } 530b57cec5SDimitry Andric 540b57cec5SDimitry Andric std::string Filename; 550b57cec5SDimitry Andric if (runPasses(*Program, PassesToRun, Filename, false)) { 560b57cec5SDimitry Andric outs() << "\n"; 570b57cec5SDimitry Andric outs() << "Optimizer passes caused failure!\n\n"; 580b57cec5SDimitry Andric return debugOptimizerCrash(); 590b57cec5SDimitry Andric } else { 600b57cec5SDimitry Andric outs() << "Combination " << num << " optimized successfully!\n"; 610b57cec5SDimitry Andric } 620b57cec5SDimitry Andric 630b57cec5SDimitry Andric // 640b57cec5SDimitry Andric // Step 3: Compile the optimized code. 650b57cec5SDimitry Andric // 660b57cec5SDimitry Andric outs() << "Running the code generator to test for a crash: "; 670b57cec5SDimitry Andric if (Error E = compileProgram(*Program)) { 680b57cec5SDimitry Andric outs() << "\n*** compileProgram threw an exception: "; 690b57cec5SDimitry Andric outs() << toString(std::move(E)); 700b57cec5SDimitry Andric return debugCodeGeneratorCrash(); 710b57cec5SDimitry Andric } 720b57cec5SDimitry Andric outs() << '\n'; 730b57cec5SDimitry Andric 740b57cec5SDimitry Andric // 750b57cec5SDimitry Andric // Step 4: Run the program and compare its output to the reference 760b57cec5SDimitry Andric // output (created above). 770b57cec5SDimitry Andric // 780b57cec5SDimitry Andric outs() << "*** Checking if passes caused miscompliation:\n"; 790b57cec5SDimitry Andric Expected<bool> Diff = diffProgram(*Program, Filename, "", false); 800b57cec5SDimitry Andric if (Error E = Diff.takeError()) { 810b57cec5SDimitry Andric errs() << toString(std::move(E)); 820b57cec5SDimitry Andric return debugCodeGeneratorCrash(); 830b57cec5SDimitry Andric } 840b57cec5SDimitry Andric if (*Diff) { 850b57cec5SDimitry Andric outs() << "\n*** diffProgram returned true!\n"; 860b57cec5SDimitry Andric Error E = debugMiscompilation(); 870b57cec5SDimitry Andric if (!E) 880b57cec5SDimitry Andric return Error::success(); 890b57cec5SDimitry Andric } 900b57cec5SDimitry Andric outs() << "\n*** diff'd output matches!\n"; 910b57cec5SDimitry Andric 920b57cec5SDimitry Andric sys::fs::remove(Filename); 930b57cec5SDimitry Andric 940b57cec5SDimitry Andric outs() << "\n\n"; 950b57cec5SDimitry Andric num++; 960b57cec5SDimitry Andric } // end while 970b57cec5SDimitry Andric 980b57cec5SDimitry Andric // Unreachable. 990b57cec5SDimitry Andric } 100