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