Skip to content

Commit 1c9ca7d

Browse files
author
Diego Trevino Ferrer
committed
[Bugpoint redesign] Added Pass to Remove Global Variables
Summary: This pass tries to remove Global Variables, as well as their derived uses. For example if a variable `@x` is used by `%call1` and `%call2`, both these uses and the definition of `@x` are deleted. Moreover if `%call1` or `%call2` are used elsewhere those uses are also deleted, and so on recursively. I'm still uncertain if this pass should remove derived uses, I'm open to suggestions. Subscribers: mgorny, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D64176 llvm-svn: 368115
1 parent 8d5c280 commit 1c9ca7d

13 files changed

+385
-206
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#!/bin/sh
2+
3+
matches=$(cat $1 | grep "@interesting = global" | wc -l)
4+
5+
if [[ $matches > 0 ]]; then
6+
exit 0
7+
else
8+
exit 1
9+
fi
+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
; Test that llvm-reduce can remove uninteresting Global Variables as well as
2+
; their direct uses.
3+
;
4+
; RUN: llvm-reduce --test %p/Inputs/remove-global-vars.sh %s
5+
; RUN: cat reduced.ll | FileCheck %s
6+
; REQUIRES: plugins, shell
7+
8+
@uninteresting1 = global i32 0, align 4
9+
; CHECK: @interesting = global
10+
@interesting = global i32 5, align 4
11+
; CHECK-NOT: global
12+
@uninteresting2 = global i32 25, align 4
13+
@uninteresting3 = global i32 50, align 4
14+
15+
define i32 @main() {
16+
entry:
17+
%retval = alloca i32, align 4
18+
store i32 0, i32* %retval, align 4
19+
; CHECK-NOT: load i32, i32* @uninteresting2, align 4
20+
%0 = load i32, i32* @uninteresting2, align 4
21+
store i32 %0, i32* @interesting, align 4
22+
; CHECK-NOT: load i32, i32* @uninteresting3, align 4
23+
%1 = load i32, i32* @uninteresting3, align 4
24+
%dec = add nsw i32 %1, -1
25+
; CHECK-NOT: store i32 %dec, i32* @uninteresting3, align 4
26+
store i32 %dec, i32* @uninteresting3, align 4
27+
; CHECK: load i32, i32* @interesting, align 4
28+
%2 = load i32, i32* @interesting, align 4
29+
; CHECK-NOT: load i32, i32* @uninteresting2, align 4
30+
%3 = load i32, i32* @uninteresting2, align 4
31+
%add = add nsw i32 %2, %3
32+
; CHECK-NOT: store i32 %add, i32* @uninteresting1, align 4
33+
store i32 %add, i32* @uninteresting1, align 4
34+
store i32 10, i32* @interesting, align 4
35+
; CHECK: load i32, i32* @interesting, align 4
36+
%4 = load i32, i32* @interesting, align 4
37+
ret i32 0
38+
}

llvm/tools/llvm-reduce/CMakeLists.txt

