diff --git a/llvm/lib/Transforms/IPO/MergeFunctions.cpp b/llvm/lib/Transforms/IPO/MergeFunctions.cpp index 9cc159830b17d..d2443a83535e4 100644 --- a/llvm/lib/Transforms/IPO/MergeFunctions.cpp +++ b/llvm/lib/Transforms/IPO/MergeFunctions.cpp @@ -283,9 +283,10 @@ class MergeFunctions { // Replace G with an alias to F (deleting function G) void writeAlias(Function *F, Function *G); - // Replace G with an alias to F if possible, or a thunk to F if possible. - // Returns false if neither is the case. - bool writeThunkOrAlias(Function *F, Function *G); + // If needed, replace G with an alias to F if possible, or a thunk to F if + // profitable. Returns false if neither is the case. If \p G is not needed + // (i.e. it is discardable and not used), \p G is removed directly. + bool writeThunkOrAliasIfNeeded(Function *F, Function *G); /// Replace function F with function G in the function tree. void replaceFunctionInTree(const FunctionNode &FN, Function *G); @@ -875,9 +876,14 @@ void MergeFunctions::writeAlias(Function *F, Function *G) { ++NumAliasesWritten; } -// Replace G with an alias to F if possible, or a thunk to F if -// profitable. Returns false if neither is the case. -bool MergeFunctions::writeThunkOrAlias(Function *F, Function *G) { +// If needed, replace G with an alias to F if possible, or a thunk to F if +// profitable. Returns false if neither is the case. If \p G is not needed (i.e. +// it is discardable and unused), \p G is removed directly. +bool MergeFunctions::writeThunkOrAliasIfNeeded(Function *F, Function *G) { + if (G->isDiscardableIfUnused() && G->use_empty() && !MergeFunctionsPDI) { + G->eraseFromParent(); + return true; + } if (canCreateAliasFor(G)) { writeAlias(F, G); return true; @@ -904,9 +910,10 @@ void MergeFunctions::mergeTwoFunctions(Function *F, Function *G) { assert((!isODR(G) || isODR(F)) && "if G is ODR, F must also be ODR due to ordering"); - // Both writeThunkOrAlias() calls below must succeed, either because we can - // create aliases for G and NewF, or because a thunk for F is profitable. - // F here has the same signature as NewF below, so that's what we check. + // Both writeThunkOrAliasIfNeeded() calls below must succeed, either because + // we can create aliases for G and NewF, or because a thunk for F is + // profitable. F here has the same signature as NewF below, so that's what + // we check. if (!canCreateThunkFor(F) && (!canCreateAliasFor(F) || !canCreateAliasFor(G))) return; @@ -930,13 +937,13 @@ void MergeFunctions::mergeTwoFunctions(Function *F, Function *G) { if (isODR(F)) replaceDirectCallers(NewF, F); - // We collect alignment before writeThunkOrAlias that overwrites NewF and - // G's content. + // We collect alignment before writeThunkOrAliasIfNeeded that overwrites + // NewF and G's content. const MaybeAlign NewFAlign = NewF->getAlign(); const MaybeAlign GAlign = G->getAlign(); - writeThunkOrAlias(F, G); - writeThunkOrAlias(F, NewF); + writeThunkOrAliasIfNeeded(F, G); + writeThunkOrAliasIfNeeded(F, NewF); if (NewFAlign || GAlign) F->setAlignment(std::max(NewFAlign.valueOrOne(), GAlign.valueOrOne())); @@ -975,7 +982,7 @@ void MergeFunctions::mergeTwoFunctions(Function *F, Function *G) { return; } - if (writeThunkOrAlias(F, G)) { + if (writeThunkOrAliasIfNeeded(F, G)) { ++NumFunctionsMerged; } } diff --git a/llvm/test/Transforms/MergeFunc/linkonce.ll b/llvm/test/Transforms/MergeFunc/linkonce.ll index 2f648edc62408..567139d97a387 100644 --- a/llvm/test/Transforms/MergeFunc/linkonce.ll +++ b/llvm/test/Transforms/MergeFunc/linkonce.ll @@ -1,5 +1,4 @@ -; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals all --include-generated-funcs --version 5 -; RUN: opt -S -passes=mergefunc < %s | FileCheck %s -implicit-check-not=funC +; RUN: opt -S -passes=mergefunc < %s | FileCheck %s -implicit-check-not=funA -implicit-check-not=funC ; Replacments should be totally ordered on the function name. ; If we don't do this we can end up with one module defining a thunk for @funA @@ -43,14 +42,8 @@ define linkonce i32 @funA(i32 %x, i32 %y) { ; CHECK-NEXT: ret i32 [[SUM3]] ; ; -; CHECK-LABEL: define linkonce i32 @funC( -; CHECK-SAME: i32 [[TMP0:%.*]], i32 [[TMP1:%.*]]) { -; CHECK-NEXT: [[TMP3:%.*]] = tail call i32 @[[GLOB0:[0-9]+]](i32 [[TMP0]], i32 [[TMP1]]) -; CHECK-NEXT: ret i32 [[TMP3]] -; -; ; CHECK-LABEL: define linkonce i32 @funB( ; CHECK-SAME: i32 [[TMP0:%.*]], i32 [[TMP1:%.*]]) { -; CHECK-NEXT: [[TMP3:%.*]] = tail call i32 @[[GLOB0]](i32 [[TMP0]], i32 [[TMP1]]) +; CHECK-NEXT: [[TMP3:%.*]] = tail call i32 @0(i32 [[TMP0]], i32 [[TMP1]]) ; CHECK-NEXT: ret i32 [[TMP3]] ; diff --git a/llvm/test/Transforms/MergeFunc/linkonce_odr.ll b/llvm/test/Transforms/MergeFunc/linkonce_odr.ll index ecbe6f08ab8c2..a1cae60685da1 100644 --- a/llvm/test/Transforms/MergeFunc/linkonce_odr.ll +++ b/llvm/test/Transforms/MergeFunc/linkonce_odr.ll @@ -1,5 +1,4 @@ -; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals all --include-generated-funcs --version 5 -; RUN: opt -S -passes=mergefunc < %s | FileCheck %s -implicit-check-not=funC +; RUN: opt -S -passes=mergefunc < %s | FileCheck %s -implicit-check-not=funA -implicit-check-not=funC ; Replacments should be totally ordered on the function name. ; If we don't do this we can end up with one module defining a thunk for @funA @@ -43,14 +42,8 @@ define linkonce_odr i32 @funA(i32 %x, i32 %y) { ; CHECK-NEXT: ret i32 [[SUM3]] ; ; -; CHECK-LABEL: define linkonce_odr i32 @funC( -; CHECK-SAME: i32 [[TMP0:%.*]], i32 [[TMP1:%.*]]) { -; CHECK-NEXT: [[TMP3:%.*]] = tail call i32 @[[GLOB0:[0-9]+]](i32 [[TMP0]], i32 [[TMP1]]) -; CHECK-NEXT: ret i32 [[TMP3]] -; -; ; CHECK-LABEL: define linkonce_odr i32 @funB( ; CHECK-SAME: i32 [[TMP0:%.*]], i32 [[TMP1:%.*]]) { -; CHECK-NEXT: [[TMP3:%.*]] = tail call i32 @[[GLOB0]](i32 [[TMP0]], i32 [[TMP1]]) +; CHECK-NEXT: [[TMP3:%.*]] = tail call i32 @0(i32 [[TMP0]], i32 [[TMP1]]) ; CHECK-NEXT: ret i32 [[TMP3]] ; diff --git a/llvm/test/Transforms/MergeFunc/merge-linkonce-odr.ll b/llvm/test/Transforms/MergeFunc/merge-linkonce-odr.ll index 7e815e1f50d64..1a622bfae72c4 100644 --- a/llvm/test/Transforms/MergeFunc/merge-linkonce-odr.ll +++ b/llvm/test/Transforms/MergeFunc/merge-linkonce-odr.ll @@ -1,5 +1,5 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals all --include-generated-funcs --version 5 -; RUN: opt -p mergefunc -S %s | FileCheck %s +; RUN: opt -p mergefunc -S %s | FileCheck --implicit-check-not=linkonce_odr_caller_of_foo_2 --implicit-check-not=linkonce_odr_caller_of_foo_1 %s define void @caller_of_callers(ptr %p) { call void @linkonce_odr_caller_of_foo_1(ptr %p) @@ -125,15 +125,3 @@ declare void @zar(ptr) ; CHECK-NEXT: tail call void @zar(ptr [[P]]) ; CHECK-NEXT: ret void ; -; -; CHECK-LABEL: define linkonce_odr hidden void @linkonce_odr_caller_of_foo_2( -; CHECK-SAME: ptr [[TMP0:%.*]]) { -; CHECK-NEXT: tail call void @[[GLOB0]](ptr [[TMP0]]) -; CHECK-NEXT: ret void -; -; -; CHECK-LABEL: define linkonce_odr hidden void @linkonce_odr_caller_of_foo_1( -; CHECK-SAME: ptr [[TMP0:%.*]]) { -; CHECK-NEXT: tail call void @[[GLOB0]](ptr [[TMP0]]) -; CHECK-NEXT: ret void -;