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