[clang] f10e0f7 - [MergeFuncs] Don't introduce calls to (linkonce,weak)_odr functions. (#125050)
via cfe-commits
cfe-commits at lists.llvm.org
Tue Feb 25 07:55:29 PST 2025
Author: Florian Hahn
Date: 2025-02-25T15:55:25Z
New Revision: f10e0f7321b34693697a0bf895d440f82b32ba54
URL: https://github.com/llvm/llvm-project/commit/f10e0f7321b34693697a0bf895d440f82b32ba54
DIFF: https://github.com/llvm/llvm-project/commit/f10e0f7321b34693697a0bf895d440f82b32ba54.diff
LOG: [MergeFuncs] Don't introduce calls to (linkonce,weak)_odr functions. (#125050)
Avoid creating new calls to linkonce_odr/weak_odr functions when
merging 2 functions, as this may introduce an infinite call
cycle.
Consider 2 functions below, both present in 2 modules.
Module X
--
define linkonce_odr void @"A"() {
call void @"foo"()
}
define linkonce_odr void @"B"() {
call void @"foo"()
}
---
Module Y
---
global @"g" = @"B"
define linkonce_odr void @"A"() {
%l = load @"g"
call void %l()
}
define linkonce_odr void @"B"() {
call void @"foo"()
}
---
@"A" and @"B" in both modules are semantically equivalent
Module X after function merging:
---
define linkonce_odr void @"A"() {
call void @"foo"()
}
define linkonce_odr void @"B"() {
call void @"A"()
}
---
Module Y is unchanged.
Then the linker picks @"A" from module Y and @"B" from module X. Now there's an infinite call cycle
PR: https://github.com/llvm/llvm-project/pull/125050
Added:
Modified:
clang/test/CodeGenCXX/merge-functions.cpp
llvm/lib/Transforms/IPO/MergeFunctions.cpp
llvm/test/Transforms/MergeFunc/comdat.ll
llvm/test/Transforms/MergeFunc/linkonce_odr.ll
llvm/test/Transforms/MergeFunc/merge-linkonce-odr-used.ll
llvm/test/Transforms/MergeFunc/merge-linkonce-odr-weak-odr-mixed-used.ll
llvm/test/Transforms/MergeFunc/merge-linkonce-odr.ll
llvm/test/Transforms/MergeFunc/merge-weak-odr-used.ll
llvm/test/Transforms/MergeFunc/merge-weak-odr.ll
Removed:
################################################################################
diff --git a/clang/test/CodeGenCXX/merge-functions.cpp b/clang/test/CodeGenCXX/merge-functions.cpp
index 892234ceedd37..d3afd8086f41a 100644
--- a/clang/test/CodeGenCXX/merge-functions.cpp
+++ b/clang/test/CodeGenCXX/merge-functions.cpp
@@ -1,6 +1,6 @@
// REQUIRES: x86-registered-target
-// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -O0 -fmerge-functions -emit-llvm -o - -x c++ < %s | FileCheck %s -implicit-check-not=_ZN1A1gEiPi
-// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -O1 -fmerge-functions -emit-llvm -o - -x c++ < %s | FileCheck %s -implicit-check-not=_ZN1A1gEiPi
+// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -O0 -fmerge-functions -emit-llvm -o - -x c++ < %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -O1 -fmerge-functions -emit-llvm -o - -x c++ < %s | FileCheck %s
// Basic functionality test. Function merging doesn't kick in on functions that
// are too simple.
@@ -10,4 +10,8 @@ struct A {
virtual int g(int x, int *p) { return x ? *p : 1; }
} a;
-// CHECK: define {{.*}} @_ZN1A1fEiPi
+// CHECK: define linkonce_odr noundef i32 @_ZN1A1gEiPi(
+// CHECK: tail call noundef i32 @0(
+
+// CHECK: define linkonce_odr noundef i32 @_ZN1A1fEiPi(
+// CHECK: tail call noundef i32 @0(
diff --git a/llvm/lib/Transforms/IPO/MergeFunctions.cpp b/llvm/lib/Transforms/IPO/MergeFunctions.cpp
index e8508416f5427..9cc159830b17d 100644
--- a/llvm/lib/Transforms/IPO/MergeFunctions.cpp
+++ b/llvm/lib/Transforms/IPO/MergeFunctions.cpp
@@ -889,10 +889,20 @@ bool MergeFunctions::writeThunkOrAlias(Function *F, Function *G) {
return false;
}
+/// Returns true if \p F is either weak_odr or linkonce_odr.
+static bool isODR(const Function *F) {
+ return F->hasWeakODRLinkage() || F->hasLinkOnceODRLinkage();
+}
+
// Merge two equivalent functions. Upon completion, Function G is deleted.
void MergeFunctions::mergeTwoFunctions(Function *F, Function *G) {
- if (F->isInterposable()) {
- assert(G->isInterposable());
+
+ // Create a new thunk that both F and G can call, if F cannot call G directly.
+ // That is the case if F is either interposable or if G is either weak_odr or
+ // linkonce_odr.
+ if (F->isInterposable() || (isODR(F) && isODR(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.
@@ -913,6 +923,13 @@ void MergeFunctions::mergeTwoFunctions(Function *F, Function *G) {
removeUsers(F);
F->replaceAllUsesWith(NewF);
+ // If G or NewF are (weak|linkonce)_odr, update all callers to call the
+ // thunk.
+ if (isODR(G))
+ replaceDirectCallers(G, F);
+ if (isODR(F))
+ replaceDirectCallers(NewF, F);
+
// We collect alignment before writeThunkOrAlias that overwrites NewF and
// G's content.
const MaybeAlign NewFAlign = NewF->getAlign();
@@ -986,16 +1003,24 @@ void MergeFunctions::replaceFunctionInTree(const FunctionNode &FN,
// Ordering for functions that are equal under FunctionComparator
static bool isFuncOrderCorrect(const Function *F, const Function *G) {
+ if (isODR(F) != isODR(G)) {
+ // ODR functions before non-ODR functions. A ODR function can call a non-ODR
+ // function if it is not interposable, but not the other way around.
+ return isODR(G);
+ }
+
if (F->isInterposable() != G->isInterposable()) {
// Strong before weak, because the weak function may call the strong
// one, but not the other way around.
return !F->isInterposable();
}
+
if (F->hasLocalLinkage() != G->hasLocalLinkage()) {
// External before local, because we definitely have to keep the external
// function, but may be able to drop the local one.
return !F->hasLocalLinkage();
}
+
// Impose a total order (by name) on the replacement of functions. This is
// important when operating on more than one module independently to prevent
// cycles of thunks calling each other when the modules are linked together.
diff --git a/llvm/test/Transforms/MergeFunc/comdat.ll b/llvm/test/Transforms/MergeFunc/comdat.ll
index f6e104625bc41..3770c772b3f88 100644
--- a/llvm/test/Transforms/MergeFunc/comdat.ll
+++ b/llvm/test/Transforms/MergeFunc/comdat.ll
@@ -19,6 +19,7 @@ define linkonce_odr hidden i32 @g(i32 %x, i32 %y) comdat {
ret i32 %sum3
}
-; CHECK-DAG: define linkonce_odr hidden i32 @f(i32 %x, i32 %y) comdat
-; CHECK-DAG: define linkonce_odr hidden i32 @g(i32 %0, i32 %1) comdat
+; CHECK-DAG: define private i32 @0(i32 %x, i32 %y) comdat($f)
+; CHECK-DAG: define linkonce_odr hidden i32 @g(i32 %0, i32 %1) comdat {
+; CHECK-DAG: define linkonce_odr hidden i32 @f(i32 %0, i32 %1) {
diff --git a/llvm/test/Transforms/MergeFunc/linkonce_odr.ll b/llvm/test/Transforms/MergeFunc/linkonce_odr.ll
index 14b56a8ece30e..ecbe6f08ab8c2 100644
--- a/llvm/test/Transforms/MergeFunc/linkonce_odr.ll
+++ b/llvm/test/Transforms/MergeFunc/linkonce_odr.ll
@@ -7,8 +7,6 @@
; The problem with this is that the linker could then choose these two stubs
; each of the two modules and we end up with two stubs calling each other.
-
-
define linkonce_odr i32 @funC(i32 %x, i32 %y) {
%sum = add i32 %x, %y
%sum2 = add i32 %x, %sum
@@ -37,7 +35,7 @@ define linkonce_odr i32 @funA(i32 %x, i32 %y) {
;.
; CHECK: @take_addr_of_funB = global ptr @funB
;.
-; CHECK-LABEL: define linkonce_odr i32 @funA(
+; CHECK-LABEL: define private i32 @0(
; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
; CHECK-NEXT: [[SUM:%.*]] = add i32 [[X]], [[Y]]
; CHECK-NEXT: [[SUM2:%.*]] = add i32 [[X]], [[SUM]]
@@ -45,8 +43,14 @@ 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 @funA(i32 [[TMP0]], i32 [[TMP1]])
+; CHECK-NEXT: [[TMP3:%.*]] = tail call i32 @[[GLOB0]](i32 [[TMP0]], i32 [[TMP1]])
; CHECK-NEXT: ret i32 [[TMP3]]
;
diff --git a/llvm/test/Transforms/MergeFunc/merge-linkonce-odr-used.ll b/llvm/test/Transforms/MergeFunc/merge-linkonce-odr-used.ll
index fe6a5210454b6..db53a783058d1 100644
--- a/llvm/test/Transforms/MergeFunc/merge-linkonce-odr-used.ll
+++ b/llvm/test/Transforms/MergeFunc/merge-linkonce-odr-used.ll
@@ -41,13 +41,13 @@ declare void @foo(ptr)
;.
; CHECK-LABEL: define void @caller_of_callers(
; CHECK-SAME: ptr [[P:%.*]]) {
-; CHECK-NEXT: call void @linkonce_odr_caller_of_foo_1(ptr [[P]])
-; CHECK-NEXT: call void @linkonce_odr_caller_of_foo_1(ptr [[P]])
-; CHECK-NEXT: call void @linkonce_odr_caller_of_foo_1(ptr [[P]])
+; CHECK-NEXT: call void @[[GLOB0:[0-9]+]](ptr [[P]])
+; CHECK-NEXT: call void @[[GLOB0]](ptr [[P]])
+; CHECK-NEXT: call void @[[GLOB0]](ptr [[P]])
; CHECK-NEXT: ret void
;
;
-; CHECK-LABEL: define linkonce_odr void @linkonce_odr_caller_of_foo_1(
+; CHECK-LABEL: define private void @0(
; CHECK-SAME: ptr [[P:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*:]]
; CHECK-NEXT: tail call void @foo(ptr [[P]])
@@ -58,12 +58,18 @@ declare void @foo(ptr)
;
; CHECK-LABEL: define linkonce_odr void @linkonce_odr_caller_of_foo_2(
; CHECK-SAME: ptr [[TMP0:%.*]]) {
-; CHECK-NEXT: tail call void @linkonce_odr_caller_of_foo_1(ptr [[TMP0]])
+; CHECK-NEXT: tail call void @[[GLOB0]](ptr [[TMP0]])
+; CHECK-NEXT: ret void
+;
+;
+; CHECK-LABEL: define linkonce_odr void @linkonce_odr_caller_of_foo_1(
+; CHECK-SAME: ptr [[TMP0:%.*]]) {
+; CHECK-NEXT: tail call void @[[GLOB0]](ptr [[TMP0]])
; CHECK-NEXT: ret void
;
;
; CHECK-LABEL: define linkonce_odr void @linkonce_odr_caller_of_foo_3(
; CHECK-SAME: ptr [[TMP0:%.*]]) {
-; CHECK-NEXT: tail call void @linkonce_odr_caller_of_foo_1(ptr [[TMP0]])
+; CHECK-NEXT: tail call void @[[GLOB0]](ptr [[TMP0]])
; CHECK-NEXT: ret void
;
diff --git a/llvm/test/Transforms/MergeFunc/merge-linkonce-odr-weak-odr-mixed-used.ll b/llvm/test/Transforms/MergeFunc/merge-linkonce-odr-weak-odr-mixed-used.ll
index 63c6b22424f4c..19f98d93f1ab1 100644
--- a/llvm/test/Transforms/MergeFunc/merge-linkonce-odr-weak-odr-mixed-used.ll
+++ b/llvm/test/Transforms/MergeFunc/merge-linkonce-odr-weak-odr-mixed-used.ll
@@ -41,13 +41,13 @@ declare void @foo(ptr)
;.
; CHECK-LABEL: define void @caller_of_callers(
; CHECK-SAME: ptr [[P:%.*]]) {
-; CHECK-NEXT: call void @linkonce_odr_caller_of_foo_2(ptr [[P]])
-; CHECK-NEXT: call void @linkonce_odr_caller_of_foo_2(ptr [[P]])
-; CHECK-NEXT: call void @linkonce_odr_caller_of_foo_2(ptr [[P]])
+; CHECK-NEXT: call void @[[GLOB0:[0-9]+]](ptr [[P]])
+; CHECK-NEXT: call void @[[GLOB0]](ptr [[P]])
+; CHECK-NEXT: call void @[[GLOB0]](ptr [[P]])
; CHECK-NEXT: ret void
;
;
-; CHECK-LABEL: define linkonce_odr void @linkonce_odr_caller_of_foo_2(
+; CHECK-LABEL: define private void @0(
; CHECK-SAME: ptr [[P:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*:]]
; CHECK-NEXT: tail call void @foo(ptr [[P]])
@@ -58,12 +58,18 @@ declare void @foo(ptr)
;
; CHECK-LABEL: define weak_odr void @weak_odr_caller_of_foo_1(
; CHECK-SAME: ptr [[TMP0:%.*]]) {
-; CHECK-NEXT: tail call void @linkonce_odr_caller_of_foo_2(ptr [[TMP0]])
+; CHECK-NEXT: tail call void @[[GLOB0]](ptr [[TMP0]])
+; CHECK-NEXT: ret void
+;
+;
+; CHECK-LABEL: define linkonce_odr 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 weak_odr void @weak_odr_caller_of_foo_3(
; CHECK-SAME: ptr [[TMP0:%.*]]) {
-; CHECK-NEXT: tail call void @linkonce_odr_caller_of_foo_2(ptr [[TMP0]])
+; CHECK-NEXT: tail call void @[[GLOB0]](ptr [[TMP0]])
; CHECK-NEXT: ret void
;
diff --git a/llvm/test/Transforms/MergeFunc/merge-linkonce-odr.ll b/llvm/test/Transforms/MergeFunc/merge-linkonce-odr.ll
index 13d9fe3f98f28..7e815e1f50d64 100644
--- a/llvm/test/Transforms/MergeFunc/merge-linkonce-odr.ll
+++ b/llvm/test/Transforms/MergeFunc/merge-linkonce-odr.ll
@@ -85,20 +85,21 @@ entry:
}
declare void @zar(ptr)
+
; CHECK-LABEL: define void @caller_of_callers(
; CHECK-SAME: ptr [[P:%.*]]) {
-; CHECK-NEXT: call void @linkonce_odr_caller_of_foo_1(ptr [[P]])
-; CHECK-NEXT: call void @linkonce_odr_caller_of_foo_1(ptr [[P]])
-; CHECK-NEXT: call void @linkonce_odr_caller_of_foo_1(ptr [[P]])
-; CHECK-NEXT: call void @linkonce_odr_caller_of_bar_2(ptr [[P]])
-; CHECK-NEXT: call void @linkonce_odr_caller_of_bar_2(ptr [[P]])
-; CHECK-NEXT: call void @linkonce_odr_caller_of_bar_2(ptr [[P]])
+; CHECK-NEXT: call void @[[GLOB0:[0-9]+]](ptr [[P]])
+; CHECK-NEXT: call void @[[GLOB0]](ptr [[P]])
+; CHECK-NEXT: call void @[[GLOB0]](ptr [[P]])
+; CHECK-NEXT: call void @internal_caller_of_bar_1(ptr [[P]])
+; CHECK-NEXT: call void @internal_caller_of_bar_1(ptr [[P]])
+; CHECK-NEXT: call void @internal_caller_of_bar_1(ptr [[P]])
; CHECK-NEXT: call void @hidden_caller_of_zar_1(ptr [[P]])
; CHECK-NEXT: call void @hidden_caller_of_zar_1(ptr [[P]])
; CHECK-NEXT: ret void
;
;
-; CHECK-LABEL: define linkonce_odr hidden void @linkonce_odr_caller_of_foo_1(
+; CHECK-LABEL: define private void @0(
; CHECK-SAME: ptr [[P:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*:]]
; CHECK-NEXT: tail call void @foo(ptr [[P]])
@@ -107,7 +108,7 @@ declare void @zar(ptr)
; CHECK-NEXT: ret void
;
;
-; CHECK-LABEL: define linkonce_odr hidden void @linkonce_odr_caller_of_bar_2(
+; CHECK-LABEL: define internal void @internal_caller_of_bar_1(
; CHECK-SAME: ptr [[P:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*:]]
; CHECK-NEXT: tail call void @bar(ptr [[P]])
@@ -124,3 +125,15 @@ 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
+;
diff --git a/llvm/test/Transforms/MergeFunc/merge-weak-odr-used.ll b/llvm/test/Transforms/MergeFunc/merge-weak-odr-used.ll
index 6c2b22fd1da7d..601a1275ec2f8 100644
--- a/llvm/test/Transforms/MergeFunc/merge-weak-odr-used.ll
+++ b/llvm/test/Transforms/MergeFunc/merge-weak-odr-used.ll
@@ -41,13 +41,13 @@ declare void @foo(ptr)
;.
; CHECK-LABEL: define void @caller_of_callers(
; CHECK-SAME: ptr [[P:%.*]]) {
-; CHECK-NEXT: call void @weak_odr_caller_of_foo_1(ptr [[P]])
-; CHECK-NEXT: call void @weak_odr_caller_of_foo_1(ptr [[P]])
-; CHECK-NEXT: call void @weak_odr_caller_of_foo_1(ptr [[P]])
+; CHECK-NEXT: call void @[[GLOB0:[0-9]+]](ptr [[P]])
+; CHECK-NEXT: call void @[[GLOB0]](ptr [[P]])
+; CHECK-NEXT: call void @[[GLOB0]](ptr [[P]])
; CHECK-NEXT: ret void
;
;
-; CHECK-LABEL: define weak_odr void @weak_odr_caller_of_foo_1(
+; CHECK-LABEL: define private void @0(
; CHECK-SAME: ptr [[P:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*:]]
; CHECK-NEXT: tail call void @foo(ptr [[P]])
@@ -58,12 +58,18 @@ declare void @foo(ptr)
;
; CHECK-LABEL: define weak_odr void @weak_odr_caller_of_foo_2(
; CHECK-SAME: ptr [[TMP0:%.*]]) {
-; CHECK-NEXT: tail call void @weak_odr_caller_of_foo_1(ptr [[TMP0]])
+; CHECK-NEXT: tail call void @[[GLOB0]](ptr [[TMP0]])
+; CHECK-NEXT: ret void
+;
+;
+; CHECK-LABEL: define weak_odr void @weak_odr_caller_of_foo_1(
+; CHECK-SAME: ptr [[TMP0:%.*]]) {
+; CHECK-NEXT: tail call void @[[GLOB0]](ptr [[TMP0]])
; CHECK-NEXT: ret void
;
;
; CHECK-LABEL: define weak_odr void @weak_odr_caller_of_foo_3(
; CHECK-SAME: ptr [[TMP0:%.*]]) {
-; CHECK-NEXT: tail call void @weak_odr_caller_of_foo_1(ptr [[TMP0]])
+; CHECK-NEXT: tail call void @[[GLOB0]](ptr [[TMP0]])
; CHECK-NEXT: ret void
;
diff --git a/llvm/test/Transforms/MergeFunc/merge-weak-odr.ll b/llvm/test/Transforms/MergeFunc/merge-weak-odr.ll
index 3ea279a411c72..01acad06c50ce 100644
--- a/llvm/test/Transforms/MergeFunc/merge-weak-odr.ll
+++ b/llvm/test/Transforms/MergeFunc/merge-weak-odr.ll
@@ -87,18 +87,18 @@ entry:
declare void @zar(ptr)
; CHECK-LABEL: define void @caller_of_callers(
; CHECK-SAME: ptr [[P:%.*]]) {
-; CHECK-NEXT: call void @weak_odr_caller_of_foo_1(ptr [[P]])
-; CHECK-NEXT: call void @weak_odr_caller_of_foo_1(ptr [[P]])
-; CHECK-NEXT: call void @weak_odr_caller_of_foo_1(ptr [[P]])
-; CHECK-NEXT: call void @weak_odr_caller_of_bar_2(ptr [[P]])
-; CHECK-NEXT: call void @weak_odr_caller_of_bar_2(ptr [[P]])
-; CHECK-NEXT: call void @weak_odr_caller_of_bar_2(ptr [[P]])
+; CHECK-NEXT: call void @[[GLOB0:[0-9]+]](ptr [[P]])
+; CHECK-NEXT: call void @[[GLOB0]](ptr [[P]])
+; CHECK-NEXT: call void @[[GLOB0]](ptr [[P]])
+; CHECK-NEXT: call void @internal_caller_of_bar_1(ptr [[P]])
+; CHECK-NEXT: call void @internal_caller_of_bar_1(ptr [[P]])
+; CHECK-NEXT: call void @internal_caller_of_bar_1(ptr [[P]])
; CHECK-NEXT: call void @hidden_caller_of_zar_1(ptr [[P]])
; CHECK-NEXT: call void @hidden_caller_of_zar_1(ptr [[P]])
; CHECK-NEXT: ret void
;
;
-; CHECK-LABEL: define weak_odr hidden void @weak_odr_caller_of_foo_1(
+; CHECK-LABEL: define private void @0(
; CHECK-SAME: ptr [[P:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*:]]
; CHECK-NEXT: tail call void @foo(ptr [[P]])
@@ -107,7 +107,7 @@ declare void @zar(ptr)
; CHECK-NEXT: ret void
;
;
-; CHECK-LABEL: define weak_odr hidden void @weak_odr_caller_of_bar_2(
+; CHECK-LABEL: define internal void @internal_caller_of_bar_1(
; CHECK-SAME: ptr [[P:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*:]]
; CHECK-NEXT: tail call void @bar(ptr [[P]])
@@ -127,19 +127,31 @@ declare void @zar(ptr)
;
; CHECK-LABEL: define weak_odr hidden void @weak_odr_caller_of_foo_2(
; CHECK-SAME: ptr [[TMP0:%.*]]) {
-; CHECK-NEXT: tail call void @weak_odr_caller_of_foo_1(ptr [[TMP0]])
+; CHECK-NEXT: tail call void @[[GLOB0]](ptr [[TMP0]])
+; CHECK-NEXT: ret void
+;
+;
+; CHECK-LABEL: define weak_odr hidden void @weak_odr_caller_of_foo_1(
+; CHECK-SAME: ptr [[TMP0:%.*]]) {
+; CHECK-NEXT: tail call void @[[GLOB0]](ptr [[TMP0]])
; CHECK-NEXT: ret void
;
;
; CHECK-LABEL: define weak_odr hidden void @weak_odr_caller_of_foo_3(
; CHECK-SAME: ptr [[TMP0:%.*]]) {
-; CHECK-NEXT: tail call void @weak_odr_caller_of_foo_1(ptr [[TMP0]])
+; CHECK-NEXT: tail call void @[[GLOB0]](ptr [[TMP0]])
+; CHECK-NEXT: ret void
+;
+;
+; CHECK-LABEL: define weak_odr hidden void @weak_odr_caller_of_bar_2(
+; CHECK-SAME: ptr [[TMP0:%.*]]) {
+; CHECK-NEXT: tail call void @internal_caller_of_bar_1(ptr [[TMP0]])
; CHECK-NEXT: ret void
;
;
; CHECK-LABEL: define weak_odr hidden void @weak_odr_caller_of_bar_3(
; CHECK-SAME: ptr [[TMP0:%.*]]) {
-; CHECK-NEXT: tail call void @weak_odr_caller_of_bar_2(ptr [[TMP0]])
+; CHECK-NEXT: tail call void @internal_caller_of_bar_1(ptr [[TMP0]])
; CHECK-NEXT: ret void
;
;
More information about the cfe-commits
mailing list