1193323Sed//===-- FindBugs.cpp - Run Many Different Optimizations -------------------===//
2193323Sed//
3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353358Sdim// See https://llvm.org/LICENSE.txt for license information.
5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6193323Sed//
7193323Sed//===----------------------------------------------------------------------===//
8193323Sed//
9314564Sdim// This file defines an interface that allows bugpoint to choose different
10314564Sdim// combinations of optimizations to run on the selected input. Bugpoint will
11193323Sed// run these optimizations and record the success/failure of each. This way
12193323Sed// we can hopefully spot bugs in the optimizations.
13193323Sed//
14193323Sed//===----------------------------------------------------------------------===//
15193323Sed
16193323Sed#include "BugDriver.h"
17261991Sdim#include "llvm/Support/FileSystem.h"
18198090Srdivacky#include "llvm/Support/raw_ostream.h"
19321369Sdim#include <random>
20193323Sedusing namespace llvm;
21193323Sed
22314564SdimError
23314564SdimBugDriver::runManyPasses(const std::vector<std::string> &AllPasses) {
24193323Sed  setPassesToRun(AllPasses);
25198090Srdivacky  outs() << "Starting bug finding procedure...\n\n";
26314564Sdim
27193323Sed  // Creating a reference output if necessary
28314564Sdim  if (Error E = initializeExecutionEnvironment())
29314564Sdim    return E;
30314564Sdim
31198090Srdivacky  outs() << "\n";
32193323Sed  if (ReferenceOutputFile.empty()) {
33198090Srdivacky    outs() << "Generating reference output from raw program: \n";
34341825Sdim    if (Error E = createReferenceFile(*Program))
35314564Sdim      return E;
36193323Sed  }
37314564Sdim
38321369Sdim  std::mt19937 randomness(std::random_device{}());
39193323Sed  unsigned num = 1;
40314564Sdim  while (1) {
41193323Sed    //
42193323Sed    // Step 1: Randomize the order of the optimizer passes.
43193323Sed    //
44321369Sdim    std::shuffle(PassesToRun.begin(), PassesToRun.end(), randomness);
45314564Sdim
46193323Sed    //
47193323Sed    // Step 2: Run optimizer passes on the program and check for success.
48193323Sed    //
49198090Srdivacky    outs() << "Running selected passes on program to test for crash: ";
50314564Sdim    for (int i = 0, e = PassesToRun.size(); i != e; i++) {
51212793Sdim      outs() << "-" << PassesToRun[i] << " ";
52193323Sed    }
53314564Sdim
54193323Sed    std::string Filename;
55341825Sdim    if (runPasses(*Program, PassesToRun, Filename, false)) {
56198090Srdivacky      outs() << "\n";
57198090Srdivacky      outs() << "Optimizer passes caused failure!\n\n";
58314564Sdim      return debugOptimizerCrash();
59193323Sed    } else {
60198090Srdivacky      outs() << "Combination " << num << " optimized successfully!\n";
61193323Sed    }
62314564Sdim
63193323Sed    //
64193323Sed    // Step 3: Compile the optimized code.
65193323Sed    //
66198090Srdivacky    outs() << "Running the code generator to test for a crash: ";
67341825Sdim    if (Error E = compileProgram(*Program)) {
68198090Srdivacky      outs() << "\n*** compileProgram threw an exception: ";
69314564Sdim      outs() << toString(std::move(E));
70314564Sdim      return debugCodeGeneratorCrash();
71193323Sed    }
72207618Srdivacky    outs() << '\n';
73314564Sdim
74193323Sed    //
75314564Sdim    // Step 4: Run the program and compare its output to the reference
76193323Sed    // output (created above).
77193323Sed    //
78198090Srdivacky    outs() << "*** Checking if passes caused miscompliation:\n";
79341825Sdim    Expected<bool> Diff = diffProgram(*Program, Filename, "", false);
80314564Sdim    if (Error E = Diff.takeError()) {
81314564Sdim      errs() << toString(std::move(E));
82314564Sdim      return debugCodeGeneratorCrash();
83314564Sdim    }
84314564Sdim    if (*Diff) {
85207618Srdivacky      outs() << "\n*** diffProgram returned true!\n";
86314564Sdim      Error E = debugMiscompilation();
87314564Sdim      if (!E)
88314564Sdim        return Error::success();
89207618Srdivacky    }
90207618Srdivacky    outs() << "\n*** diff'd output matches!\n";
91314564Sdim
92261991Sdim    sys::fs::remove(Filename);
93314564Sdim
94198090Srdivacky    outs() << "\n\n";
95193323Sed    num++;
96314564Sdim  } // end while
97314564Sdim
98193323Sed  // Unreachable.
99193323Sed}
100