Skip to content

Revert "Reland: Dead Virtual Function Elimination" #615

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 23, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
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
4 changes: 0 additions & 4 deletions clang/include/clang/Basic/CodeGenOptions.def
Original file line number Diff line number Diff line change
Expand Up @@ -287,10 +287,6 @@ CODEGENOPT(EmitLLVMUseLists, 1, 0) ///< Control whether to serialize use-lists.
CODEGENOPT(WholeProgramVTables, 1, 0) ///< Whether to apply whole-program
/// vtable optimization.

CODEGENOPT(VirtualFunctionElimination, 1, 0) ///< Whether to apply the dead
/// virtual function elimination
/// optimization.

/// Whether to use public LTO visibility for entities in std and stdext
/// namespaces. This is enabled by clang-cl's /MT and /MTd flags.
CODEGENOPT(LTOVisibilityPublicStd, 1, 0)
Expand Down
7 changes: 0 additions & 7 deletions clang/include/clang/Driver/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -1937,13 +1937,6 @@ def fforce_emit_vtables : Flag<["-"], "fforce-emit-vtables">, Group<f_Group>,
HelpText<"Emits more virtual tables to improve devirtualization">;
def fno_force_emit_vtables : Flag<["-"], "fno-force-emit-vtables">, Group<f_Group>,
Flags<[CoreOption]>;

def fvirtual_function_elimination : Flag<["-"], "fvirtual-function-elimination">, Group<f_Group>,
Flags<[CoreOption, CC1Option]>,
HelpText<"Enables dead virtual function elimination optimization. Requires -flto=full">;
def fno_virtual_function_elimination : Flag<["-"], "fno-virtual-function_elimination">, Group<f_Group>,
Flags<[CoreOption]>;

