246 lines · cpp
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-exception6//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 19using namespace llvm;20 21namespace {22 23TEST(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 128 @.str.1 = private unnamed_addr constant [13 x i8] c"On main: %d\0A\00", align 129 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 %add10935 }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, 644 %call10 = call i32 (ptr, ...) @printf(ptr noundef @.str.1, i32 noundef %add99)45 ret i32 %add9946 }47 48 define internal i32 @_slice_add10(i32 %arg) {49 sliceclone_entry:50 %0 = mul nsw i32 %arg, %arg51 %1 = mul nsw i32 %0, 252 %2 = mul nsw i32 %1, 253 %3 = mul nsw i32 %2, 254 %4 = add nsw i32 %3, 255 ret i32 %456 }57 58 define internal i32 @_slice_add10_alt(i32 %arg) {59 sliceclone_entry:60 %0 = mul nsw i32 %arg, %arg61 %1 = mul nsw i32 %0, 262 %2 = mul nsw i32 %1, 263 %3 = mul nsw i32 %2, 264 %4 = add nsw i32 %3, 265 ret i32 %466 }67 )invalid",68 Err, Ctx));69 70 // Expects true after merging _slice_add10 and _slice_add10_alt71 EXPECT_TRUE(MergeFunctionsPass::runOnModule(*M));72}73 74TEST(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 179 @.str.1 = private unnamed_addr constant [13 x i8] c"On main: %d\0A\00", align 180 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 %add10986 }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, 695 %call10 = call i32 (ptr, ...) @printf(ptr noundef @.str.1, i32 noundef %add99)96 ret i32 %add9997 }98 99 define internal i32 @_slice_add10(i32 %arg) {100 sliceclone_entry:101 %0 = mul nsw i32 %arg, %arg102 %1 = mul nsw i32 %0, 2103 %2 = mul nsw i32 %1, 2104 %3 = mul nsw i32 %2, 2105 %4 = add nsw i32 %3, 2106 ret i32 %4107 }108 109 define internal i32 @_slice_add10_alt(i32 %arg) {110 sliceclone_entry:111 %0 = mul nsw i32 %arg, %arg112 %1 = mul nsw i32 %0, 2113 %2 = mul nsw i32 %1, 2114 %3 = mul nsw i32 %2, 2115 %4 = add nsw i32 %3, 2116 ret i32 %4117 }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 function130 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 137TEST(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 1142 @.str.1 = private unnamed_addr constant [13 x i8] c"On main: %d\0A\00", align 1143 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 %add109149 }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, 6158 %call10 = call i32 (ptr, ...) @printf(ptr noundef @.str.1, i32 noundef %add99)159 ret i32 %add99160 }161 162 define internal i32 @_slice_add10(i32 %arg) {163 sliceclone_entry:164 %0 = mul nsw i32 %arg, %arg165 %1 = mul nsw i32 %0, 2166 %2 = mul nsw i32 %1, 2167 %3 = mul nsw i32 %2, 2168 %4 = add nsw i32 %3, 2169 ret i32 %4170 }171 172 define internal i32 @_slice_add10_alt(i32 %arg) {173 sliceclone_entry:174 %0 = mul nsw i32 %arg, %arg175 %1 = mul nsw i32 %0, 2176 %2 = mul nsw i32 %1, 2177 %3 = mul nsw i32 %2, 2178 %4 = add nsw i32 %3, 2179 ret i32 %0180 }181 )invalid",182 Err, Ctx));183 184 // Expects false after trying to merge _slice_add10 and _slice_add10_alt185 EXPECT_FALSE(MergeFunctionsPass::runOnModule(*M));186}187 188TEST(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 1193 @.str.1 = private unnamed_addr constant [13 x i8] c"On main: %d\0A\00", align 1194 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 %add109200 }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, 6209 %call10 = call i32 (ptr, ...) @printf(ptr noundef @.str.1, i32 noundef %add99)210 ret i32 %add99211 }212 213 define internal i32 @_slice_add10(i32 %arg) {214 sliceclone_entry:215 %0 = mul nsw i32 %arg, %arg216 %1 = mul nsw i32 %0, 2217 %2 = mul nsw i32 %1, 2218 %3 = mul nsw i32 %2, 2219 %4 = add nsw i32 %3, 2220 ret i32 %4221 }222 223 define internal i32 @_slice_add10_alt(i32 %arg) {224 sliceclone_entry:225 %0 = mul nsw i32 %arg, %arg226 %1 = mul nsw i32 %0, 2227 %2 = mul nsw i32 %1, 2228 %3 = mul nsw i32 %2, 2229 %4 = add nsw i32 %3, 2230 ret i32 %0231 }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 map243 EXPECT_EQ(MergeResult.size(), 0u);244}245 246} // namespace