diff --git a/llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp b/llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp index 36a1841b36346..5325642af9dd0 100644 --- a/llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp +++ b/llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp @@ -168,6 +168,14 @@ static cl::list cl::desc("Prevent function(s) from being devirtualized"), cl::Hidden, cl::CommaSeparated); +/// 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. +static cl::opt WholeProgramDevirtCutoff( + "wholeprogramdevirt-cutoff", + cl::desc("Max number of devirtualizations for devirt module pass"), + cl::init(0)); + /// Mechanism to add runtime checking of devirtualization decisions, optionally /// trapping or falling back to indirect call on any that are not correct. /// Trapping mode is useful for debugging undefined behavior leading to failures @@ -316,6 +324,9 @@ VirtualCallTarget::VirtualCallTarget(GlobalValue *Fn, const TypeMemberInfo *TM) namespace { +// Tracks the number of devirted calls in the IR transformation. +static unsigned NumDevirtCalls = 0; + // A slot in a set of virtual tables. The TypeID identifies the set of virtual // tables, and the ByteOffset is the offset in bytes from the address point to // the virtual function pointer. @@ -1169,10 +1180,16 @@ void DevirtModule::applySingleImplDevirt(VTableSlotInfo &SlotInfo, if (!OptimizedCalls.insert(&VCallSite.CB).second) continue; + // Stop when the number of devirted calls reaches the cutoff. + if (WholeProgramDevirtCutoff.getNumOccurrences() > 0 && + NumDevirtCalls >= WholeProgramDevirtCutoff) + return; + if (RemarksEnabled) VCallSite.emitRemark("single-impl", TheFn->stripPointerCasts()->getName(), OREGetter); NumSingleImpl++; + NumDevirtCalls++; auto &CB = VCallSite.CB; assert(!CB.getCalledFunction() && "devirtualizing direct call?"); IRBuilder<> Builder(&CB); diff --git a/llvm/test/Transforms/WholeProgramDevirt/import.ll b/llvm/test/Transforms/WholeProgramDevirt/import.ll index 4e4df5f35a777..de25bc10a7c12 100644 --- a/llvm/test/Transforms/WholeProgramDevirt/import.ll +++ b/llvm/test/Transforms/WholeProgramDevirt/import.ll @@ -8,6 +8,12 @@ ; RUN: opt -S -passes=wholeprogramdevirt -wholeprogramdevirt-summary-action=import -wholeprogramdevirt-read-summary=%S/Inputs/import-vcp-branch-funnel.yaml < %s | FileCheck --check-prefixes=CHECK,VCP,VCP-X86,VCP64,BRANCH-FUNNEL %s ; RUN: opt -S -passes=wholeprogramdevirt -wholeprogramdevirt-summary-action=import -wholeprogramdevirt-read-summary=%S/Inputs/import-branch-funnel.yaml < %s | FileCheck --check-prefixes=CHECK,BRANCH-FUNNEL,BRANCH-FUNNEL-NOVCP %s +; Cutoff value is not explicitly set. Expect 3 remark messages. +; RUN: opt -S -passes=wholeprogramdevirt -wholeprogramdevirt-summary-action=import -pass-remarks=wholeprogramdevirt -wholeprogramdevirt-read-summary=%S/Inputs/import-single-impl.yaml < %s 2>&1 | grep "single-impl" | count 3 +; Cutoff value is set to 1. Expect one remark messages. +; RUN: opt -S -passes=wholeprogramdevirt -wholeprogramdevirt-summary-action=import -pass-remarks=wholeprogramdevirt -wholeprogramdevirt-cutoff=1 -wholeprogramdevirt-read-summary=%S/Inputs/import-single-impl.yaml < %s 2>&1 | grep "single-impl" | count 1 +; Cutoff value is explicitly set to zero. Expect no remark message. +; RUN: opt -S -passes=wholeprogramdevirt -wholeprogramdevirt-summary-action=import -pass-remarks=wholeprogramdevirt -wholeprogramdevirt-cutoff=0 -wholeprogramdevirt-read-summary=%S/Inputs/import-single-impl.yaml < %s 2>&1 | FileCheck -implicit-check-not="remark" %s target datalayout = "e-p:64:64" target triple = "x86_64-unknown-linux-gnu"