Skip to content

Commit 15d75a0

Browse files
authored
Merge pull request #615 from hyp/revert-dvfe
Revert "Reland: Dead Virtual Function Elimination"
2 parents 1abba77 + 0304533 commit 15d75a0

33 files changed

+81
-1425
lines changed

clang/include/clang/Basic/CodeGenOptions.def

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -287,10 +287,6 @@ CODEGENOPT(EmitLLVMUseLists, 1, 0) ///< Control whether to serialize use-lists.
287287
CODEGENOPT(WholeProgramVTables, 1, 0) ///< Whether to apply whole-program
288288
/// vtable optimization.
289289

290-
CODEGENOPT(VirtualFunctionElimination, 1, 0) ///< Whether to apply the dead
291-
/// virtual function elimination
292-
/// optimization.
293-
294290
/// Whether to use public LTO visibility for entities in std and stdext
295291
/// namespaces. This is enabled by clang-cl's /MT and /MTd flags.
296292
CODEGENOPT(LTOVisibilityPublicStd, 1, 0)

clang/include/clang/Driver/Options.td

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1937,13 +1937,6 @@ def fforce_emit_vtables : Flag<["-"], "fforce-emit-vtables">, Group<f_Group>,
19371937
HelpText<"Emits more virtual tables to improve devirtualization">;
19381938
def fno_force_emit_vtables : Flag<["-"], "fno-force-emit-vtables">, Group<f_Group>,
19391939
Flags<[CoreOption]>;
1940-
1941-
def fvirtual_function_elimination : Flag<["-"], "fvirtual-function-elimination">, Group<f_Group>,
1942-
Flags<[CoreOption, CC1Option]>,
1943-
HelpText<"Enables dead virtual function elimination optimization. Requires -flto=full">;
1944-
def fno_virtual_function_elimination : Flag<["-"], "fno-virtual-function_elimination">, Group<f_Group>,
1945-
Flags<[CoreOption]>;
1946-
19471940
def fwrapv : Flag<["-"], "fwrapv">, Group<f_Group>, Flags<[CC1Option]>,
19481941
HelpText<"Treat signed integer overflow as two's complement">;
19491942
def fwritable_strings : Flag<["-"], "fwritable-strings">, Group<f_Group>, Flags<[CC1Option]>,

