1
+ // ===- MergeFunctionsTest.cpp - Unit tests for MergeFunctionsPass ---------===//
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
+ #include " llvm/Transforms/IPO/MergeFunctions.h"
10
+
11
+ #include " llvm/ADT/SetVector.h"
12
+ #include " llvm/AsmParser/Parser.h"
13
+ #include " llvm/IR/LLVMContext.h"
14
+ #include " llvm/IR/Module.h"
15
+ #include " llvm/Support/SourceMgr.h"
16
+ #include " gtest/gtest.h"
17
+ #include < memory>
18
+
19
+ using namespace llvm ;
20
+
21
+ namespace {
22
+
23
+ TEST (MergeFunctions, TrueOutputModuleTest) {
24
+ LLVMContext Ctx;
25
+ SMDiagnostic Err;
26
+ std::unique_ptr<Module> M (parseAssemblyString (R"invalid(
27
+ @.str = private unnamed_addr constant [10 x i8] c"On f: %d\0A\00", align 1
28
+ @.str.1 = private unnamed_addr constant [13 x i8] c"On main: %d\0A\00", align 1
29
+
30
+ define dso_local i32 @f(i32 noundef %arg) {
31
+ entry:
32
+ %add109 = call i32 @_slice_add10(i32 %arg)
33
+ %call = call i32 (ptr, ...) @printf(ptr noundef @.str, i32 noundef %add109)
34
+ ret i32 %add109
35
+ }
36
+
37
+ declare i32 @printf(ptr noundef, ...)
38
+
39
+ define dso_local i32 @main(i32 noundef %argc, ptr noundef %argv) {
40
+ entry:
41
+ %add99 = call i32 @_slice_add10(i32 %argc)
42
+ %call = call i32 @f(i32 noundef 2)
43
+ %sub = sub nsw i32 %call, 6
44
+ %call10 = call i32 (ptr, ...) @printf(ptr noundef @.str.1, i32 noundef %add99)
45
+ ret i32 %add99
46
+ }
47
+
48
+ define internal i32 @_slice_add10(i32 %arg) {
49
+ sliceclone_entry:
50
+ %0 = mul nsw i32 %arg, %arg
51
+ %1 = mul nsw i32 %0, 2
52
+ %2 = mul nsw i32 %1, 2
53
+ %3 = mul nsw i32 %2, 2
54
+ %4 = add nsw i32 %3, 2
55
+ ret i32 %4
56
+ }
57
+
58
+ define internal i32 @_slice_add10_alt(i32 %arg) {
59
+ sliceclone_entry:
60
+ %0 = mul nsw i32 %arg, %arg
61
+ %1 = mul nsw i32 %0, 2
62
+ %2 = mul nsw i32 %1, 2
63
+ %3 = mul nsw i32 %2, 2
64
+ %4 = add nsw i32 %3, 2
65
+ ret i32 %4
66
+ }
67
+ )invalid" ,
68
+ Err, Ctx));
69
+
70
+ // Expects true after merging _slice_add10 and _slice_add10_alt
71
+ EXPECT_TRUE (MergeFunctionsPass::runOnModule (*M));
72
+ }
73
+
74
+ TEST (MergeFunctions, TrueOutputFunctionsTest) {
75
+ LLVMContext Ctx;
76
+ SMDiagnostic Err;
77
+ std::unique_ptr<Module> M (parseAssemblyString (R"invalid(
78
+ @.str = private unnamed_addr constant [10 x i8] c"On f: %d\0A\00", align 1
79
+ @.str.1 = private unnamed_addr constant [13 x i8] c"On main: %d\0A\00", align 1
80
+
81
+ define dso_local i32 @f(i32 noundef %arg) {
82
+ entry:
83
+ %add109 = call i32 @_slice_add10(i32 %arg)
84
+ %call = call i32 (ptr, ...) @printf(ptr noundef @.str, i32 noundef %add109)
85
+ ret i32 %add109
86
+ }
87
+
88
+ declare i32 @printf(ptr noundef, ...)
89
+
90
+ define dso_local i32 @main(i32 noundef %argc, ptr noundef %argv) {
91
+ entry:
92
+ %add99 = call i32 @_slice_add10(i32 %argc)
93
+ %call = call i32 @f(i32 noundef 2)
94
+ %sub = sub nsw i32 %call, 6
95
+ %call10 = call i32 (ptr, ...) @printf(ptr noundef @.str.1, i32 noundef %add99)
96
+ ret i32 %add99
97
+ }
98
+
99
+ define internal i32 @_slice_add10(i32 %arg) {
100
+ sliceclone_entry:
101
+ %0 = mul nsw i32 %arg, %arg
102
+ %1 = mul nsw i32 %0, 2
103
+ %2 = mul nsw i32 %1, 2
104
+ %3 = mul nsw i32 %2, 2
105
+ %4 = add nsw i32 %3, 2
106
+ ret i32 %4
107
+ }
108
+
109
+ define internal i32 @_slice_add10_alt(i32 %arg) {
110
+ sliceclone_entry:
111
+ %0 = mul nsw i32 %arg, %arg
112
+ %1 = mul nsw i32 %0, 2
113
+ %2 = mul nsw i32 %1, 2
114
+ %3 = mul nsw i32 %2, 2
115
+ %4 = add nsw i32 %3, 2
116
+ ret i32 %4
117
+ }
118
+ )invalid" ,
119
+ Err, Ctx));
120
+
121
+ SetVector<Function *> FunctionsSet;
122
+ for (Function &F : *M)
123
+ FunctionsSet.insert (&F);
124
+
125
+ DenseMap<Function *, Function *> MergeResult =
126
+ MergeFunctionsPass::runOnFunctions (FunctionsSet.getArrayRef ());
127
+
128
+ // Expects that both functions (_slice_add10 and _slice_add10_alt)
129
+ // be mapped to the same new function
130
+ EXPECT_TRUE (!MergeResult.empty ());
131
+ Function *NewFunction = M->getFunction (" _slice_add10" );
132
+ for (auto P : MergeResult)
133
+ if (P.second )
134
+ EXPECT_EQ (P.second , NewFunction);
135
+ }
136
+
137
+ TEST (MergeFunctions, FalseOutputModuleTest) {
138
+ LLVMContext Ctx;
139
+ SMDiagnostic Err;
140
+ std::unique_ptr<Module> M (parseAssemblyString (R"invalid(
141
+ @.str = private unnamed_addr constant [10 x i8] c"On f: %d\0A\00", align 1
142
+ @.str.1 = private unnamed_addr constant [13 x i8] c"On main: %d\0A\00", align 1
143
+
144
+ define dso_local i32 @f(i32 noundef %arg) {
145
+ entry:
146
+ %add109 = call i32 @_slice_add10(i32 %arg)
147
+ %call = call i32 (ptr, ...) @printf(ptr noundef @.str, i32 noundef %add109)
148
+ ret i32 %add109
149
+ }
150
+
151
+ declare i32 @printf(ptr noundef, ...)
152
+
153
+ define dso_local i32 @main(i32 noundef %argc, ptr noundef %argv) {
154
+ entry:
155
+ %add99 = call i32 @_slice_add10(i32 %argc)
156
+ %call = call i32 @f(i32 noundef 2)
157
+ %sub = sub nsw i32 %call, 6
158
+ %call10 = call i32 (ptr, ...) @printf(ptr noundef @.str.1, i32 noundef %add99)
159
+ ret i32 %add99
160
+ }
161
+
162
+ define internal i32 @_slice_add10(i32 %arg) {
163
+ sliceclone_entry:
164
+ %0 = mul nsw i32 %arg, %arg
165
+ %1 = mul nsw i32 %0, 2
166
+ %2 = mul nsw i32 %1, 2
167
+ %3 = mul nsw i32 %2, 2
168
+ %4 = add nsw i32 %3, 2
169
+ ret i32 %4
170
+ }
171
+
172
+ define internal i32 @_slice_add10_alt(i32 %arg) {
173
+ sliceclone_entry:
174
+ %0 = mul nsw i32 %arg, %arg
175
+ %1 = mul nsw i32 %0, 2
176
+ %2 = mul nsw i32 %1, 2
177
+ %3 = mul nsw i32 %2, 2
178
+ %4 = add nsw i32 %3, 2
179
+ ret i32 %0
180
+ }
181
+ )invalid" ,
182
+ Err, Ctx));
183
+
184
+ // Expects false after trying to merge _slice_add10 and _slice_add10_alt
185
+ EXPECT_FALSE (MergeFunctionsPass::runOnModule (*M));
186
+ }
187
+
188
+ TEST (MergeFunctions, FalseOutputFunctionsTest) {
189
+ LLVMContext Ctx;
190
+ SMDiagnostic Err;
191
+ std::unique_ptr<Module> M (parseAssemblyString (R"invalid(
192
+ @.str = private unnamed_addr constant [10 x i8] c"On f: %d\0A\00", align 1
193
+ @.str.1 = private unnamed_addr constant [13 x i8] c"On main: %d\0A\00", align 1
194
+
195
+ define dso_local i32 @f(i32 noundef %arg) {
196
+ entry:
197
+ %add109 = call i32 @_slice_add10(i32 %arg)
198
+ %call = call i32 (ptr, ...) @printf(ptr noundef @.str, i32 noundef %add109)
199
+ ret i32 %add109
200
+ }
201
+
202
+ declare i32 @printf(ptr noundef, ...)
203
+
204
+ define dso_local i32 @main(i32 noundef %argc, ptr noundef %argv) {
205
+ entry:
206
+ %add99 = call i32 @_slice_add10(i32 %argc)
207
+ %call = call i32 @f(i32 noundef 2)
208
+ %sub = sub nsw i32 %call, 6
209
+ %call10 = call i32 (ptr, ...) @printf(ptr noundef @.str.1, i32 noundef %add99)
210
+ ret i32 %add99
211
+ }
212
+
213
+ define internal i32 @_slice_add10(i32 %arg) {
214
+ sliceclone_entry:
215
+ %0 = mul nsw i32 %arg, %arg
216
+ %1 = mul nsw i32 %0, 2
217
+ %2 = mul nsw i32 %1, 2
218
+ %3 = mul nsw i32 %2, 2
219
+ %4 = add nsw i32 %3, 2
220
+ ret i32 %4
221
+ }
222
+
223
+ define internal i32 @_slice_add10_alt(i32 %arg) {
224
+ sliceclone_entry:
225
+ %0 = mul nsw i32 %arg, %arg
226
+ %1 = mul nsw i32 %0, 2
227
+ %2 = mul nsw i32 %1, 2
228
+ %3 = mul nsw i32 %2, 2
229
+ %4 = add nsw i32 %3, 2
230
+ ret i32 %0
231
+ }
232
+ )invalid" ,
233
+ Err, Ctx));
234
+
235
+ SetVector<Function *> FunctionsSet;
236
+ for (Function &F : *M)
237
+ FunctionsSet.insert (&F);
238
+
239
+ DenseMap<Function *, Function *> MergeResult =
240
+ MergeFunctionsPass::runOnFunctions (FunctionsSet.getArrayRef ());
241
+
242
+ // Expects empty map
243
+ EXPECT_EQ (MergeResult.size (), 0u );
244
+ }
245
+
246
+ } // namespace
0 commit comments