Skip to content

Commit

Permalink
WholeProgramDevirt: Implement exporting for single-impl devirtualizat…
Browse files Browse the repository at this point in the history
…ion.

Differential Revision: https://reviews.llvm.org/D29811

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@296945 91177308-0d34-0410-b5e6-96231b3b80d8
  • Loading branch information
pcc committed Mar 4, 2017
1 parent d31e3ed commit d1e011d
Show file tree
Hide file tree
Showing 2 changed files with 132 additions and 6 deletions.
60 changes: 54 additions & 6 deletions lib/Transforms/IPO/WholeProgramDevirt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,10 @@ struct CallSiteInfo {
// These fields are used during the export phase of ThinLTO and reflect
// information collected from function summaries.

/// Whether any function summary contains an llvm.assume(llvm.type.test) for
/// this slot.
bool SummaryHasTypeTestAssumeUsers;

/// CFI-specific: a vector containing the list of function summaries that use
/// the llvm.type.checked.load intrinsic and therefore will require
/// resolutions for llvm.type.test in order to implement CFI checks if
Expand All @@ -320,6 +324,11 @@ struct CallSiteInfo {
/// non-empty, we will need to add a use of llvm.type.test to each of the
/// function summaries in the vector.
std::vector<FunctionSummary *> SummaryTypeCheckedLoadUsers;

bool isExported() const {
return SummaryHasTypeTestAssumeUsers ||
!SummaryTypeCheckedLoadUsers.empty();
}
};

// Call site information collected for a specific VTableSlot.
Expand Down Expand Up @@ -406,9 +415,11 @@ struct DevirtModule {
const std::set<TypeMemberInfo> &TypeMemberInfos,
uint64_t ByteOffset);

void applySingleImplDevirt(VTableSlotInfo &SlotInfo, Constant *TheFn);
void applySingleImplDevirt(VTableSlotInfo &SlotInfo, Constant *TheFn,
bool &IsExported);
bool trySingleImplDevirt(MutableArrayRef<VirtualCallTarget> TargetsForSlot,
VTableSlotInfo &SlotInfo);
VTableSlotInfo &SlotInfo,
WholeProgramDevirtResolution *Res);

