mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-26 04:32:44 +01:00
WholeProgramDevirt: Implement exporting for single-impl devirtualization.
Differential Revision: https://reviews.llvm.org/D29811 llvm-svn: 296945
This commit is contained in:
parent
85c3314674
commit
0551aa2e46
@ -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
|
||||
@ -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.
|
||||
@ -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,
|
||||
@ -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)
|
||||
@ -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)
|
||||
@ -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;
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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])
|
||||
@ -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;
|
||||
|
||||
|
78
test/Transforms/WholeProgramDevirt/export-single-impl.ll
Normal file
78
test/Transforms/WholeProgramDevirt/export-single-impl.ll
Normal file
@ -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 !{}
|
Loading…
Reference in New Issue
Block a user