clang/lib/CodeGen/CGClass.cpp

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2804,16 +2804,11 @@ void CodeGenFunction::EmitVTablePtrCheck(const CXXRecordDecl *RD,
28042804

28052805
bool CodeGenFunction::ShouldEmitVTableTypeCheckedLoad(const CXXRecordDecl *RD) {
28062806
if (!CGM.getCodeGenOpts().WholeProgramVTables ||
2807+
!SanOpts.has(SanitizerKind::CFIVCall) ||
2808+
!CGM.getCodeGenOpts().SanitizeTrap.has(SanitizerKind::CFIVCall) ||
28072809
!CGM.HasHiddenLTOVisibility(RD))
28082810
return false;
28092811

2810-
if (CGM.getCodeGenOpts().VirtualFunctionElimination)
2811-
return true;
2812-
2813-
if (!SanOpts.has(SanitizerKind::CFIVCall) ||
2814-
!CGM.getCodeGenOpts().SanitizeTrap.has(SanitizerKind::CFIVCall))
2815-
return false;
2816-
28172812
std::string TypeName = RD->getQualifiedNameAsString();
28182813
return !getContext().getSanitizerBlacklist().isBlacklistedType(
28192814
SanitizerKind::CFIVCall, TypeName);
@@ -2836,13 +2831,8 @@ llvm::Value *CodeGenFunction::EmitVTableTypeCheckedLoad(
28362831
TypeId});
28372832
llvm::Value *CheckResult = Builder.CreateExtractValue(CheckedLoad, 1);
28382833

2839-
std::string TypeName = RD->getQualifiedNameAsString();
2840-
if (SanOpts.has(SanitizerKind::CFIVCall) &&
2841-
!getContext().getSanitizerBlacklist().isBlacklistedType(
2842-
SanitizerKind::CFIVCall, TypeName)) {
2843-
EmitCheck(std::make_pair(CheckResult, SanitizerKind::CFIVCall),
2844-
SanitizerHandler::CFICheckFail, {}, {});
2845-
}
2834+
EmitCheck(std::make_pair(CheckResult, SanitizerKind::CFIVCall),
2835+
SanitizerHandler::CFICheckFail, nullptr, nullptr);
28462836

28472837
return Builder.CreateBitCast(
28482838
Builder.CreateExtractValue(CheckedLoad, 0),

clang/lib/CodeGen/CGVTables.cpp

Lines changed: 2 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -822,7 +822,7 @@ CodeGenVTables::GenerateConstructionVTable(const CXXRecordDecl *RD,
822822
assert(!VTable->isDeclaration() && "Shouldn't set properties on declaration");
823823
CGM.setGVProperties(VTable, RD);
824824

825-
CGM.EmitVTableTypeMetadata(RD, VTable, *VTLayout.get());
825+
CGM.EmitVTableTypeMetadata(VTable, *VTLayout.get());
826826

827827
return VTable;
828828
}
@@ -1053,32 +1053,7 @@ bool CodeGenModule::HasHiddenLTOVisibility(const CXXRecordDecl *RD) {
10531053
return true;
10541054
}
10551055

1056-
llvm::GlobalObject::VCallVisibility
1057-
CodeGenModule::GetVCallVisibilityLevel(const CXXRecordDecl *RD) {
1058-
LinkageInfo LV = RD->getLinkageAndVisibility();
1059-
llvm::GlobalObject::VCallVisibility TypeVis;
1060-
if (!isExternallyVisible(LV.getLinkage()))
1061-
TypeVis = llvm::GlobalObject::VCallVisibilityTranslationUnit;
1062-
else if (HasHiddenLTOVisibility(RD))
1063-
TypeVis = llvm::GlobalObject::VCallVisibilityLinkageUnit;
1064-
else
1065-
TypeVis = llvm::GlobalObject::VCallVisibilityPublic;
1066-
1067-
for (auto B : RD->bases())
1068-
if (B.getType()->getAsCXXRecordDecl()->isDynamicClass())
1069-
TypeVis = std::min(TypeVis,
1070-
GetVCallVisibilityLevel(B.getType()->getAsCXXRecordDecl()));
1071-
1072-
for (auto B : RD->vbases())
1073-
if (B.getType()->getAsCXXRecordDecl()->isDynamicClass())
1074-
TypeVis = std::min(TypeVis,
1075-
GetVCallVisibilityLevel(B.getType()->getAsCXXRecordDecl()));
1076-
1077-
return TypeVis;
1078-
}
1079-
1080-
void CodeGenModule::EmitVTableTypeMetadata(const CXXRecordDecl *RD,
1081-
llvm::GlobalVariable *VTable,
1056+
void CodeGenModule::EmitVTableTypeMetadata(llvm::GlobalVariable *VTable,
10821057
const VTableLayout &VTLayout) {
10831058
if (!getCodeGenOpts().LTOUnit)
10841059
return;
@@ -1138,10 +1113,4 @@ void CodeGenModule::EmitVTableTypeMetadata(const CXXRecordDecl *RD,
11381113
VTable->addTypeMetadata((PointerWidth * I).getQuantity(), MD);
11391114
}
11401115
}
1141-
1142-
if (getCodeGenOpts().VirtualFunctionElimination) {
1143-
llvm::GlobalObject::VCallVisibility TypeVis = GetVCallVisibilityLevel(RD);
1144-
if (TypeVis != llvm::GlobalObject::VCallVisibilityPublic)
1145-
VTable->addVCallVisibilityMetadata(TypeVis);
1146-
}
11471116
}

clang/lib/CodeGen/CodeGenModule.h

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1345,16 +1345,8 @@ class CodeGenModule : public CodeGenTypeCache {
13451345
/// optimization.
13461346
bool HasHiddenLTOVisibility(const CXXRecordDecl *RD);
13471347

1348-
/// Returns the vcall visibility of the given type. This is the scope in which
1349-
/// a virtual function call could be made which ends up being dispatched to a
1350-
/// member function of this class. This scope can be wider than the visibility
1351-
/// of the class itself when the class has a more-visible dynamic base class.
1352-
llvm::GlobalObject::VCallVisibility
1353-
GetVCallVisibilityLevel(const CXXRecordDecl *RD);
1354-
13551348
/// Emit type metadata for the given vtable using the given layout.
1356-
void EmitVTableTypeMetadata(const CXXRecordDecl *RD,
1357-
llvm::GlobalVariable *VTable,
1349+
void EmitVTableTypeMetadata(llvm::GlobalVariable *VTable,
13581350
const VTableLayout &VTLayout);
13591351

13601352
/// Generate a cross-DSO type identifier for MD.

clang/lib/CodeGen/ItaniumCXXABI.cpp

Lines changed: 35 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -668,88 +668,53 @@ CGCallee ItaniumCXXABI::EmitLoadOfMemberFunctionPointer(
668668
VTableOffset = Builder.CreateTrunc(VTableOffset, CGF.Int32Ty);
669669
VTableOffset = Builder.CreateZExt(VTableOffset, CGM.PtrDiffTy);
670670
}
671+
// Compute the address of the virtual function pointer.
672+
llvm::Value *VFPAddr = Builder.CreateGEP(VTable, VTableOffset);
671673

672674
// Check the address of the function pointer if CFI on member function
673675
// pointers is enabled.
674676
llvm::Constant *CheckSourceLocation;
675677
llvm::Constant *CheckTypeDesc;
676678
bool ShouldEmitCFICheck = CGF.SanOpts.has(SanitizerKind::CFIMFCall) &&
677679
CGM.HasHiddenLTOVisibility(RD);
678-
bool ShouldEmitVFEInfo = CGM.getCodeGenOpts().VirtualFunctionElimination &&
679-
CGM.HasHiddenLTOVisibility(RD);
680-
llvm::Value *VirtualFn = nullptr;
681-
682-
{
680+
if (ShouldEmitCFICheck) {
683681
CodeGenFunction::SanitizerScope SanScope(&CGF);
684-
llvm::Value *TypeId = nullptr;
685-
llvm::Value *CheckResult = nullptr;
686-
687-
if (ShouldEmitCFICheck || ShouldEmitVFEInfo) {
688-
// If doing CFI or VFE, we will need the metadata node to check against.
689-
llvm::Metadata *MD =
690-
CGM.CreateMetadataIdentifierForVirtualMemPtrType(QualType(MPT, 0));
691-
TypeId = llvm::MetadataAsValue::get(CGF.getLLVMContext(), MD);
692-
}
693682

694-
llvm::Value *VFPAddr = Builder.CreateGEP(VTable, VTableOffset);
695-
696-
if (ShouldEmitVFEInfo) {
697-
// If doing VFE, load from the vtable with a type.checked.load intrinsic
698-
// call. Note that we use the GEP to calculate the address to load from
699-
// and pass 0 as the offset to the intrinsic. This is because every
700-
// vtable slot of the correct type is marked with matching metadata, and
701-
// we know that the load must be from one of these slots.
702-
llvm::Value *CheckedLoad = Builder.CreateCall(
703-
CGM.getIntrinsic(llvm::Intrinsic::type_checked_load),
704-
{VFPAddr, llvm::ConstantInt::get(CGM.Int32Ty, 0), TypeId});
705-
CheckResult = Builder.CreateExtractValue(CheckedLoad, 1);
706-
VirtualFn = Builder.CreateExtractValue(CheckedLoad, 0);
707-
VirtualFn = Builder.CreateBitCast(VirtualFn, FTy->getPointerTo(),
708-
"memptr.virtualfn");
709-
} else {
710-
// When not doing VFE, emit a normal load, as it allows more
711-
// optimisations than type.checked.load.
712-
if (ShouldEmitCFICheck) {
713-
CheckResult = Builder.CreateCall(
714-
CGM.getIntrinsic(llvm::Intrinsic::type_test),
715-
{Builder.CreateBitCast(VFPAddr, CGF.Int8PtrTy), TypeId});
716-
}
717-
VFPAddr =
718-
Builder.CreateBitCast(VFPAddr, FTy->getPointerTo()->getPointerTo());
719-
VirtualFn = Builder.CreateAlignedLoad(VFPAddr, CGF.getPointerAlign(),
720-
"memptr.virtualfn");
721-
}
722-
assert(VirtualFn && "Virtual fuction pointer not created!");
723-
assert((!ShouldEmitCFICheck || !ShouldEmitVFEInfo || CheckResult) &&
724-
"Check result required but not created!");
725-
726-
if (ShouldEmitCFICheck) {
727-
// If doing CFI, emit the check.
728-
CheckSourceLocation = CGF.EmitCheckSourceLocation(E->getBeginLoc());
729-
CheckTypeDesc = CGF.EmitCheckTypeDescriptor(QualType(MPT, 0));
730-
llvm::Constant *StaticData[] = {
731-
llvm::ConstantInt::get(CGF.Int8Ty, CodeGenFunction::CFITCK_VMFCall),
732-
CheckSourceLocation,
733-
CheckTypeDesc,
734-
};
683+
CheckSourceLocation = CGF.EmitCheckSourceLocation(E->getBeginLoc());
684+
CheckTypeDesc = CGF.EmitCheckTypeDescriptor(QualType(MPT, 0));
685+
llvm::Constant *StaticData[] = {
686+
llvm::ConstantInt::get(CGF.Int8Ty, CodeGenFunction::CFITCK_VMFCall),
687+
CheckSourceLocation,
688+
CheckTypeDesc,
689+
};
735690

736-
if (CGM.getCodeGenOpts().SanitizeTrap.has(SanitizerKind::CFIMFCall)) {
737-
CGF.EmitTrapCheck(CheckResult);
738-
} else {
739-
llvm::Value *AllVtables = llvm::MetadataAsValue::get(
740-
CGM.getLLVMContext(),
741-
llvm::MDString::get(CGM.getLLVMContext(), "all-vtables"));
742-
llvm::Value *ValidVtable = Builder.CreateCall(
743-
CGM.getIntrinsic(llvm::Intrinsic::type_test), {VTable, AllVtables});
744-
CGF.EmitCheck(std::make_pair(CheckResult, SanitizerKind::CFIMFCall),
745-
SanitizerHandler::CFICheckFail, StaticData,
746-
{VTable, ValidVtable});
747-
}
691+
llvm::Metadata *MD =
692+
CGM.CreateMetadataIdentifierForVirtualMemPtrType(QualType(MPT, 0));
693+
llvm::Value *TypeId = llvm::MetadataAsValue::get(CGF.getLLVMContext(), MD);
694+
695+
llvm::Value *TypeTest = Builder.CreateCall(
696+
CGM.getIntrinsic(llvm::Intrinsic::type_test), {VFPAddr, TypeId});
748697

749-
FnVirtual = Builder.GetInsertBlock();
698+
if (CGM.getCodeGenOpts().SanitizeTrap.has(SanitizerKind::CFIMFCall)) {
699+
CGF.EmitTrapCheck(TypeTest);
700+
} else {
701+
llvm::Value *AllVtables = llvm::MetadataAsValue::get(
702+
CGM.getLLVMContext(),
703+
llvm::MDString::get(CGM.getLLVMContext(), "all-vtables"));
704+
llvm::Value *ValidVtable = Builder.CreateCall(
705+
CGM.getIntrinsic(llvm::Intrinsic::type_test), {VTable, AllVtables});
706+
CGF.EmitCheck(std::make_pair(TypeTest, SanitizerKind::CFIMFCall),
707+
SanitizerHandler::CFICheckFail, StaticData,
708+
{VTable, ValidVtable});
750709
}
751-
} // End of sanitizer scope
752710

711+
FnVirtual = Builder.GetInsertBlock();
712+
}
713+
714+
// Load the virtual function to call.
715+
VFPAddr = Builder.CreateBitCast(VFPAddr, FTy->getPointerTo()->getPointerTo());
716+
llvm::Value *VirtualFn = Builder.CreateAlignedLoad(
717+
VFPAddr, CGF.getPointerAlign(), "memptr.virtualfn");
753718
CGF.EmitBranch(FnEnd);
754719

755720
// In the non-virtual path, the function pointer is actually a
@@ -1811,7 +1776,7 @@ void ItaniumCXXABI::emitVTableDefinitions(CodeGenVTables &CGVT,
18111776
EmitFundamentalRTTIDescriptors(RD);
18121777

18131778
if (!VTable->isDeclarationForLinker())
1814-
CGM.EmitVTableTypeMetadata(RD, VTable, VTLayout);
1779+
CGM.EmitVTableTypeMetadata(VTable, VTLayout);
18151780
}
18161781

18171782
bool ItaniumCXXABI::isVirtualOffsetNeededForVTableField(

clang/lib/Driver/ToolChains/Clang.cpp

Lines changed: 3 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -5814,30 +5814,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
58145814
CmdArgs.push_back(Args.MakeArgString(TargetInfo.str()));
58155815
}
58165816

5817-
bool VirtualFunctionElimination =
5818-
Args.hasFlag(options::OPT_fvirtual_function_elimination,
5819-
options::OPT_fno_virtual_function_elimination, false);
5820-
if (VirtualFunctionElimination) {
5821-
// VFE requires full LTO (currently, this might be relaxed to allow ThinLTO
5822-
// in the future).
5823-
if (D.getLTOMode() != LTOK_Full)
5824-
D.Diag(diag::err_drv_argument_only_allowed_with)
5825-
<< "-fvirtual-function-elimination"
5826-
<< "-flto=full";
5827-
5828-
CmdArgs.push_back("-fvirtual-function-elimination");
5829-
}
5830-
5831-
// VFE requires whole-program-vtables, and enables it by default.
5832-
bool WholeProgramVTables = Args.hasFlag(
5833-
options::OPT_fwhole_program_vtables,
5834-
options::OPT_fno_whole_program_vtables, VirtualFunctionElimination);
5835-
if (VirtualFunctionElimination && !WholeProgramVTables) {
5836-
D.Diag(diag::err_drv_argument_not_allowed_with)
5837-
<< "-fno-whole-program-vtables"
5838-
<< "-fvirtual-function-elimination";
5839-
}
5840-
5817+
bool WholeProgramVTables =
5818+
Args.hasFlag(options::OPT_fwhole_program_vtables,
5819+
options::OPT_fno_whole_program_vtables, false);
58415820
if (WholeProgramVTables) {
58425821
if (!D.isUsingLTO())
58435822
D.Diag(diag::err_drv_argument_only_allowed_with)

clang/lib/Frontend/CompilerInvocation.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -844,8 +844,6 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
844844
Opts.CodeViewGHash = Args.hasArg(OPT_gcodeview_ghash);
845845
Opts.MacroDebugInfo = Args.hasArg(OPT_debug_info_macro);
846846
Opts.WholeProgramVTables = Args.hasArg(OPT_fwhole_program_vtables);
847-
Opts.VirtualFunctionElimination =
848-
Args.hasArg(OPT_fvirtual_function_elimination);
849847
Opts.LTOVisibilityPublicStd = Args.hasArg(OPT_flto_visibility_public_std);
850848
Opts.SplitDwarfFile = Args.getLastArgValue(OPT_split_dwarf_file);
851849
Opts.SplitDwarfOutput = Args.getLastArgValue(OPT_split_dwarf_output);

clang/test/CodeGenCXX/vcall-visibility-metadata.cpp

Lines changed: 0 additions & 88 deletions
This file was deleted.

0 commit comments

Comments
 (0)