-
Notifications
You must be signed in to change notification settings - Fork 14.4k
[WPD]: Apply speculative WPD in non-lto mode. #145031
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
base: main
Are you sure you want to change the base?
Changes from all commits
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 |
---|---|---|
@@ -0,0 +1,56 @@ | ||
// Check that speculative devirtualization works without the need for LTO or visibility. | ||
// RUN: %clang_cc1 -fwhole-program-vtables -O1 %s -emit-llvm -o - | FileCheck %s | ||
|
||
struct A { | ||
A(){} | ||
__attribute__((noinline)) | ||
virtual int virtual1(){return 20;} | ||
__attribute__((noinline)) | ||
virtual void empty_virtual(){} | ||
}; | ||
|
||
struct B : A { | ||
B(){} | ||
__attribute__((noinline)) | ||
virtual int virtual1() override {return 50;} | ||
__attribute__((noinline)) | ||
virtual void empty_virtual() override {} | ||
}; | ||
|
||
// Test that we can apply speculative devirtualization | ||
// without the need for LTO or visibility. | ||
__attribute__((noinline)) | ||
int test_devirtual(A *a) { | ||
// CHECK: %0 = load ptr, ptr %vtable, align 8 | ||
// CHECK-NEXT: %1 = icmp eq ptr %0, @_ZN1B8virtual1Ev | ||
// CHECK-NEXT: br i1 %1, label %if.true.direct_targ, label %if.false.orig_indirect, !prof !12 | ||
|
||
// CHECK: if.true.direct_targ: ; preds = %entry | ||
// CHECK-NEXT: %2 = tail call noundef i32 @_ZN1B8virtual1Ev(ptr noundef nonnull align 8 dereferenceable(8) %a) | ||
// CHECK-NEXT: br label %if.end.icp | ||
|
||
// CHECK: if.false.orig_indirect: ; preds = %entry | ||
// CHECK-NEXT: %call = tail call noundef i32 %0(ptr noundef nonnull align 8 dereferenceable(8) %a) | ||
// CHECK-NEXT: br label %if.end.icp | ||
|
||
// CHECK: if.end.icp: ; preds = %if.false.orig_indirect, %if.true.direct_targ | ||
// CHECK-NEXT: %3 = phi i32 [ %call, %if.false.orig_indirect ], [ %2, %if.true.direct_targ ] | ||
// CHECK-NEXT: ret i32 %3 | ||
|
||
return a->virtual1(); | ||
} | ||
|
||
// Test that we skip devirtualization for empty virtual functions as most probably | ||
// they are used for interfaces. | ||
__attribute__((noinline)) | ||
void test_devirtual_empty_fn(A *a) { | ||
// CHECK: load ptr, ptr %vfn, align 8 | ||
// CHECK-NEXT: tail call void %0(ptr noundef nonnull align 8 dereferenceable(8) %a) | ||
a->empty_virtual(); | ||
} | ||
|
||
void test() { | ||
A *a = new B(); | ||
test_devirtual(a); | ||
test_devirtual_empty_fn(a); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,15 +1,11 @@ | ||
// RUN: not %clang -target x86_64-unknown-linux -fwhole-program-vtables -### %s 2>&1 | FileCheck --check-prefix=NO-LTO %s | ||
// RUN: not %clang_cl --target=x86_64-pc-win32 -fwhole-program-vtables -### -- %s 2>&1 | FileCheck --check-prefix=NO-LTO %s | ||
// NO-LTO: invalid argument '-fwhole-program-vtables' only allowed with '-flto' | ||
// RUN: %clang -target x86_64-unknown-linux -fwhole-program-vtables -O1 -### %s 2>&1 | FileCheck --check-prefix=WPD-NO-LTO %s | ||
// RUN: %clang_cl --target=x86_64-pc-win32 -fwhole-program-vtables -O1 -### -- %s 2>&1 | FileCheck --check-prefix=WPD-NO-LTO %s | ||
// WPD-NO-LTO: "-fwhole-program-vtables" | ||
|
||
// RUN: %clang -target x86_64-unknown-linux -fwhole-program-vtables -flto -### %s 2>&1 | FileCheck --check-prefix=LTO %s | ||
// RUN: not %clang_cl --target=x86_64-pc-win32 -fwhole-program-vtables -flto -### -- %s 2>&1 | FileCheck --check-prefix=LTO %s | ||
// LTO: "-fwhole-program-vtables" | ||
|
||
/// -funified-lto does not imply -flto, so we still get an error that fwhole-program-vtables has no effect without -flto | ||
// RUN: not %clang --target=x86_64-pc-linux-gnu -fwhole-program-vtables -funified-lto -### %s 2>&1 | FileCheck --check-prefix=NO-LTO %s | ||
// RUN: not %clang --target=x86_64-pc-linux-gnu -fwhole-program-vtables -fno-unified-lto -### %s 2>&1 | FileCheck --check-prefix=NO-LTO %s | ||
|
||
// RUN: %clang -target x86_64-unknown-linux -fwhole-program-vtables -fno-whole-program-vtables -flto -### %s 2>&1 | FileCheck --check-prefix=LTO-DISABLE %s | ||
// RUN: not %clang_cl --target=x86_64-pc-win32 -fwhole-program-vtables -fno-whole-program-vtables -flto -### -- %s 2>&1 | FileCheck --check-prefix=LTO-DISABLE %s | ||
// LTO-DISABLE-NOT: "-fwhole-program-vtables" |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -321,6 +321,7 @@ PipelineTuningOptions::PipelineTuningOptions() { | |
MergeFunctions = EnableMergeFunctions; | ||
InlinerThreshold = -1; | ||
EagerlyInvalidateAnalyses = EnableEagerlyInvalidateAnalyses; | ||
WholeProgramDevirt = false; | ||
} | ||
|
||
namespace llvm { | ||
|
@@ -1629,6 +1630,23 @@ PassBuilder::buildModuleOptimizationPipeline(OptimizationLevel Level, | |
if (!LTOPreLink) | ||
MPM.addPass(RelLookupTableConverterPass()); | ||
|
||
if (PTO.WholeProgramDevirt && LTOPhase == ThinOrFullLTOPhase::None) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does this need to be guarded by whether whole program vtables was enabled? We don't for LTO. What happens if it is simply always invoked for non-LTO? |
||
MPM.addPass(WholeProgramDevirtPass(/*ExportSummary*/ nullptr, | ||
/*ImportSummary*/ nullptr, | ||
/*InLTOMode=*/false)); | ||
MPM.addPass(LowerTypeTestsPass(nullptr, nullptr, | ||
lowertypetests::DropTestKind::Assume)); | ||
if (EnableModuleInliner) { | ||
MPM.addPass(ModuleInlinerPass(getInlineParamsFromOptLevel(Level), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think you want to reinvoke the inliner. Better to invoke WPD from the module simplifier right before the inliner is invoked there. |
||
UseInlineAdvisor, | ||
ThinOrFullLTOPhase::None)); | ||
} else { | ||
MPM.addPass(ModuleInlinerWrapperPass( | ||
getInlineParamsFromOptLevel(Level), | ||
/* MandatoryFirst */ true, | ||
InlineContext{ThinOrFullLTOPhase::None, InlinePass::CGSCCInliner})); | ||
} | ||
} | ||
return MPM; | ||
} | ||
|
||
|
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.
Generally we don't test that LLVM optimizations are applied in clang tests. Better to split this into 2 tests: