Skip to content

Commit f10e0f7

Browse files
authored
[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: #125050
1 parent 5fd1888 commit f10e0f7

File tree

9 files changed

+125
-48
lines changed

9 files changed

+125
-48
lines changed
Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// REQUIRES: x86-registered-target
2-
// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -O0 -fmerge-functions -emit-llvm -o - -x c++ < %s | FileCheck %s -implicit-check-not=_ZN1A1gEiPi
3-
// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -O1 -fmerge-functions -emit-llvm -o - -x c++ < %s | FileCheck %s -implicit-check-not=_ZN1A1gEiPi
2+
// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -O0 -fmerge-functions -emit-llvm -o - -x c++ < %s | FileCheck %s
3+
// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -O1 -fmerge-functions -emit-llvm -o - -x c++ < %s | FileCheck %s
44

55
// Basic functionality test. Function merging doesn't kick in on functions that
66
// are too simple.
@@ -10,4 +10,8 @@ struct A {
1010
virtual int g(int x, int *p) { return x ? *p : 1; }
1111
} a;
1212

13-
// CHECK: define {{.*}} @_ZN1A1fEiPi
13+
// CHECK: define linkonce_odr noundef i32 @_ZN1A1gEiPi(
14+
// CHECK: tail call noundef i32 @0(
15+
16+
// CHECK: define linkonce_odr noundef i32 @_ZN1A1fEiPi(
17+
// CHECK: tail call noundef i32 @0(

llvm/lib/Transforms/IPO/MergeFunctions.cpp

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -889,10 +889,20 @@ bool MergeFunctions::writeThunkOrAlias(Function *F, Function *G) {
889889
return false;
890890
}
891891

892+
/// Returns true if \p F is either weak_odr or linkonce_odr.
893+
static bool isODR(const Function *F) {
894+
return F->hasWeakODRLinkage() || F->hasLinkOnceODRLinkage();
895+
}
896+
892897
// Merge two equivalent functions. Upon completion, Function G is deleted.
893898
void MergeFunctions::mergeTwoFunctions(Function *F, Function *G) {
894-
if (F->isInterposable()) {
895-
assert(G->isInterposable());
899+
900+
// Create a new thunk that both F and G can call, if F cannot call G directly.
901+
// That is the case if F is either interposable or if G is either weak_odr or
902+
// linkonce_odr.
903+
if (F->isInterposable() || (isODR(F) && isODR(G))) {
904+
assert((!isODR(G) || isODR(F)) &&
905+
"if G is ODR, F must also be ODR due to ordering");
896906

897907
// Both writeThunkOrAlias() calls below must succeed, either because we can
898908
// 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) {
913923
removeUsers(F);
914924
F->replaceAllUsesWith(NewF);
915925

926+
// If G or NewF are (weak|linkonce)_odr, update all callers to call the
927+
// thunk.
928+
if (isODR(G))
929+
replaceDirectCallers(G, F);
930+
if (isODR(F))
931+
replaceDirectCallers(NewF, F);
932+
916933
// We collect alignment before writeThunkOrAlias that overwrites NewF and
917934
// G's content.
918935
const MaybeAlign NewFAlign = NewF->getAlign();
@@ -986,16 +1003,24 @@ void MergeFunctions::replaceFunctionInTree(const FunctionNode &FN,
9861003

9871004
// Ordering for functions that are equal under FunctionComparator
9881005
static bool isFuncOrderCorrect(const Function *F, const Function *G) {
1006+
if (isODR(F) != isODR(G)) {
1007+
// ODR functions before non-ODR functions. A ODR function can call a non-ODR
1008+
// function if it is not interposable, but not the other way around.
1009+
return isODR(G);
1010+
}
1011+
9891012
if (F->isInterposable() != G->isInterposable()) {
9901013
// Strong before weak, because the weak function may call the strong
9911014
// one, but not the other way around.
9921015
return !F->isInterposable();
9931016
}
1017+
9941018
if (F->hasLocalLinkage() != G->hasLocalLinkage()) {
9951019
// External before local, because we definitely have to keep the external
9961020
// function, but may be able to drop the local one.
9971021
return !F->hasLocalLinkage();
9981022
}
1023+
9991024
// Impose a total order (by name) on the replacement of functions. This is
10001025
// important when operating on more than one module independently to prevent
10011026
// cycles of thunks calling each other when the modules are linked together.

llvm/test/Transforms/MergeFunc/comdat.ll

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ define linkonce_odr hidden i32 @g(i32 %x, i32 %y) comdat {
1919
ret i32 %sum3
2020
}
2121

22-
; CHECK-DAG: define linkonce_odr hidden i32 @f(i32 %x, i32 %y) comdat
23-
; CHECK-DAG: define linkonce_odr hidden i32 @g(i32 %0, i32 %1) comdat
22+
; CHECK-DAG: define private i32 @0(i32 %x, i32 %y) comdat($f)
23+
; CHECK-DAG: define linkonce_odr hidden i32 @g(i32 %0, i32 %1) comdat {
24+
; CHECK-DAG: define linkonce_odr hidden i32 @f(i32 %0, i32 %1) {
2425

llvm/test/Transforms/MergeFunc/linkonce_odr.ll

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@
77
; The problem with this is that the linker could then choose these two stubs
88
; each of the two modules and we end up with two stubs calling each other.
99

10-
11-
1210
define linkonce_odr i32 @funC(i32 %x, i32 %y) {
1311
%sum = add i32 %x, %y
1412
%sum2 = add i32 %x, %sum
@@ -37,16 +35,22 @@ define linkonce_odr i32 @funA(i32 %x, i32 %y) {
3735
;.
3836
; CHECK: @take_addr_of_funB = global ptr @funB
3937
;.
40-
; CHECK-LABEL: define linkonce_odr i32 @funA(
38+
; CHECK-LABEL: define private i32 @0(
4139
; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
4240
; CHECK-NEXT: [[SUM:%.*]] = add i32 [[X]], [[Y]]
4341
; CHECK-NEXT: [[SUM2:%.*]] = add i32 [[X]], [[SUM]]
4442
; CHECK-NEXT: [[SUM3:%.*]] = add i32 [[X]], [[SUM2]]
4543
; CHECK-NEXT: ret i32 [[SUM3]]
4644
;
4745
;
46+
; CHECK-LABEL: define linkonce_odr i32 @funC(
47+
; CHECK-SAME: i32 [[TMP0:%.*]], i32 [[TMP1:%.*]]) {
48+
; CHECK-NEXT: [[TMP3:%.*]] = tail call i32 @[[GLOB0:[0-9]+]](i32 [[TMP0]], i32 [[TMP1]])
49+
; CHECK-NEXT: ret i32 [[TMP3]]
50+
;
51+
;
4852
; CHECK-LABEL: define linkonce_odr i32 @funB(
4953
; CHECK-SAME: i32 [[TMP0:%.*]], i32 [[TMP1:%.*]]) {
50-
; CHECK-NEXT: [[TMP3:%.*]] = tail call i32 @funA(i32 [[TMP0]], i32 [[TMP1]])
54+
; CHECK-NEXT: [[TMP3:%.*]] = tail call i32 @[[GLOB0]](i32 [[TMP0]], i32 [[TMP1]])
5155
; CHECK-NEXT: ret i32 [[TMP3]]
5256
;

llvm/test/Transforms/MergeFunc/merge-linkonce-odr-used.ll

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,13 +41,13 @@ declare void @foo(ptr)
4141
;.
4242
; CHECK-LABEL: define void @caller_of_callers(
4343
; CHECK-SAME: ptr [[P:%.*]]) {
44-
; CHECK-NEXT: call void @linkonce_odr_caller_of_foo_1(ptr [[P]])
45-
; CHECK-NEXT: call void @linkonce_odr_caller_of_foo_1(ptr [[P]])
46-
; CHECK-NEXT: call void @linkonce_odr_caller_of_foo_1(ptr [[P]])
44+
; CHECK-NEXT: call void @[[GLOB0:[0-9]+]](ptr [[P]])
45+
; CHECK-NEXT: call void @[[GLOB0]](ptr [[P]])
46+
; CHECK-NEXT: call void @[[GLOB0]](ptr [[P]])
4747
; CHECK-NEXT: ret void
4848
;
4949
;
50-
; CHECK-LABEL: define linkonce_odr void @linkonce_odr_caller_of_foo_1(
50+
; CHECK-LABEL: define private void @0(
5151
; CHECK-SAME: ptr [[P:%.*]]) {
5252
; CHECK-NEXT: [[ENTRY:.*:]]
5353
; CHECK-NEXT: tail call void @foo(ptr [[P]])
@@ -58,12 +58,18 @@ declare void @foo(ptr)
5858
;
5959
; CHECK-LABEL: define linkonce_odr void @linkonce_odr_caller_of_foo_2(
6060
; CHECK-SAME: ptr [[TMP0:%.*]]) {
61-
; CHECK-NEXT: tail call void @linkonce_odr_caller_of_foo_1(ptr [[TMP0]])
61+
; CHECK-NEXT: tail call void @[[GLOB0]](ptr [[TMP0]])
62+
; CHECK-NEXT: ret void
63+
;
64+
;
65+
; CHECK-LABEL: define linkonce_odr void @linkonce_odr_caller_of_foo_1(
66+
; CHECK-SAME: ptr [[TMP0:%.*]]) {
67+
; CHECK-NEXT: tail call void @[[GLOB0]](ptr [[TMP0]])
6268
; CHECK-NEXT: ret void
6369
;
6470
;
6571
; CHECK-LABEL: define linkonce_odr void @linkonce_odr_caller_of_foo_3(
6672
; CHECK-SAME: ptr [[TMP0:%.*]]) {
67-
; CHECK-NEXT: tail call void @linkonce_odr_caller_of_foo_1(ptr [[TMP0]])
73+
; CHECK-NEXT: tail call void @[[GLOB0]](ptr [[TMP0]])
6874
; CHECK-NEXT: ret void
6975
;

llvm/test/Transforms/MergeFunc/merge-linkonce-odr-weak-odr-mixed-used.ll

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,13 +41,13 @@ declare void @foo(ptr)
4141
;.
4242
; CHECK-LABEL: define void @caller_of_callers(
4343
; CHECK-SAME: ptr [[P:%.*]]) {
44-
; CHECK-NEXT: call void @linkonce_odr_caller_of_foo_2(ptr [[P]])
45-
; CHECK-NEXT: call void @linkonce_odr_caller_of_foo_2(ptr [[P]])
46-
; CHECK-NEXT: call void @linkonce_odr_caller_of_foo_2(ptr [[P]])
44+
; CHECK-NEXT: call void @[[GLOB0:[0-9]+]](ptr [[P]])
45+
; CHECK-NEXT: call void @[[GLOB0]](ptr [[P]])
46+
; CHECK-NEXT: call void @[[GLOB0]](ptr [[P]])
4747
; CHECK-NEXT: ret void
4848
;
4949
;
50-
; CHECK-LABEL: define linkonce_odr void @linkonce_odr_caller_of_foo_2(
50+
; CHECK-LABEL: define private void @0(
5151
; CHECK-SAME: ptr [[P:%.*]]) {
5252
; CHECK-NEXT: [[ENTRY:.*:]]
5353
; CHECK-NEXT: tail call void @foo(ptr [[P]])
@@ -58,12 +58,18 @@ declare void @foo(ptr)
5858
;
5959
; CHECK-LABEL: define weak_odr void @weak_odr_caller_of_foo_1(
6060
; CHECK-SAME: ptr [[TMP0:%.*]]) {
61-
; CHECK-NEXT: tail call void @linkonce_odr_caller_of_foo_2(ptr [[TMP0]])
61+
; CHECK-NEXT: tail call void @[[GLOB0]](ptr [[TMP0]])
62+
; CHECK-NEXT: ret void
63+
;
64+
;
65+
; CHECK-LABEL: define linkonce_odr void @linkonce_odr_caller_of_foo_2(
66+
; CHECK-SAME: ptr [[TMP0:%.*]]) {
67+
; CHECK-NEXT: tail call void @[[GLOB0]](ptr [[TMP0]])
6268
; CHECK-NEXT: ret void
6369
;
6470
;
6571
; CHECK-LABEL: define weak_odr void @weak_odr_caller_of_foo_3(
6672
; CHECK-SAME: ptr [[TMP0:%.*]]) {
67-
; CHECK-NEXT: tail call void @linkonce_odr_caller_of_foo_2(ptr [[TMP0]])
73+
; CHECK-NEXT: tail call void @[[GLOB0]](ptr [[TMP0]])
6874
; CHECK-NEXT: ret void
6975
;

llvm/test/Transforms/MergeFunc/merge-linkonce-odr.ll

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -85,20 +85,21 @@ entry:
8585
}
8686

8787
declare void @zar(ptr)
88+
8889
; CHECK-LABEL: define void @caller_of_callers(
8990
; CHECK-SAME: ptr [[P:%.*]]) {
90-
; CHECK-NEXT: call void @linkonce_odr_caller_of_foo_1(ptr [[P]])
91-
; CHECK-NEXT: call void @linkonce_odr_caller_of_foo_1(ptr [[P]])
92-
; CHECK-NEXT: call void @linkonce_odr_caller_of_foo_1(ptr [[P]])
93-
; CHECK-NEXT: call void @linkonce_odr_caller_of_bar_2(ptr [[P]])
94-
; CHECK-NEXT: call void @linkonce_odr_caller_of_bar_2(ptr [[P]])
95-
; CHECK-NEXT: call void @linkonce_odr_caller_of_bar_2(ptr [[P]])
91+
; CHECK-NEXT: call void @[[GLOB0:[0-9]+]](ptr [[P]])
92+
; CHECK-NEXT: call void @[[GLOB0]](ptr [[P]])
93+
; CHECK-NEXT: call void @[[GLOB0]](ptr [[P]])
94+
; CHECK-NEXT: call void @internal_caller_of_bar_1(ptr [[P]])
95+
; CHECK-NEXT: call void @internal_caller_of_bar_1(ptr [[P]])
96+
; CHECK-NEXT: call void @internal_caller_of_bar_1(ptr [[P]])
9697
; CHECK-NEXT: call void @hidden_caller_of_zar_1(ptr [[P]])
9798
; CHECK-NEXT: call void @hidden_caller_of_zar_1(ptr [[P]])
9899
; CHECK-NEXT: ret void
99100
;
100101
;
101-
; CHECK-LABEL: define linkonce_odr hidden void @linkonce_odr_caller_of_foo_1(
102+
; CHECK-LABEL: define private void @0(
102103
; CHECK-SAME: ptr [[P:%.*]]) {
103104
; CHECK-NEXT: [[ENTRY:.*:]]
104105
; CHECK-NEXT: tail call void @foo(ptr [[P]])
@@ -107,7 +108,7 @@ declare void @zar(ptr)
107108
; CHECK-NEXT: ret void
108109
;
109110
;
110-
; CHECK-LABEL: define linkonce_odr hidden void @linkonce_odr_caller_of_bar_2(
111+
; CHECK-LABEL: define internal void @internal_caller_of_bar_1(
111112
; CHECK-SAME: ptr [[P:%.*]]) {
112113
; CHECK-NEXT: [[ENTRY:.*:]]
113114
; CHECK-NEXT: tail call void @bar(ptr [[P]])
@@ -124,3 +125,15 @@ declare void @zar(ptr)
124125
; CHECK-NEXT: tail call void @zar(ptr [[P]])
125126
; CHECK-NEXT: ret void
126127
;
128+
;
129+
; CHECK-LABEL: define linkonce_odr hidden void @linkonce_odr_caller_of_foo_2(
130+
; CHECK-SAME: ptr [[TMP0:%.*]]) {
131+
; CHECK-NEXT: tail call void @[[GLOB0]](ptr [[TMP0]])
132+
; CHECK-NEXT: ret void
133+
;
134+
;
135+
; CHECK-LABEL: define linkonce_odr hidden void @linkonce_odr_caller_of_foo_1(
136+
; CHECK-SAME: ptr [[TMP0:%.*]]) {
137+
; CHECK-NEXT: tail call void @[[GLOB0]](ptr [[TMP0]])
138+
; CHECK-NEXT: ret void
139+
;

llvm/test/Transforms/MergeFunc/merge-weak-odr-used.ll

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,13 +41,13 @@ declare void @foo(ptr)
4141
;.
4242
; CHECK-LABEL: define void @caller_of_callers(
4343
; CHECK-SAME: ptr [[P:%.*]]) {
44-
; CHECK-NEXT: call void @weak_odr_caller_of_foo_1(ptr [[P]])
45-
; CHECK-NEXT: call void @weak_odr_caller_of_foo_1(ptr [[P]])
46-
; CHECK-NEXT: call void @weak_odr_caller_of_foo_1(ptr [[P]])
44+
; CHECK-NEXT: call void @[[GLOB0:[0-9]+]](ptr [[P]])
45+
; CHECK-NEXT: call void @[[GLOB0]](ptr [[P]])
46+
; CHECK-NEXT: call void @[[GLOB0]](ptr [[P]])
4747
; CHECK-NEXT: ret void
4848
;
4949
;
50-
; CHECK-LABEL: define weak_odr void @weak_odr_caller_of_foo_1(
50+
; CHECK-LABEL: define private void @0(
5151
; CHECK-SAME: ptr [[P:%.*]]) {
5252
; CHECK-NEXT: [[ENTRY:.*:]]
5353
; CHECK-NEXT: tail call void @foo(ptr [[P]])
@@ -58,12 +58,18 @@ declare void @foo(ptr)
5858
;
5959
; CHECK-LABEL: define weak_odr void @weak_odr_caller_of_foo_2(
6060
; CHECK-SAME: ptr [[TMP0:%.*]]) {
61-
; CHECK-NEXT: tail call void @weak_odr_caller_of_foo_1(ptr [[TMP0]])
61+
; CHECK-NEXT: tail call void @[[GLOB0]](ptr [[TMP0]])
62+
; CHECK-NEXT: ret void
63+
;
64+
;
65+
; CHECK-LABEL: define weak_odr void @weak_odr_caller_of_foo_1(
66+
; CHECK-SAME: ptr [[TMP0:%.*]]) {
67+
; CHECK-NEXT: tail call void @[[GLOB0]](ptr [[TMP0]])
6268
; CHECK-NEXT: ret void
6369
;
6470
;
6571
; CHECK-LABEL: define weak_odr void @weak_odr_caller_of_foo_3(
6672
; CHECK-SAME: ptr [[TMP0:%.*]]) {
67-
; CHECK-NEXT: tail call void @weak_odr_caller_of_foo_1(ptr [[TMP0]])
73+
; CHECK-NEXT: tail call void @[[GLOB0]](ptr [[TMP0]])
6874
; CHECK-NEXT: ret void
6975
;

llvm/test/Transforms/MergeFunc/merge-weak-odr.ll

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -87,18 +87,18 @@ entry:
8787
declare void @zar(ptr)
8888
; CHECK-LABEL: define void @caller_of_callers(
8989
; CHECK-SAME: ptr [[P:%.*]]) {
90-
; CHECK-NEXT: call void @weak_odr_caller_of_foo_1(ptr [[P]])
91-
; CHECK-NEXT: call void @weak_odr_caller_of_foo_1(ptr [[P]])
92-
; CHECK-NEXT: call void @weak_odr_caller_of_foo_1(ptr [[P]])
93-
; CHECK-NEXT: call void @weak_odr_caller_of_bar_2(ptr [[P]])
94-
; CHECK-NEXT: call void @weak_odr_caller_of_bar_2(ptr [[P]])
95-
; CHECK-NEXT: call void @weak_odr_caller_of_bar_2(ptr [[P]])
90+
; CHECK-NEXT: call void @[[GLOB0:[0-9]+]](ptr [[P]])
91+
; CHECK-NEXT: call void @[[GLOB0]](ptr [[P]])
92+
; CHECK-NEXT: call void @[[GLOB0]](ptr [[P]])
93+
; CHECK-NEXT: call void @internal_caller_of_bar_1(ptr [[P]])
94+
; CHECK-NEXT: call void @internal_caller_of_bar_1(ptr [[P]])
95+
; CHECK-NEXT: call void @internal_caller_of_bar_1(ptr [[P]])
9696
; CHECK-NEXT: call void @hidden_caller_of_zar_1(ptr [[P]])
9797
; CHECK-NEXT: call void @hidden_caller_of_zar_1(ptr [[P]])
9898
; CHECK-NEXT: ret void
9999
;
100100
;
101-
; CHECK-LABEL: define weak_odr hidden void @weak_odr_caller_of_foo_1(
101+
; CHECK-LABEL: define private void @0(
102102
; CHECK-SAME: ptr [[P:%.*]]) {
103103
; CHECK-NEXT: [[ENTRY:.*:]]
104104
; CHECK-NEXT: tail call void @foo(ptr [[P]])
@@ -107,7 +107,7 @@ declare void @zar(ptr)
107107
; CHECK-NEXT: ret void
108108
;
109109
;
110-
; CHECK-LABEL: define weak_odr hidden void @weak_odr_caller_of_bar_2(
110+
; CHECK-LABEL: define internal void @internal_caller_of_bar_1(
111111
; CHECK-SAME: ptr [[P:%.*]]) {
112112
; CHECK-NEXT: [[ENTRY:.*:]]
113113
; CHECK-NEXT: tail call void @bar(ptr [[P]])
@@ -127,19 +127,31 @@ declare void @zar(ptr)
127127
;
128128
; CHECK-LABEL: define weak_odr hidden void @weak_odr_caller_of_foo_2(
129129
; CHECK-SAME: ptr [[TMP0:%.*]]) {
130-
; CHECK-NEXT: tail call void @weak_odr_caller_of_foo_1(ptr [[TMP0]])
130+
; CHECK-NEXT: tail call void @[[GLOB0]](ptr [[TMP0]])
131+
; CHECK-NEXT: ret void
132+
;
133+
;
134+
; CHECK-LABEL: define weak_odr hidden void @weak_odr_caller_of_foo_1(
135+
; CHECK-SAME: ptr [[TMP0:%.*]]) {
136+
; CHECK-NEXT: tail call void @[[GLOB0]](ptr [[TMP0]])
131137
; CHECK-NEXT: ret void
132138
;
133139
;
134140
; CHECK-LABEL: define weak_odr hidden void @weak_odr_caller_of_foo_3(
135141
; CHECK-SAME: ptr [[TMP0:%.*]]) {
136-
; CHECK-NEXT: tail call void @weak_odr_caller_of_foo_1(ptr [[TMP0]])
142+
; CHECK-NEXT: tail call void @[[GLOB0]](ptr [[TMP0]])
143+
; CHECK-NEXT: ret void
144+
;
145+
;
146+
; CHECK-LABEL: define weak_odr hidden void @weak_odr_caller_of_bar_2(
147+
; CHECK-SAME: ptr [[TMP0:%.*]]) {
148+
; CHECK-NEXT: tail call void @internal_caller_of_bar_1(ptr [[TMP0]])
137149
; CHECK-NEXT: ret void
138150
;
139151
;
140152
; CHECK-LABEL: define weak_odr hidden void @weak_odr_caller_of_bar_3(
141153
; CHECK-SAME: ptr [[TMP0:%.*]]) {
142-
; CHECK-NEXT: tail call void @weak_odr_caller_of_bar_2(ptr [[TMP0]])
154+
; CHECK-NEXT: tail call void @internal_caller_of_bar_1(ptr [[TMP0]])
143155
; CHECK-NEXT: ret void
144156
;
145157
;

0 commit comments

Comments
 (0)