Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,18 @@ static cl::list<std::string>
cl::desc("Prevent function(s) from being devirtualized"),
cl::Hidden, cl::CommaSeparated);

/// A function is unreachable if its entry block ends with 'unreachable' IR
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you note that this is useful for removing abstract class virtual destructors, which are emitted with a trap and unreachable instruction, and add a TODO to identify these more precisely?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

related - probably update the description which currently says that this is about pure virtual functions, but most of those are already handled due to the __cxa_pure_virtual in the vtable slot.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated the surrounding comment with the motivating case and a TODO for Clang's codegen, and updated PR description as suggested.

/// instruction. In some cases, the program intends to run such functions and
/// terminate, for instance, a unit test may run a death test. A non-test
/// program might (or allowed to) invoke such functions to report failures
/// (whether/when it's a good practice or not is a different topic). Regard
/// unreachable function as possible devirtualize targets to keep the program
/// behavior.
static cl::opt<bool> WholeProgramDevirtKeepUnreachableFunction(
"wholeprogramdevirt-keep-unreachable-function",
cl::desc("Regard unreachable functions as possible devirtualize targets."),
cl::Hidden, cl::init(true));

/// If explicitly specified, the devirt module pass will stop transformation
/// once the total number of devirtualizations reach the cutoff value. Setting
/// this option to 0 explicitly will do 0 devirtualization.
Expand Down Expand Up @@ -386,6 +398,9 @@ template <> struct DenseMapInfo<VTableSlotSummary> {
// 2) All function summaries indicate it's unreachable
// 3) There is no non-function with the same GUID (which is rare)
static bool mustBeUnreachableFunction(ValueInfo TheFnVI) {
if (WholeProgramDevirtKeepUnreachableFunction)
return false;

if ((!TheFnVI) || TheFnVI.getSummaryList().empty()) {
// Returns false if ValueInfo is absent, or the summary list is empty
// (e.g., function declarations).
Expand Down Expand Up @@ -2241,6 +2256,8 @@ DevirtModule::lookUpFunctionValueInfo(Function *TheFn,

bool DevirtModule::mustBeUnreachableFunction(
Function *const F, ModuleSummaryIndex *ExportSummary) {
if (WholeProgramDevirtKeepUnreachableFunction)
return false;
// First, learn unreachability by analyzing function IR.
if (!F->isDeclaration()) {
// A function must be unreachable if its entry block ends with an
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
; Test that static devirtualization doesn't happen because there are two
; devirtualizable targets. Unreachable functions are kept in the devirtualizable
; target set by default.
; RUN: opt -S -passes=wholeprogramdevirt -whole-program-visibility -pass-remarks=wholeprogramdevirt %s 2>&1 | FileCheck %s --implicit-check-not="single-impl"

; Test that regular LTO will analyze IR, detect unreachable functions and discard unreachable functions
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that this is only done under the -wholeprogramdevirt-keep-unreachable-function=false option

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done.

; when finding virtual call targets.
; In this test case, the unreachable function is the virtual deleting destructor of an abstract class.
; RUN: opt -S -passes=wholeprogramdevirt -whole-program-visibility -pass-remarks=wholeprogramdevirt -wholeprogramdevirt-keep-unreachable-function=false %s 2>&1 | FileCheck %s --check-prefix=DEVIRT

; RUN: opt -S -passes=wholeprogramdevirt -whole-program-visibility -pass-remarks=wholeprogramdevirt %s 2>&1 | FileCheck %s

; CHECK: remark: tmp.cc:21:3: single-impl: devirtualized a call to _ZN7DerivedD0Ev
; CHECK: remark: <unknown>:0:0: devirtualized _ZN7DerivedD0Ev
; DEVIRT: remark: tmp.cc:21:3: single-impl: devirtualized a call to _ZN7DerivedD0Ev
; DEVIRT: remark: <unknown>:0:0: devirtualized _ZN7DerivedD0Ev

source_filename = "tmp.cc"
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
Expand Down
Loading