def fwrapv : Flag<["-"], "fwrapv">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Treat signed integer overflow as two's complement">;
def fwritable_strings : Flag<["-"], "fwritable-strings">, Group<f_Group>, Flags<[CC1Option]>,
Expand Down
18 changes: 4 additions & 14 deletions clang/lib/CodeGen/CGClass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2804,16 +2804,11 @@ void CodeGenFunction::EmitVTablePtrCheck(const CXXRecordDecl *RD,

bool CodeGenFunction::ShouldEmitVTableTypeCheckedLoad(const CXXRecordDecl *RD) {
if (!CGM.getCodeGenOpts().WholeProgramVTables ||
!SanOpts.has(SanitizerKind::CFIVCall) ||
!CGM.getCodeGenOpts().SanitizeTrap.has(SanitizerKind::CFIVCall) ||
!CGM.HasHiddenLTOVisibility(RD))
return false;

if (CGM.getCodeGenOpts().VirtualFunctionElimination)
return true;

if (!SanOpts.has(SanitizerKind::CFIVCall) ||
!CGM.getCodeGenOpts().SanitizeTrap.has(SanitizerKind::CFIVCall))
return false;

std::string TypeName = RD->getQualifiedNameAsString();
return !getContext().getSanitizerBlacklist().isBlacklistedType(
SanitizerKind::CFIVCall, TypeName);
Expand All @@ -2836,13 +2831,8 @@ llvm::Value *CodeGenFunction::EmitVTableTypeCheckedLoad(
TypeId});
llvm::Value *CheckResult = Builder.CreateExtractValue(CheckedLoad, 1);

std::string TypeName = RD->getQualifiedNameAsString();
if (SanOpts.has(SanitizerKind::CFIVCall) &&
!getContext().getSanitizerBlacklist().isBlacklistedType(
SanitizerKind::CFIVCall, TypeName)) {
EmitCheck(std::make_pair(CheckResult, SanitizerKind::CFIVCall),
SanitizerHandler::CFICheckFail, {}, {});
}
EmitCheck(std::make_pair(CheckResult, SanitizerKind::CFIVCall),
SanitizerHandler::CFICheckFail, nullptr, nullptr);

return Builder.CreateBitCast(
Builder.CreateExtractValue(CheckedLoad, 0),
Expand Down
35 changes: 2 additions & 33 deletions clang/lib/CodeGen/CGVTables.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -822,7 +822,7 @@ CodeGenVTables::GenerateConstructionVTable(const CXXRecordDecl *RD,
assert(!VTable->isDeclaration() && "Shouldn't set properties on declaration");
CGM.setGVProperties(VTable, RD);

CGM.EmitVTableTypeMetadata(RD, VTable, *VTLayout.get());
CGM.EmitVTableTypeMetadata(VTable, *VTLayout.get());

return VTable;
}
Expand Down Expand Up @@ -1053,32 +1053,7 @@ bool CodeGenModule::HasHiddenLTOVisibility(const CXXRecordDecl *RD) {
return true;
}

llvm::GlobalObject::VCallVisibility
CodeGenModule::GetVCallVisibilityLevel(const CXXRecordDecl *RD) {
LinkageInfo LV = RD->getLinkageAndVisibility();
llvm::GlobalObject::VCallVisibility TypeVis;
if (!isExternallyVisible(LV.getLinkage()))
TypeVis = llvm::GlobalObject::VCallVisibilityTranslationUnit;
else if (HasHiddenLTOVisibility(RD))
TypeVis = llvm::GlobalObject::VCallVisibilityLinkageUnit;
else
TypeVis = llvm::GlobalObject::VCallVisibilityPublic;

for (auto B : RD->bases())
if (B.getType()->getAsCXXRecordDecl()->isDynamicClass())
TypeVis = std::min(TypeVis,
GetVCallVisibilityLevel(B.getType()->getAsCXXRecordDecl()));

for (auto B : RD->vbases())
if (B.getType()->getAsCXXRecordDecl()->isDynamicClass())
TypeVis = std::min(TypeVis,
GetVCallVisibilityLevel(B.getType()->getAsCXXRecordDecl()));

return TypeVis;
}

void CodeGenModule::EmitVTableTypeMetadata(const CXXRecordDecl *RD,
llvm::GlobalVariable *VTable,
void CodeGenModule::EmitVTableTypeMetadata(llvm::GlobalVariable *VTable,
const VTableLayout &VTLayout) {
if (!getCodeGenOpts().LTOUnit)
return;
Expand Down Expand Up @@ -1138,10 +1113,4 @@ void CodeGenModule::EmitVTableTypeMetadata(const CXXRecordDecl *RD,
VTable->addTypeMetadata((PointerWidth * I).getQuantity(), MD);
}
}

if (getCodeGenOpts().VirtualFunctionElimination) {
llvm::GlobalObject::VCallVisibility TypeVis = GetVCallVisibilityLevel(RD);
if (TypeVis != llvm::GlobalObject::VCallVisibilityPublic)
VTable->addVCallVisibilityMetadata(TypeVis);
}
}
10 changes: 1 addition & 9 deletions clang/lib/CodeGen/CodeGenModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -1345,16 +1345,8 @@ class CodeGenModule : public CodeGenTypeCache {
/// optimization.
bool HasHiddenLTOVisibility(const CXXRecordDecl *RD);

/// Returns the vcall visibility of the given type. This is the scope in which
/// a virtual function call could be made which ends up being dispatched to a
/// member function of this class. This scope can be wider than the visibility
/// of the class itself when the class has a more-visible dynamic base class.
llvm::GlobalObject::VCallVisibility
GetVCallVisibilityLevel(const CXXRecordDecl *RD);

/// Emit type metadata for the given vtable using the given layout.
void EmitVTableTypeMetadata(const CXXRecordDecl *RD,
llvm::GlobalVariable *VTable,
void EmitVTableTypeMetadata(llvm::GlobalVariable *VTable,
const VTableLayout &VTLayout);

/// Generate a cross-DSO type identifier for MD.
Expand Down
105 changes: 35 additions & 70 deletions clang/lib/CodeGen/ItaniumCXXABI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -668,88 +668,53 @@ CGCallee ItaniumCXXABI::EmitLoadOfMemberFunctionPointer(
VTableOffset = Builder.CreateTrunc(VTableOffset, CGF.Int32Ty);
VTableOffset = Builder.CreateZExt(VTableOffset, CGM.PtrDiffTy);
}
// Compute the address of the virtual function pointer.
llvm::Value *VFPAddr = Builder.CreateGEP(VTable, VTableOffset);

// Check the address of the function pointer if CFI on member function
// pointers is enabled.
llvm::Constant *CheckSourceLocation;
llvm::Constant *CheckTypeDesc;
bool ShouldEmitCFICheck = CGF.SanOpts.has(SanitizerKind::CFIMFCall) &&
CGM.HasHiddenLTOVisibility(RD);
bool ShouldEmitVFEInfo = CGM.getCodeGenOpts().VirtualFunctionElimination &&
CGM.HasHiddenLTOVisibility(RD);
llvm::Value *VirtualFn = nullptr;

{
if (ShouldEmitCFICheck) {
CodeGenFunction::SanitizerScope SanScope(&CGF);
llvm::Value *TypeId = nullptr;
llvm::Value *CheckResult = nullptr;

if (ShouldEmitCFICheck || ShouldEmitVFEInfo) {
// If doing CFI or VFE, we will need the metadata node to check against.
llvm::Metadata *MD =
CGM.CreateMetadataIdentifierForVirtualMemPtrType(QualType(MPT, 0));
TypeId = llvm::MetadataAsValue::get(CGF.getLLVMContext(), MD);
}

llvm::Value *VFPAddr = Builder.CreateGEP(VTable, VTableOffset);

if (ShouldEmitVFEInfo) {
// If doing VFE, load from the vtable with a type.checked.load intrinsic
// call. Note that we use the GEP to calculate the address to load from
// and pass 0 as the offset to the intrinsic. This is because every
// vtable slot of the correct type is marked with matching metadata, and
// we know that the load must be from one of these slots.
llvm::Value *CheckedLoad = Builder.CreateCall(
CGM.getIntrinsic(llvm::Intrinsic::type_checked_load),
{VFPAddr, llvm::ConstantInt::get(CGM.Int32Ty, 0), TypeId});
CheckResult = Builder.CreateExtractValue(CheckedLoad, 1);
VirtualFn = Builder.CreateExtractValue(CheckedLoad, 0);
VirtualFn = Builder.CreateBitCast(VirtualFn, FTy->getPointerTo(),
"memptr.virtualfn");
} else {
// When not doing VFE, emit a normal load, as it allows more
// optimisations than type.checked.load.
if (ShouldEmitCFICheck) {
CheckResult = Builder.CreateCall(
CGM.getIntrinsic(llvm::Intrinsic::type_test),
{Builder.CreateBitCast(VFPAddr, CGF.Int8PtrTy), TypeId});
}
VFPAddr =
Builder.CreateBitCast(VFPAddr, FTy->getPointerTo()->getPointerTo());
VirtualFn = Builder.CreateAlignedLoad(VFPAddr, CGF.getPointerAlign(),
"memptr.virtualfn");
}
assert(VirtualFn && "Virtual fuction pointer not created!");
assert((!ShouldEmitCFICheck || !ShouldEmitVFEInfo || CheckResult) &&
"Check result required but not created!");

if (ShouldEmitCFICheck) {
// If doing CFI, emit the check.
CheckSourceLocation = CGF.EmitCheckSourceLocation(E->getBeginLoc());
CheckTypeDesc = CGF.EmitCheckTypeDescriptor(QualType(MPT, 0));
llvm::Constant *StaticData[] = {
llvm::ConstantInt::get(CGF.Int8Ty, CodeGenFunction::CFITCK_VMFCall),
CheckSourceLocation,
CheckTypeDesc,
};
CheckSourceLocation = CGF.EmitCheckSourceLocation(E->getBeginLoc());
CheckTypeDesc = CGF.EmitCheckTypeDescriptor(QualType(MPT, 0));
llvm::Constant *StaticData[] = {
llvm::ConstantInt::get(CGF.Int8Ty, CodeGenFunction::CFITCK_VMFCall),
CheckSourceLocation,
CheckTypeDesc,
};

if (CGM.getCodeGenOpts().SanitizeTrap.has(SanitizerKind::CFIMFCall)) {
CGF.EmitTrapCheck(CheckResult);
} else {
llvm::Value *AllVtables = llvm::MetadataAsValue::get(
CGM.getLLVMContext(),
llvm::MDString::get(CGM.getLLVMContext(), "all-vtables"));
llvm::Value *ValidVtable = Builder.CreateCall(
CGM.getIntrinsic(llvm::Intrinsic::type_test), {VTable, AllVtables});
CGF.EmitCheck(std::make_pair(CheckResult, SanitizerKind::CFIMFCall),
SanitizerHandler::CFICheckFail, StaticData,
{VTable, ValidVtable});
}
llvm::Metadata *MD =
CGM.CreateMetadataIdentifierForVirtualMemPtrType(QualType(MPT, 0));
llvm::Value *TypeId = llvm::MetadataAsValue::get(CGF.getLLVMContext(), MD);

llvm::Value *TypeTest = Builder.CreateCall(
CGM.getIntrinsic(llvm::Intrinsic::type_test), {VFPAddr, TypeId});

FnVirtual = Builder.GetInsertBlock();
if (CGM.getCodeGenOpts().SanitizeTrap.has(SanitizerKind::CFIMFCall)) {
CGF.EmitTrapCheck(TypeTest);
} else {
llvm::Value *AllVtables = llvm::MetadataAsValue::get(
CGM.getLLVMContext(),
llvm::MDString::get(CGM.getLLVMContext(), "all-vtables"));
llvm::Value *ValidVtable = Builder.CreateCall(
CGM.getIntrinsic(llvm::Intrinsic::type_test), {VTable, AllVtables});
CGF.EmitCheck(std::make_pair(TypeTest, SanitizerKind::CFIMFCall),
SanitizerHandler::CFICheckFail, StaticData,
{VTable, ValidVtable});
}
} // End of sanitizer scope

FnVirtual = Builder.GetInsertBlock();
}

// Load the virtual function to call.
VFPAddr = Builder.CreateBitCast(VFPAddr, FTy->getPointerTo()->getPointerTo());
llvm::Value *VirtualFn = Builder.CreateAlignedLoad(
VFPAddr, CGF.getPointerAlign(), "memptr.virtualfn");
CGF.EmitBranch(FnEnd);

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

if (!VTable->isDeclarationForLinker())
CGM.EmitVTableTypeMetadata(RD, VTable, VTLayout);
CGM.EmitVTableTypeMetadata(VTable, VTLayout);
}

bool ItaniumCXXABI::isVirtualOffsetNeededForVTableField(
Expand Down
27 changes: 3 additions & 24 deletions clang/lib/Driver/ToolChains/Clang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5814,30 +5814,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(Args.MakeArgString(TargetInfo.str()));
}

bool VirtualFunctionElimination =
Args.hasFlag(options::OPT_fvirtual_function_elimination,
options::OPT_fno_virtual_function_elimination, false);
if (VirtualFunctionElimination) {
// VFE requires full LTO (currently, this might be relaxed to allow ThinLTO
// in the future).
if (D.getLTOMode() != LTOK_Full)
D.Diag(diag::err_drv_argument_only_allowed_with)
<< "-fvirtual-function-elimination"
<< "-flto=full";

CmdArgs.push_back("-fvirtual-function-elimination");
}

// VFE requires whole-program-vtables, and enables it by default.
bool WholeProgramVTables = Args.hasFlag(
options::OPT_fwhole_program_vtables,
options::OPT_fno_whole_program_vtables, VirtualFunctionElimination);
if (VirtualFunctionElimination && !WholeProgramVTables) {
D.Diag(diag::err_drv_argument_not_allowed_with)
<< "-fno-whole-program-vtables"
<< "-fvirtual-function-elimination";
}

bool WholeProgramVTables =
Args.hasFlag(options::OPT_fwhole_program_vtables,
options::OPT_fno_whole_program_vtables, false);
if (WholeProgramVTables) {
if (!D.isUsingLTO())
D.Diag(diag::err_drv_argument_only_allowed_with)
Expand Down
2 changes: 0 additions & 2 deletions clang/lib/Frontend/CompilerInvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -844,8 +844,6 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
Opts.CodeViewGHash = Args.hasArg(OPT_gcodeview_ghash);
Opts.MacroDebugInfo = Args.hasArg(OPT_debug_info_macro);
Opts.WholeProgramVTables = Args.hasArg(OPT_fwhole_program_vtables);
Opts.VirtualFunctionElimination =
Args.hasArg(OPT_fvirtual_function_elimination);
Opts.LTOVisibilityPublicStd = Args.hasArg(OPT_flto_visibility_public_std);
Opts.SplitDwarfFile = Args.getLastArgValue(OPT_split_dwarf_file);
Opts.SplitDwarfOutput = Args.getLastArgValue(OPT_split_dwarf_output);
Expand Down
88 changes: 0 additions & 88 deletions clang/test/CodeGenCXX/vcall-visibility-metadata.cpp

This file was deleted.

Loading