-
Notifications
You must be signed in to change notification settings - Fork 15.4k
[WholeProgramDevirt] Add check for AvailableExternal and give up icall.branch.funnel #143468
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
49b51cf
0725ff3
fd5e7a1
14ee5ff
a133a21
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1093,6 +1093,7 @@ bool DevirtModule::tryFindVirtualCallTargets( | |
| std::vector<VirtualCallTarget> &TargetsForSlot, | ||
| const std::set<TypeMemberInfo> &TypeMemberInfos, uint64_t ByteOffset, | ||
| ModuleSummaryIndex *ExportSummary) { | ||
| bool hasAvailableExternally = false; | ||
| for (const TypeMemberInfo &TM : TypeMemberInfos) { | ||
| if (!TM.Bits->GV->isConstant()) | ||
| return false; | ||
|
|
@@ -1103,6 +1104,16 @@ bool DevirtModule::tryFindVirtualCallTargets( | |
| GlobalObject::VCallVisibilityPublic) | ||
| return false; | ||
|
|
||
| // Record if the first GV is AvailableExternally | ||
| if (TargetsForSlot.empty()) | ||
| hasAvailableExternally = TM.Bits->GV->hasAvailableExternallyLinkage(); | ||
|
|
||
| // When the first GV is AvailableExternally, check if all other GVs are | ||
|
||
| // also AvailableExternally. If they are not the same, return false. | ||
| if (!TargetsForSlot.empty() && hasAvailableExternally && | ||
| !TM.Bits->GV->hasAvailableExternallyLinkage()) | ||
| return false; | ||
|
|
||
| Function *Fn = nullptr; | ||
| Constant *C = nullptr; | ||
| std::tie(Fn, C) = | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,57 @@ | ||
| ; RUN: opt -S -passes=wholeprogramdevirt -whole-program-visibility %s | FileCheck %s | ||
|
|
||
| ; This test is reduced from C++ code like this: | ||
| ; class A :public std::exception { | ||
| ; public: | ||
| ; A() {}; | ||
| ; const char* what () const throw () {return "A";} | ||
| ; }; | ||
| ; long test(std::exception *p) { | ||
| ; const char* ch = p->what(); | ||
| ; return std::strlen(ch); | ||
| ; } | ||
| ; | ||
| ; Build command is "clang++ -O2 -target x86_64-unknown-linux -flto=thin \ | ||
| ; -fwhole-program-vtables -static-libstdc++ -Wl,-plugin-opt=-whole-program-visibility" | ||
| ; | ||
| ; _ZTVSt9exception's visibility is 1 (Linkage Unit), and available_externally. | ||
| ; But another vtable _ZTV1A.0 is not available_externally. | ||
| ; They should not do devirtualization because they are in different linkage type. | ||
|
|
||
| target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128" | ||
| target triple = "x86_64-unknown-linux" | ||
|
|
||
| @_ZTVSt9exception = available_externally constant { [5 x ptr] } { [5 x ptr] [ptr null, ptr null, ptr null, ptr null, ptr @_ZNKSt9exception4whatEv] }, !type !0, !type !1, !vcall_visibility !2 | ||
| @_ZTV1A.0 = constant [5 x ptr] [ptr null, ptr null, ptr null, ptr null, ptr @_ZNK1A4whatEv], !type !3, !type !4, !type !5, !type !6, !vcall_visibility !2 | ||
|
|
||
| declare ptr @_ZNKSt9exception4whatEv() | ||
|
|
||
| define i64 @_Z4testPSt9exception() { | ||
| %1 = call i1 @llvm.type.test(ptr null, metadata !"_ZTSSt9exception") | ||
| tail call void @llvm.assume(i1 %1) | ||
| %2 = getelementptr i8, ptr null, i64 16 | ||
| %3 = load ptr, ptr %2, align 8 | ||
| %4 = tail call ptr %3(ptr null) | ||
| ret i64 0 | ||
| } | ||
|
|
||
| ; Function Attrs: nocallback nofree nosync nounwind willreturn memory(inaccessiblemem: write) | ||
| declare void @llvm.assume(i1 noundef) #0 | ||
|
|
||
| declare ptr @_ZNK1A4whatEv() | ||
|
|
||
| ; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none) | ||
| declare i1 @llvm.type.test(ptr, metadata) #1 | ||
|
|
||
| ; CHECK-NOT: call void (...) @llvm.icall.branch.funnel | ||
|
|
||
| attributes #0 = { nocallback nofree nosync nounwind willreturn memory(inaccessiblemem: write) } | ||
| attributes #1 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) } | ||
|
|
||
| !0 = !{i64 16, !"_ZTSSt9exception"} | ||
| !1 = !{i64 32, !"_ZTSMSt9exceptionKDoFPKcvE.virtual"} | ||
| !2 = !{i64 1} | ||
| !3 = !{i32 16, !"_ZTS1A"} | ||
| !4 = !{i32 32, !"_ZTSM1AKDoFPKcvE.virtual"} | ||
| !5 = !{i32 16, !"_ZTSSt9exception"} | ||
| !6 = !{i32 32, !"_ZTSMSt9exceptionKDoFPKcvE.virtual"} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you, @shiltian. Done.