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