mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2025-04-02 15:51:54 +00:00

Summary: Fixes http://lab.llvm.org:8011/builders/sanitizer-x86_64-linux-bootstrap-msan/builds/14002 and http://lab.llvm.org:8011/builders/lld-x86_64-darwin13/builds/35392/steps/build_Lld/logs/stdio Subscribers: mgorny, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D65843 llvm-svn: 368117
171 lines
5.4 KiB
C++
171 lines
5.4 KiB
C++
//===- Delta.cpp - Delta Debugging Algorithm Implementation ---------------===//
|
|
//
|
|
// 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 contains the implementation for the Delta Debugging Algorithm:
|
|
// it splits a given set of Targets (i.e. Functions, Instructions, BBs, etc.)
|
|
// into chunks and tries to reduce the number chunks that are interesting.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "Delta.h"
|
|
|
|
/// Writes IR code to the given Filepath
|
|
static bool writeProgramToFile(StringRef Filepath, int FD, const Module &M) {
|
|
ToolOutputFile Out(Filepath, FD);
|
|
M.print(Out.os(), /*AnnotationWriter=*/nullptr);
|
|
Out.os().close();
|
|
|
|
if (!Out.os().has_error()) {
|
|
Out.keep();
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/// Creates a temporary (and unique) file inside the tmp folder and writes
|
|
/// the given module IR.
|
|
static SmallString<128> createTmpFile(Module *M, StringRef TmpDir) {
|
|
SmallString<128> UniqueFilepath;
|
|
int UniqueFD;
|
|
|
|
std::error_code EC = sys::fs::createUniqueFile(TmpDir + "/tmp-%%%.ll",
|
|
UniqueFD, UniqueFilepath);
|
|
if (EC) {
|
|
errs() << "Error making unique filename: " << EC.message() << "!\n";
|
|
exit(1);
|
|
}
|
|
|
|
if (writeProgramToFile(UniqueFilepath, UniqueFD, *M)) {
|
|
errs() << "Error emitting bitcode to file '" << UniqueFilepath << "'!\n";
|
|
exit(1);
|
|
}
|
|
return UniqueFilepath;
|
|
}
|
|
|
|
/// Prints the Chunk Indexes with the following format: [start, end], if
|
|
/// chunk is at minimum size (1), then it just displays [start].
|
|
static void printChunks(std::vector<Chunk> Chunks, bool Oneline = false) {
|
|
for (auto C : Chunks) {
|
|
if (!Oneline)
|
|
outs() << '\t';
|
|
outs() << "[" << C.begin;
|
|
if (C.end - C.begin != 0)
|
|
outs() << "," << C.end;
|
|
outs() << "]";
|
|
if (!Oneline)
|
|
outs() << '\n';
|
|
}
|
|
}
|
|
|
|
/// Counts the amount of lines for a given file
|
|
static unsigned getLines(StringRef Filepath) {
|
|
unsigned Lines = 0;
|
|
std::string CurrLine;
|
|
std::ifstream FileStream(Filepath);
|
|
|
|
while (std::getline(FileStream, CurrLine))
|
|
++Lines;
|
|
|
|
return Lines;
|
|
}
|
|
|
|
/// Splits Chunks in half and prints them.
|
|
/// If unable to split (when chunk size is 1) returns false.
|
|
static bool increaseGranularity(std::vector<Chunk> &Chunks) {
|
|
outs() << "Increasing granularity...";
|
|
std::vector<Chunk> NewChunks;
|
|
bool SplitOne = false;
|
|
|
|
for (auto &C : Chunks) {
|
|
if (C.end - C.begin == 0)
|
|
NewChunks.push_back(C);
|
|
else {
|
|
unsigned Half = (C.begin + C.end) / 2;
|
|
NewChunks.push_back({C.begin, Half});
|
|
NewChunks.push_back({Half + 1, C.end});
|
|
SplitOne = true;
|
|
}
|
|
}
|
|
if (SplitOne) {
|
|
Chunks = NewChunks;
|
|
outs() << "Success! New Chunks:\n";
|
|
printChunks(Chunks);
|
|
}
|
|
return SplitOne;
|
|
}
|
|
|
|
void llvm::runDeltaPass(
|
|
TestRunner &Test, unsigned Targets,
|
|
std::function<std::unique_ptr<Module>(std::vector<Chunk>, Module *)>
|
|
ExtractChunksFromModule) {
|
|
if (!Targets)
|
|
return;
|
|
|
|
std::vector<Chunk> Chunks = {{1, Targets}};
|
|
std::set<Chunk> UninterestingChunks;
|
|
std::unique_ptr<Module> ReducedProgram;
|
|
|
|
if (!Test.run(Test.getReducedFilepath()) || !increaseGranularity(Chunks)) {
|
|
outs() << "\nCouldn't reduce\n";
|
|
outs() << "----------------------------\n";
|
|
return;
|
|
}
|
|
|
|
do {
|
|
UninterestingChunks = {};
|
|
for (int I = Chunks.size() - 1; I >= 0; --I) {
|
|
std::vector<Chunk> CurrentChunks;
|
|
|
|
for (auto C : Chunks)
|
|
if (!UninterestingChunks.count(C) && C != Chunks[I])
|
|
CurrentChunks.push_back(C);
|
|
|
|
if (CurrentChunks.empty())
|
|
break;
|
|
|
|
// Generate Module with only Targets inside Current Chunks
|
|
std::unique_ptr<Module> CurrentProgram =
|
|
ExtractChunksFromModule(CurrentChunks, Test.getProgram());
|
|
// Write Module to tmp file
|
|
SmallString<128> CurrentFilepath =
|
|
createTmpFile(CurrentProgram.get(), Test.getTmpDir());
|
|
|
|
outs() << "Testing with: ";
|
|
printChunks(CurrentChunks, /*Oneline=*/true);
|
|
outs() << " | " << sys::path::filename(CurrentFilepath);
|
|
|
|
// Current Chunks aren't interesting
|
|
if (!Test.run(CurrentFilepath)) {
|
|
outs() << "\n";
|
|
continue;
|
|
}
|
|
// We only care about interesting chunks if they reduce the testcase
|
|
if (getLines(CurrentFilepath) < getLines(Test.getReducedFilepath())) {
|
|
UninterestingChunks.insert(Chunks[I]);
|
|
Test.setReducedFilepath(CurrentFilepath);
|
|
ReducedProgram = std::move(CurrentProgram);
|
|
outs() << " **** SUCCESS | lines: " << getLines(CurrentFilepath);
|
|
}
|
|
outs() << "\n";
|
|
}
|
|
// Delete uninteresting chunks
|
|
auto UnwantedChunks = Chunks.end();
|
|
UnwantedChunks = std::remove_if(Chunks.begin(), Chunks.end(),
|
|
[UninterestingChunks](const Chunk &C) {
|
|
return UninterestingChunks.count(C);
|
|
});
|
|
Chunks.erase(UnwantedChunks, Chunks.end());
|
|
|
|
} while (!UninterestingChunks.empty() || increaseGranularity(Chunks));
|
|
|
|
// If we reduced the testcase replace it
|
|
if (ReducedProgram)
|
|
Test.setProgram(std::move(ReducedProgram));
|
|
outs() << "Couldn't increase anymore.\n";
|
|
outs() << "----------------------------\n";
|
|
} |