+2
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@ set(LLVM_NO_DEAD_STRIP 1)
1515
add_llvm_tool(llvm-reduce
1616
llvm-reduce.cpp
1717
TestRunner.cpp
18+
deltas/Delta.cpp
1819
deltas/RemoveFunctions.cpp
20+
deltas/RemoveGlobalVars.cpp
1921

2022
DEPENDS
2123
intrinsics_gen

llvm/tools/llvm-reduce/DeltaManager.h

+9-5
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,30 @@
1-
//===- llvm-reduce.cpp - The LLVM Delta Reduction utility -----------------===//
1+
//===- DeltaManager.h - Runs Delta Passes to reduce Input -----------------===//
22
//
33
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
44
// See https://llvm.org/LICENSE.txt for license information.
55
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
66
//
77
//===----------------------------------------------------------------------===//
88
//
9-
// This class calls each specialized Delta pass by passing it as a template to
10-
// the generic Delta Pass.
9+
// This file calls each specialized Delta pass in order to reduce the input IR
10+
// file.
1111
//
1212
//===----------------------------------------------------------------------===//
1313

1414
#include "TestRunner.h"
1515
#include "deltas/Delta.h"
1616
#include "deltas/RemoveFunctions.h"
17+
#include "deltas/RemoveGlobalVars.h"
1718

1819
namespace llvm {
1920

2021
inline void runDeltaPasses(TestRunner &Tester) {
22+
// TODO: Add option to only call certain delta passes
2123
outs() << "Reducing functions...\n";
22-
Delta<RemoveFunctions>::run(Tester);
23-
// TODO: Implement the rest of the Delta Passes
24+
removeFunctionsDeltaPass(Tester);
25+
outs() << "Reducing GVs...\n";
26+
removeGlobalsDeltaPass(Tester);
27+
// TODO: Implement the remaining Delta Passes
2428
}
2529

2630
} // namespace llvm

llvm/tools/llvm-reduce/TestRunner.cpp

+8
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
1+
//===-- TestRunner.cpp ----------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
19
#include "TestRunner.h"
210

311
using namespace llvm;

llvm/tools/llvm-reduce/TestRunner.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//===- llvm-reduce.cpp - The LLVM Delta Reduction utility -----------------===//
1+
//===-- tools/llvm-reduce/TestRunner.h ---------------------------*- C++ -*-===/
22
//
33
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
44
// See https://llvm.org/LICENSE.txt for license information.
+171
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
//===- Delta.cpp - Delta Debugging Algorithm Implementation ---------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// This file contains the implementation for the Delta Debugging Algorithm:
10+
// it splits a given set of Targets (i.e. Functions, Instructions, BBs, etc.)
11+
// into chunks and tries to reduce the number chunks that are interesting.
12+
//
13+
//===----------------------------------------------------------------------===//
14+
15+
#include "Delta.h"
16+
17+
/// Writes IR code to the given Filepath
18+
static bool writeProgramToFile(StringRef Filepath, int FD, const Module &M) {
19+
ToolOutputFile Out(Filepath, FD);
20+
M.print(Out.os(), /*AnnotationWriter=*/nullptr);
21+
Out.os().close();
22+
23+
if (!Out.os().has_error()) {
24+
Out.keep();
25+
return false;
26+
}
27+
return true;
28+
}
29+
30+
/// Creates a temporary (and unique) file inside the tmp folder and writes
31+
/// the given module IR.
32+
static SmallString<128> createTmpFile(Module *M, StringRef TmpDir) {
33+
SmallString<128> UniqueFilepath;
34+
int UniqueFD;
35+
36+
std::error_code EC = sys::fs::createUniqueFile(TmpDir + "/tmp-%%%.ll",
37+
UniqueFD, UniqueFilepath);
38+
if (EC) {
39+
errs() << "Error making unique filename: " << EC.message() << "!\n";
40+
exit(1);
41+
}
42+
43+
if (writeProgramToFile(UniqueFilepath, UniqueFD, *M)) {
44+
errs() << "Error emitting bitcode to file '" << UniqueFilepath << "'!\n";
45+
exit(1);
46+
}
47+
return UniqueFilepath;
48+
}
49+
50+
/// Prints the Chunk Indexes with the following format: [start, end], if
51+
/// chunk is at minimum size (1), then it just displays [start].
52+
static void printChunks(std::vector<Chunk> Chunks, bool Oneline = false) {
53+
for (auto C : Chunks) {
54+
if (!Oneline)
55+
outs() << '\t';
56+
outs() << "[" << C.begin;
57+
if (C.end - C.begin != 0)
58+
outs() << "," << C.end;
59+
outs() << "]";
60+
if (!Oneline)
61+
outs() << '\n';
62+
}
63+
}
64+
65+
/// Counts the amount of lines for a given file
66+
static unsigned getLines(StringRef Filepath) {
67+
unsigned Lines = 0;
68+
std::string CurrLine;
69+
std::ifstream FileStream(Filepath);
70+
71+
while (std::getline(FileStream, CurrLine))
72+
++Lines;
73+
74+
return Lines;
75+
}
76+
77+
/// Splits Chunks in half and prints them.
78+
/// If unable to split (when chunk size is 1) returns false.
79+
static bool increaseGranularity(std::vector<Chunk> &Chunks) {
80+
outs() << "Increasing granularity...";
81+
std::vector<Chunk> NewChunks;
82+
bool SplitOne = false;
83+
84+
for (auto &C : Chunks) {
85+
if (C.end - C.begin == 0)
86+
NewChunks.push_back(C);
87+
else {
88+
int Half = (C.begin + C.end) / 2;
89+
NewChunks.push_back({C.begin, Half});
90+
NewChunks.push_back({Half + 1, C.end});
91+
SplitOne = true;
92+
}
93+
}
94+
if (SplitOne) {
95+
Chunks = NewChunks;
96+
outs() << "Success! New Chunks:\n";
97+
printChunks(Chunks);
98+
}
99+
return SplitOne;
100+
}
101+
102+
void llvm::runDeltaPass(
103+
TestRunner &Test, int Targets,
104+
std::function<std::unique_ptr<Module>(std::vector<Chunk>, Module *)>
105+
ExtractChunksFromModule) {
106+
if (!Targets)
107+
return;
108+
109+
std::vector<Chunk> Chunks = {{1, Targets}};
110+
std::set<Chunk> UninterestingChunks;
111+
std::unique_ptr<Module> ReducedProgram;
112+
113+
if (!Test.run(Test.getReducedFilepath()) || !increaseGranularity(Chunks)) {
114+
outs() << "\nCouldn't reduce\n";
115+
outs() << "----------------------------\n";
116+
return;
117+
}
118+
119+
do {
120+
UninterestingChunks = {};
121+
for (int I = Chunks.size() - 1; I >= 0; --I) {
122+
std::vector<Chunk> CurrentChunks;
123+
124+
for (auto C : Chunks)
125+
if (!UninterestingChunks.count(C) && C != Chunks[I])
126+
CurrentChunks.push_back(C);
127+
128+
if (CurrentChunks.empty())
129+
break;
130+
131+
// Generate Module with only Targets inside Current Chunks
132+
std::unique_ptr<Module> CurrentProgram =
133+
ExtractChunksFromModule(CurrentChunks, Test.getProgram());
134+
// Write Module to tmp file
135+
SmallString<128> CurrentFilepath =
136+
createTmpFile(CurrentProgram.get(), Test.getTmpDir());
137+
138+
outs() << "Testing with: ";
139+
printChunks(CurrentChunks, /*Oneline=*/true);
140+
outs() << " | " << sys::path::filename(CurrentFilepath);
141+
142+
// Current Chunks aren't interesting
143+
if (!Test.run(CurrentFilepath)) {
144+
outs() << "\n";
145+
continue;
146+
}
147+
// We only care about interesting chunks if they reduce the testcase
148+
if (getLines(CurrentFilepath) < getLines(Test.getReducedFilepath())) {
149+
UninterestingChunks.insert(Chunks[I]);
150+
Test.setReducedFilepath(CurrentFilepath);
151+
ReducedProgram = std::move(CurrentProgram);
152+
outs() << " **** SUCCESS | lines: " << getLines(CurrentFilepath);
153+
}
154+
outs() << "\n";
155+
}
156+
// Delete uninteresting chunks
157+
auto UnwantedChunks = Chunks.end();
158+
UnwantedChunks = std::remove_if(Chunks.begin(), Chunks.end(),
159+
[UninterestingChunks](const Chunk &C) {
160+
return UninterestingChunks.count(C);
161+
});
162+
Chunks.erase(UnwantedChunks, Chunks.end());
163+
164+
} while (!UninterestingChunks.empty() || increaseGranularity(Chunks));
165+
166+
// If we reduced the testcase replace it
167+
if (ReducedProgram)
168+
Test.setProgram(std::move(ReducedProgram));
169+
outs() << "Couldn't increase anymore.\n";
170+
outs() << "----------------------------\n";
171+
}

0 commit comments

Comments
 (0)