Skip to content

Commit a193673

Browse files
authored
Enable multiple 'src'/'tgt' pairs in a single source (#902)
Change: Instead of only searching for 'src' and 'tgt' in single-file mode, search for an arbitrary number of pairs of 'src{+d}'/'tgt{+d}' or 'src_*'/'tgt_*'. I.e. if have the following functions in a file: ``` define @src {} define @tgt {} define @src2 {} define @tgt2 {} define @src_foo {} define @tgt_foo {} define @src4 {} define @tgt_bar {} ``` Alive2 will have the following pairs: 'src'/'tgt', 'src2'/'tgt2', and 'src_foo'/'tgt_bar'. It will ignore 'src4' and 'tgt_bar'. Motivation: This just a QOL change. A lot of LLVM patches have associated alive2 links. In some cases there need to be many links (i.e. https://reviews.llvm.org/D149521). Being able to specify multiple 'src'/'tgt' pairs in a single file would enable verifying multiple cases with a single link making it easier.
1 parent b301169 commit a193673

File tree

4 files changed

+170
-7
lines changed

4 files changed

+170
-7
lines changed
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
declare i8 @llvm.ssub.sat.i8(i8, i8)
2+
define i1 @src(i8 %x, i8 %y) {
3+
%m = call i8 @llvm.ssub.sat.i8(i8 %x, i8 %y)
4+
%r = icmp eq i8 %m, 0
5+
ret i1 %r
6+
}
7+
8+
define i1 @tgt(i8 %x, i8 %y) {
9+
%r = icmp eq i8 %x, %y
10+
ret i1 %r
11+
}
12+
13+
define i1 @src1(i8 %x, i8 %y) {
14+
%m = call i8 @llvm.ssub.sat.i8(i8 %x, i8 %y)
15+
%r = icmp ne i8 %m, 0
16+
ret i1 %r
17+
}
18+
19+
define i1 @tgt1(i8 %x, i8 %y) {
20+
%r = icmp ne i8 %x, %y
21+
ret i1 %r
22+
}
23+
24+
define i1 @src2(i8 %x, i8 %y) {
25+
%m = call i8 @llvm.ssub.sat.i8(i8 %x, i8 %y)
26+
%r = icmp sle i8 %m, 0
27+
ret i1 %r
28+
}
29+
30+
define i1 @tgt2(i8 %x, i8 %y) {
31+
%r = icmp sle i8 %x, %y
32+
ret i1 %r
33+
}
34+
35+
define i1 @src3(i8 %x, i8 %y) {
36+
%m = call i8 @llvm.ssub.sat.i8(i8 %x, i8 %y)
37+
%r = icmp slt i8 %m, 0
38+
ret i1 %r
39+
}
40+
41+
define i1 @tgt3(i8 %x, i8 %y) {
42+
%r = icmp slt i8 %x, %y
43+
ret i1 %r
44+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
declare i8 @llvm.ssub.sat.i8(i8, i8)
2+
define i1 @src_sge(i8 %x, i8 %y) {
3+
%m = call i8 @llvm.ssub.sat.i8(i8 %x, i8 %y)
4+
%r = icmp sge i8 %m, 0
5+
ret i1 %r
6+
}
7+
8+
define i1 @tgt_sge(i8 %x, i8 %y) {
9+
%r = icmp sge i8 %x, %y
10+
ret i1 %r
11+
}
12+
13+
define i1 @src_sgt(i8 %x, i8 %y) {
14+
%m = call i8 @llvm.ssub.sat.i8(i8 %x, i8 %y)
15+
%r = icmp sgt i8 %m, 0
16+
ret i1 %r
17+
}
18+
19+
define i1 @tgt_sgt(i8 %x, i8 %y) {
20+
%r = icmp sgt i8 %x, %y
21+
ret i1 %r
22+
}
23+
24+
; unused
25+
define i1 @src(i8 %x, i8 %y) {
26+
%m = call i8 @llvm.ssub.sat.i8(i8 %x, i8 %y)
27+
%r = icmp sgt i8 %m, 0
28+
ret i1 %r
29+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
define i8 @src(i8 %x) {
2+
%m = sub i8 %x, -1
3+
ret i8 %m
4+
}
5+
6+
define i8 @tgt(i8 %x) {
7+
%m = xor i8 %x, -1
8+
ret i8 %m
9+
}
10+
11+
; Transformation doesn't verify!
12+
13+
define i8 @src3(i8 %x) {
14+
%m = sub i8 0, %x
15+
ret i8 %m
16+
}
17+
18+
define i8 @tgt3(i8 %x) {
19+
%m = xor i8 %x, -1
20+
ret i8 %m
21+
}
22+
23+
; Transformation doesn't verify!
24+
25+
define i8 @src9(i8 %x) {
26+
%m = sub i8 -1, %x
27+
ret i8 %m
28+
}
29+
30+
define i8 @tgt9(i8 %x) {
31+
%m = xor i8 %x, -1
32+
ret i8 %m
33+
}
34+
35+
; Transformation seems to be correct!
36+
37+
define i8 @src4(i8 %x, i8 %y) {
38+
%m = add i8 %y, %x
39+
ret i8 %m
40+
}
41+
42+
define i8 @tgt4(i8 %x) {
43+
%m = xor i8 %x, -1
44+
ret i8 %m
45+
}
46+
47+
; ERROR: Signature mismatch between src and tgt

tools/alive-tv.cpp

Lines changed: 50 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,14 @@ alive-tv will optimize the entire module using an optimization
106106
pipeline similar to -O2, and then verify that functions in the
107107
optimized module refine those in the original one. This provides a
108108
convenient way to demonstrate an existing optimizer bug.
109+
110+
Multiple "src" and "tgt" functions can be specified in the same file
111+
by postfixing, after "src" and "tgt", either a unique integer or an
112+
'_' followed by an arbitrary string. For example if the file contains
113+
the following functions "src", "tgt", "src4", "tgt4", "src_foo",
114+
"tgt_foo", "src_bar", "tgt5", then the pairs "src" <-> "tgt", "src4"
115+
<-> "tgt4", and "src_foo" <-> "tgt_foo" will be verifed but "src_bar"
116+
and "tgt5" will unused.
109117
)EOF";
110118

111119
llvm::cl::HideUnrelatedOptions(alive_cmdargs);
@@ -134,18 +142,53 @@ convenient way to demonstrate an existing optimizer bug.
134142

135143
unique_ptr<llvm::Module> M2;
136144
if (opt_file2.empty()) {
137-
auto SRC = findFunction(*M1, opt_src_fn);
138-
auto TGT = findFunction(*M1, opt_tgt_fn);
139-
if (SRC && TGT) {
140-
verifier.compareFunctions(*SRC, *TGT);
141-
goto end;
142-
} else {
145+
unsigned Cnt = 0;
146+
for (auto &F1 : *M1.get()) {
147+
if (F1.isDeclaration())
148+
continue;
149+
auto SrcFName = F1.getName();
150+
if (!SrcFName.startswith(opt_src_fn))
151+
continue;
152+
153+
// Check src{+d}/tgt{+d} variant
154+
if (std::find_if(SrcFName.begin() + opt_src_fn.length(), SrcFName.end(),
155+
[](unsigned char c) { return !std::isdigit(c); }) ==
156+
SrcFName.end()) {
157+
// Pass, we found a valid postfix
158+
}
159+
// Check src_*/tgt_* variant
160+
else if (SrcFName.str().length() > opt_src_fn.length() &&
161+
SrcFName[opt_src_fn.length()] == '_') {
162+
// Pass, we found a valid postfix
163+
}
164+
// No valid postfix.
165+
else {
166+
continue;
167+
}
168+
169+
// Check if we have tgt + same postfix
170+
auto DstFName =
171+
SrcFName.str().replace(0, opt_src_fn.length(), opt_tgt_fn);
172+
auto SRC = findFunction(*M1, SrcFName.str());
173+
auto TGT = findFunction(*M1, DstFName);
174+
if (SRC && TGT) {
175+
++Cnt;
176+
if (!verifier.compareFunctions(*SRC, *TGT))
177+
if (opt_error_fatal)
178+
goto end;
179+
}
180+
}
181+
if (Cnt == 0) {
143182
M2 = CloneModule(*M1);
144183
auto err = optimize_module(M2.get(), optPass);
145184
if (!err.empty()) {
146185
*out << "Error parsing list of LLVM passes: " << err << '\n';
147186
return -1;
148187
}
188+
} else if (Cnt > 1) {
189+
goto summary;
190+
} else {
191+
goto end;
149192
}
150193
} else {
151194
M2 = openInputFile(Context, opt_file2);
@@ -184,7 +227,7 @@ convenient way to demonstrate an existing optimizer bug.
184227
}
185228
}
186229
}
187-
230+
summary:
188231
*out << "Summary:\n"
189232
" " << verifier.num_correct << " correct transformations\n"
190233
" " << verifier.num_unsound << " incorrect transformations\n"

0 commit comments

Comments
 (0)