xref: /llvm-project/llvm/unittests/Transforms/IPO/MergeFunctionsTest.cpp (revision b96e7570c991f1bb67646a20427a83f247326a25)
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