bool tryEvaluateFunctionsWithArgs(
MutableArrayRef<VirtualCallTarget> TargetsForSlot,
Expand Down Expand Up @@ -625,7 +636,7 @@ bool DevirtModule::tryFindVirtualCallTargets(
}

void DevirtModule::applySingleImplDevirt(VTableSlotInfo &SlotInfo,
Constant *TheFn) {
Constant *TheFn, bool &IsExported) {
auto Apply = [&](CallSiteInfo &CSInfo) {
for (auto &&VCallSite : CSInfo.CallSites) {
if (RemarksEnabled)
Expand All @@ -636,6 +647,10 @@ void DevirtModule::applySingleImplDevirt(VTableSlotInfo &SlotInfo,
if (VCallSite.NumUnsafeUses)
--*VCallSite.NumUnsafeUses;
}
if (CSInfo.isExported()) {
IsExported = true;
CSInfo.SummaryTypeCheckedLoadUsers.clear();
}
};
Apply(SlotInfo.CSInfo);
for (auto &P : SlotInfo.ConstCSInfo)
Expand All @@ -644,7 +659,7 @@ void DevirtModule::applySingleImplDevirt(VTableSlotInfo &SlotInfo,

bool DevirtModule::trySingleImplDevirt(
MutableArrayRef<VirtualCallTarget> TargetsForSlot,
VTableSlotInfo &SlotInfo) {
VTableSlotInfo &SlotInfo, WholeProgramDevirtResolution *Res) {
// See if the program contains a single implementation of this virtual
// function.
Function *TheFn = TargetsForSlot[0].Fn;
Expand All @@ -655,7 +670,24 @@ bool DevirtModule::trySingleImplDevirt(
// If so, update each call site to call that implementation directly.
if (RemarksEnabled)
TargetsForSlot[0].WasDevirt = true;
applySingleImplDevirt(SlotInfo, TheFn);

bool IsExported = false;
applySingleImplDevirt(SlotInfo, TheFn, IsExported);
if (!IsExported)
return false;

// If the only implementation has local linkage, we must promote to external
// to make it visible to thin LTO objects. We can only get here during the
// ThinLTO export phase.
if (TheFn->hasLocalLinkage()) {
TheFn->setLinkage(GlobalValue::ExternalLinkage);
TheFn->setVisibility(GlobalValue::HiddenVisibility);
TheFn->setName(TheFn->getName() + "$merged");
}

Res->TheKind = WholeProgramDevirtResolution::SingleImpl;
Res->SingleImplName = TheFn->getName();

return true;
}

Expand Down Expand Up @@ -1102,10 +1134,19 @@ bool DevirtModule::run() {
if (!FS)
continue;
// FIXME: Only add live functions.
for (FunctionSummary::VFuncId VF : FS->type_test_assume_vcalls())
for (Metadata *MD : MetadataByGUID[VF.GUID])
CallSlots[{MD, VF.Offset}].CSInfo.SummaryHasTypeTestAssumeUsers =
true;
for (FunctionSummary::VFuncId VF : FS->type_checked_load_vcalls())
for (Metadata *MD : MetadataByGUID[VF.GUID])
CallSlots[{MD, VF.Offset}]
.CSInfo.SummaryTypeCheckedLoadUsers.push_back(FS);
for (const FunctionSummary::ConstVCall &VC :
FS->type_test_assume_const_vcalls())
for (Metadata *MD : MetadataByGUID[VC.VFunc.GUID])
CallSlots[{MD, VC.VFunc.Offset}]
.ConstCSInfo[VC.Args].SummaryHasTypeTestAssumeUsers = true;
for (const FunctionSummary::ConstVCall &VC :
FS->type_checked_load_const_vcalls())
for (Metadata *MD : MetadataByGUID[VC.VFunc.GUID])
Expand All @@ -1126,7 +1167,14 @@ bool DevirtModule::run() {
std::vector<VirtualCallTarget> TargetsForSlot;
if (tryFindVirtualCallTargets(TargetsForSlot, TypeIdMap[S.first.TypeID],
S.first.ByteOffset)) {
if (!trySingleImplDevirt(TargetsForSlot, S.second) &&
WholeProgramDevirtResolution *Res = nullptr;
if (Action == PassSummaryAction::Export && isa<MDString>(S.first.TypeID))
Res =
&Summary
->getTypeIdSummary(cast<MDString>(S.first.TypeID)->getString())
.WPDRes[S.first.ByteOffset];

if (!trySingleImplDevirt(TargetsForSlot, S.second, Res) &&
tryVirtualConstProp(TargetsForSlot, S.second))
DidVirtualConstProp = true;

Expand Down
78 changes: 78 additions & 0 deletions test/Transforms/WholeProgramDevirt/export-single-impl.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
; RUN: opt -wholeprogramdevirt -wholeprogramdevirt-summary-action=export -wholeprogramdevirt-read-summary=%S/Inputs/export.yaml -wholeprogramdevirt-write-summary=%t -S -o - %s | FileCheck %s
; RUN: FileCheck --check-prefix=SUMMARY %s < %t

; SUMMARY: TypeIdMap:
; SUMMARY-NEXT: typeid1:
; SUMMARY-NEXT: TTRes:
; SUMMARY-NEXT: Kind: Unsat
; SUMMARY-NEXT: SizeM1BitWidth: 0
; SUMMARY-NEXT: WPDRes:
; SUMMARY-NEXT: 0:
; SUMMARY-NEXT: Kind: SingleImpl
; SUMMARY-NEXT: SingleImplName: vf1
; SUMMARY-NEXT: ResByArg:
; SUMMARY-NEXT: typeid2:
; SUMMARY-NEXT: TTRes:
; SUMMARY-NEXT: Kind: Unsat
; SUMMARY-NEXT: SizeM1BitWidth: 0
; SUMMARY-NEXT: WPDRes:
; SUMMARY-NEXT: 0:
; SUMMARY-NEXT: Kind: SingleImpl
; SUMMARY-NEXT: SingleImplName: vf2
; SUMMARY-NEXT: ResByArg:
; SUMMARY-NEXT: typeid3:
; SUMMARY-NEXT: TTRes:
; SUMMARY-NEXT: Kind: Unsat
; SUMMARY-NEXT: SizeM1BitWidth: 0
; SUMMARY-NEXT: WPDRes:
; SUMMARY-NEXT: 0:
; SUMMARY-NEXT: Kind: SingleImpl
; SUMMARY-NEXT: SingleImplName: vf3
; SUMMARY-NEXT: ResByArg:
; SUMMARY-NEXT: typeid4:
; SUMMARY-NEXT: TTRes:
; SUMMARY-NEXT: Kind: Unsat
; SUMMARY-NEXT: SizeM1BitWidth: 0
; SUMMARY-NEXT: WPDRes:
; SUMMARY-NEXT: 0:
; SUMMARY-NEXT: Kind: SingleImpl
; SUMMARY-NEXT: SingleImplName: 'vf4$merged'
; SUMMARY-NEXT: ResByArg:
; SUMMARY-NEXT: ...

; CHECK: @vt1 = constant void (i8*)* @vf1
@vt1 = constant void (i8*)* @vf1, !type !0

; CHECK: @vt2 = constant void (i8*)* @vf2
@vt2 = constant void (i8*)* @vf2, !type !1

@vt3 = constant void (i8*)* @vf3, !type !2

; CHECK: @vt4 = constant void (i8*)* @"vf4$merged"
@vt4 = constant void (i8*)* @vf4, !type !3

@vt5 = constant void (i8*)* @vf5, !type !4

; CHECK: declare void @vf1(i8*)
declare void @vf1(i8*)

; CHECK: define void @vf2(i8*)
define void @vf2(i8*) {
ret void
}

declare void @vf3(i8*)

; CHECK: define hidden void @"vf4$merged"
define internal void @vf4(i8*) {
ret void
}

declare void @vf5(i8*)

!0 = !{i32 0, !"typeid1"}
!1 = !{i32 0, !"typeid2"}
!2 = !{i32 0, !"typeid3"}
!3 = !{i32 0, !"typeid4"}
!4 = !{i32 0, !5}
!5 = distinct !{}

0 comments on commit d1e011d

Please sign in to comment.