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