summaryrefslogtreecommitdiffstats
path: root/clang/lib/CodeGen
diff options
context:
space:
mode:
authorPeter Collingbourne <peter@pcc.me.uk>2016-02-24 20:46:36 +0000
committerPeter Collingbourne <peter@pcc.me.uk>2016-02-24 20:46:36 +0000
commitfb532b9a340958494a5346f2230d51653e8ed31e (patch)
tree8b440293a23d1fb94658086ac9ef8c5266a7e449 /clang/lib/CodeGen
parent40afcb547e4302017bcb5c06ae2204084c3dc776 (diff)
downloadbcm5719-llvm-fb532b9a340958494a5346f2230d51653e8ed31e.tar.gz
bcm5719-llvm-fb532b9a340958494a5346f2230d51653e8ed31e.zip
Add whole-program vtable optimization feature to Clang.
This patch introduces the -fwhole-program-vtables flag, which enables the whole-program vtable optimization feature (D16795) in Clang. Differential Revision: http://reviews.llvm.org/D16821 llvm-svn: 261767
Diffstat (limited to 'clang/lib/CodeGen')
-rw-r--r--clang/lib/CodeGen/CGClass.cpp30
-rw-r--r--clang/lib/CodeGen/CGExprCXX.cpp3
-rw-r--r--clang/lib/CodeGen/CGVTables.cpp35
-rw-r--r--clang/lib/CodeGen/CodeGenFunction.h8
-rw-r--r--clang/lib/CodeGen/CodeGenModule.cpp4
-rw-r--r--clang/lib/CodeGen/CodeGenModule.h11
-rw-r--r--clang/lib/CodeGen/ItaniumCXXABI.cpp4
-rw-r--r--clang/lib/CodeGen/MicrosoftCXXABI.cpp19
8 files changed, 78 insertions, 36 deletions
diff --git a/clang/lib/CodeGen/CGClass.cpp b/clang/lib/CodeGen/CGClass.cpp
index 1ec700204ab..8a82be9e5f2 100644
--- a/clang/lib/CodeGen/CGClass.cpp
+++ b/clang/lib/CodeGen/CGClass.cpp
@@ -2485,15 +2485,35 @@ LeastDerivedClassWithSameLayout(const CXXRecordDecl *RD) {
RD->bases_begin()->getType()->getAsCXXRecordDecl());
}
-void CodeGenFunction::EmitVTablePtrCheckForCall(const CXXMethodDecl *MD,
+void CodeGenFunction::EmitBitSetCodeForVCall(const CXXRecordDecl *RD,
+ llvm::Value *VTable,
+ SourceLocation Loc) {
+ if (CGM.getCodeGenOpts().WholeProgramVTables &&
+ !CGM.IsBitSetBlacklistedRecord(RD)) {
+ llvm::Metadata *MD =
+ CGM.CreateMetadataIdentifierForType(QualType(RD->getTypeForDecl(), 0));
+ llvm::Value *BitSetName =
+ llvm::MetadataAsValue::get(CGM.getLLVMContext(), MD);
+
+ llvm::Value *CastedVTable = Builder.CreateBitCast(VTable, Int8PtrTy);
+ llvm::Value *BitSetTest =
+ Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::bitset_test),
+ {CastedVTable, BitSetName});
+ Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::assume), BitSetTest);
+ }
+
+ if (SanOpts.has(SanitizerKind::CFIVCall))
+ EmitVTablePtrCheckForCall(RD, VTable, CodeGenFunction::CFITCK_VCall, Loc);
+}
+
+void CodeGenFunction::EmitVTablePtrCheckForCall(const CXXRecordDecl *RD,
llvm::Value *VTable,
CFITypeCheckKind TCK,
SourceLocation Loc) {
- const CXXRecordDecl *ClassDecl = MD->getParent();
if (!SanOpts.has(SanitizerKind::CFICastStrict))
- ClassDecl = LeastDerivedClassWithSameLayout(ClassDecl);
+ RD = LeastDerivedClassWithSameLayout(RD);
- EmitVTablePtrCheck(ClassDecl, VTable, TCK, Loc);
+ EmitVTablePtrCheck(RD, VTable, TCK, Loc);
}
void CodeGenFunction::EmitVTablePtrCheckForCast(QualType T,
@@ -2545,7 +2565,7 @@ void CodeGenFunction::EmitVTablePtrCheck(const CXXRecordDecl *RD,
llvm::Value *VTable,
CFITypeCheckKind TCK,
SourceLocation Loc) {
- if (CGM.IsCFIBlacklistedRecord(RD))
+ if (CGM.IsBitSetBlacklistedRecord(RD))
return;
SanitizerScope SanScope(this);
diff --git a/clang/lib/CodeGen/CGExprCXX.cpp b/clang/lib/CodeGen/CGExprCXX.cpp
index 604cde76a7b..614b0769231 100644
--- a/clang/lib/CodeGen/CGExprCXX.cpp
+++ b/clang/lib/CodeGen/CGExprCXX.cpp
@@ -259,7 +259,8 @@ RValue CodeGenFunction::EmitCXXMemberOrOperatorMemberCallExpr(
if (SanOpts.has(SanitizerKind::CFINVCall) &&
MD->getParent()->isDynamicClass()) {
llvm::Value *VTable = GetVTablePtr(This, Int8PtrTy, MD->getParent());
- EmitVTablePtrCheckForCall(MD, VTable, CFITCK_NVCall, CE->getLocStart());
+ EmitVTablePtrCheckForCall(MD->getParent(), VTable, CFITCK_NVCall,
+ CE->getLocStart());
}
if (getLangOpts().AppleKext && MD->isVirtual() && HasQualifier)
diff --git a/clang/lib/CodeGen/CGVTables.cpp b/clang/lib/CodeGen/CGVTables.cpp
index e96a8120207..953053bd1c3 100644
--- a/clang/lib/CodeGen/CGVTables.cpp
+++ b/clang/lib/CodeGen/CGVTables.cpp
@@ -898,21 +898,34 @@ void CodeGenModule::EmitDeferredVTables() {
DeferredVTables.clear();
}
-bool CodeGenModule::IsCFIBlacklistedRecord(const CXXRecordDecl *RD) {
- if (RD->hasAttr<UuidAttr>() &&
- getContext().getSanitizerBlacklist().isBlacklistedType("attr:uuid"))
- return true;
+bool CodeGenModule::NeedVTableBitSets() {
+ return getCodeGenOpts().WholeProgramVTables ||
+ getLangOpts().Sanitize.has(SanitizerKind::CFIVCall) ||
+ getLangOpts().Sanitize.has(SanitizerKind::CFINVCall) ||
+ getLangOpts().Sanitize.has(SanitizerKind::CFIDerivedCast) ||
+ getLangOpts().Sanitize.has(SanitizerKind::CFIUnrelatedCast);
+}
+
+bool CodeGenModule::IsBitSetBlacklistedRecord(const CXXRecordDecl *RD) {
+ std::string TypeName = RD->getQualifiedNameAsString();
+ auto isInBlacklist = [&](const SanitizerBlacklist &BL) {
+ if (RD->hasAttr<UuidAttr>() && BL.isBlacklistedType("attr:uuid"))
+ return true;
+
+ return BL.isBlacklistedType(TypeName);
+ };
- return getContext().getSanitizerBlacklist().isBlacklistedType(
- RD->getQualifiedNameAsString());
+ return isInBlacklist(WholeProgramVTablesBlacklist) ||
+ ((LangOpts.Sanitize.has(SanitizerKind::CFIVCall) ||
+ LangOpts.Sanitize.has(SanitizerKind::CFINVCall) ||
+ LangOpts.Sanitize.has(SanitizerKind::CFIDerivedCast) ||
+ LangOpts.Sanitize.has(SanitizerKind::CFIUnrelatedCast)) &&
+ isInBlacklist(getContext().getSanitizerBlacklist()));
}
void CodeGenModule::EmitVTableBitSetEntries(llvm::GlobalVariable *VTable,
const VTableLayout &VTLayout) {
- if (!LangOpts.Sanitize.has(SanitizerKind::CFIVCall) &&
- !LangOpts.Sanitize.has(SanitizerKind::CFINVCall) &&
- !LangOpts.Sanitize.has(SanitizerKind::CFIDerivedCast) &&
- !LangOpts.Sanitize.has(SanitizerKind::CFIUnrelatedCast))
+ if (!NeedVTableBitSets())
return;
CharUnits PointerWidth =
@@ -922,7 +935,7 @@ void CodeGenModule::EmitVTableBitSetEntries(llvm::GlobalVariable *VTable,
std::vector<BSEntry> BitsetEntries;
// Create a bit set entry for each address point.
for (auto &&AP : VTLayout.getAddressPoints()) {
- if (IsCFIBlacklistedRecord(AP.first.getBase()))
+ if (IsBitSetBlacklistedRecord(AP.first.getBase()))
continue;
BitsetEntries.push_back(std::make_pair(AP.first.getBase(), AP.second));
diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h
index 1254a0f93fc..9a31c8f78b5 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -1401,7 +1401,7 @@ public:
/// EmitVTablePtrCheckForCall - Virtual method MD is being called via VTable.
/// If vptr CFI is enabled, emit a check that VTable is valid.
- void EmitVTablePtrCheckForCall(const CXXMethodDecl *MD, llvm::Value *VTable,
+ void EmitVTablePtrCheckForCall(const CXXRecordDecl *RD, llvm::Value *VTable,
CFITypeCheckKind TCK, SourceLocation Loc);
/// EmitVTablePtrCheck - Emit a check that VTable is a valid virtual table for
@@ -1409,6 +1409,12 @@ public:
void EmitVTablePtrCheck(const CXXRecordDecl *RD, llvm::Value *VTable,
CFITypeCheckKind TCK, SourceLocation Loc);
+ /// If whole-program virtual table optimization is enabled, emit an assumption
+ /// that VTable is a member of the type's bitset. Or, if vptr CFI is enabled,
+ /// emit a check that VTable is a member of the type's bitset.
+ void EmitBitSetCodeForVCall(const CXXRecordDecl *RD, llvm::Value *VTable,
+ SourceLocation Loc);
+
/// CanDevirtualizeMemberFunctionCalls - Checks whether virtual calls on given
/// expr can be devirtualized.
bool CanDevirtualizeMemberFunctionCall(const Expr *Base,
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index aabcc524c93..b98094f6656 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -97,7 +97,9 @@ CodeGenModule::CodeGenModule(ASTContext &C, const HeaderSearchOptions &HSO,
NSConcreteStackBlock(nullptr), BlockObjectAssign(nullptr),
BlockObjectDispose(nullptr), BlockDescriptorType(nullptr),
GenericBlockLiteralType(nullptr), LifetimeStartFn(nullptr),
- LifetimeEndFn(nullptr), SanitizerMD(new SanitizerMetadata(*this)) {
+ LifetimeEndFn(nullptr), SanitizerMD(new SanitizerMetadata(*this)),
+ WholeProgramVTablesBlacklist(CGO.WholeProgramVTablesBlacklistFiles,
+ C.getSourceManager()) {
// Initialize the type cache.
llvm::LLVMContext &LLVMContext = M.getContext();
diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h
index f8084ef43d9..db2df793dbc 100644
--- a/clang/lib/CodeGen/CodeGenModule.h
+++ b/clang/lib/CodeGen/CodeGenModule.h
@@ -489,6 +489,8 @@ private:
/// MDNodes.
llvm::DenseMap<QualType, llvm::Metadata *> MetadataIdMap;
+ SanitizerBlacklist WholeProgramVTablesBlacklist;
+
public:
CodeGenModule(ASTContext &C, const HeaderSearchOptions &headersearchopts,
const PreprocessorOptions &ppopts,
@@ -1108,9 +1110,12 @@ public:
/// \param D Threadprivate declaration.
void EmitOMPThreadPrivateDecl(const OMPThreadPrivateDecl *D);
- /// Returns whether the given record is blacklisted from control flow
- /// integrity checks.
- bool IsCFIBlacklistedRecord(const CXXRecordDecl *RD);
+ /// Returns whether we need bit sets attached to vtables.
+ bool NeedVTableBitSets();
+
+ /// Returns whether the given record is blacklisted from whole-program
+ /// transformations (i.e. CFI or whole-program vtable optimization).
+ bool IsBitSetBlacklistedRecord(const CXXRecordDecl *RD);
/// Emit bit set entries for the given vtable using the given layout if
/// vptr CFI is enabled.
diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp
index 9d7b4da2c53..42ee9d7772c 100644
--- a/clang/lib/CodeGen/ItaniumCXXABI.cpp
+++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp
@@ -1602,9 +1602,7 @@ llvm::Value *ItaniumCXXABI::getVirtualFunctionPointer(CodeGenFunction &CGF,
auto *MethodDecl = cast<CXXMethodDecl>(GD.getDecl());
llvm::Value *VTable = CGF.GetVTablePtr(This, Ty, MethodDecl->getParent());
- if (CGF.SanOpts.has(SanitizerKind::CFIVCall))
- CGF.EmitVTablePtrCheckForCall(MethodDecl, VTable,
- CodeGenFunction::CFITCK_VCall, Loc);
+ CGF.EmitBitSetCodeForVCall(MethodDecl->getParent(), VTable, Loc);
uint64_t VTableIndex = CGM.getItaniumVTableContext().getMethodVTableIndex(GD);
llvm::Value *VFuncPtr =
diff --git a/clang/lib/CodeGen/MicrosoftCXXABI.cpp b/clang/lib/CodeGen/MicrosoftCXXABI.cpp
index eecb12c6595..ebf5497f0ec 100644
--- a/clang/lib/CodeGen/MicrosoftCXXABI.cpp
+++ b/clang/lib/CodeGen/MicrosoftCXXABI.cpp
@@ -1503,10 +1503,7 @@ void MicrosoftCXXABI::EmitDestructorCall(CodeGenFunction &CGF,
void MicrosoftCXXABI::emitVTableBitSetEntries(VPtrInfo *Info,
const CXXRecordDecl *RD,
llvm::GlobalVariable *VTable) {
- if (!getContext().getLangOpts().Sanitize.has(SanitizerKind::CFIVCall) &&
- !getContext().getLangOpts().Sanitize.has(SanitizerKind::CFINVCall) &&
- !getContext().getLangOpts().Sanitize.has(SanitizerKind::CFIDerivedCast) &&
- !getContext().getLangOpts().Sanitize.has(SanitizerKind::CFIUnrelatedCast))
+ if (!CGM.NeedVTableBitSets())
return;
llvm::NamedMDNode *BitsetsMD =
@@ -1522,13 +1519,13 @@ void MicrosoftCXXABI::emitVTableBitSetEntries(VPtrInfo *Info,
: CharUnits::Zero();
if (Info->PathToBaseWithVPtr.empty()) {
- if (!CGM.IsCFIBlacklistedRecord(RD))
+ if (!CGM.IsBitSetBlacklistedRecord(RD))
CGM.CreateVTableBitSetEntry(BitsetsMD, VTable, AddressPoint, RD);
return;
}
// Add a bitset entry for the least derived base belonging to this vftable.
- if (!CGM.IsCFIBlacklistedRecord(Info->PathToBaseWithVPtr.back()))
+ if (!CGM.IsBitSetBlacklistedRecord(Info->PathToBaseWithVPtr.back()))
CGM.CreateVTableBitSetEntry(BitsetsMD, VTable, AddressPoint,
Info->PathToBaseWithVPtr.back());
@@ -1548,12 +1545,12 @@ void MicrosoftCXXABI::emitVTableBitSetEntries(VPtrInfo *Info,
Offset = VBI->second.VBaseOffset;
if (!Offset.isZero())
return;
- if (!CGM.IsCFIBlacklistedRecord(DerivedRD))
+ if (!CGM.IsBitSetBlacklistedRecord(DerivedRD))
CGM.CreateVTableBitSetEntry(BitsetsMD, VTable, AddressPoint, DerivedRD);
}
// Finally do the same for the most derived class.
- if (Info->FullOffsetInMDC.isZero() && !CGM.IsCFIBlacklistedRecord(RD))
+ if (Info->FullOffsetInMDC.isZero() && !CGM.IsBitSetBlacklistedRecord(RD))
CGM.CreateVTableBitSetEntry(BitsetsMD, VTable, AddressPoint, RD);
}
@@ -1822,9 +1819,9 @@ llvm::Value *MicrosoftCXXABI::getVirtualFunctionPointer(CodeGenFunction &CGF,
MicrosoftVTableContext::MethodVFTableLocation ML =
CGM.getMicrosoftVTableContext().getMethodVFTableLocation(GD);
- if (CGF.SanOpts.has(SanitizerKind::CFIVCall))
- CGF.EmitVTablePtrCheck(getClassAtVTableLocation(getContext(), GD, ML),
- VTable, CodeGenFunction::CFITCK_VCall, Loc);
+ if (CGM.NeedVTableBitSets())
+ CGF.EmitBitSetCodeForVCall(getClassAtVTableLocation(getContext(), GD, ML),
+ VTable, Loc);
llvm::Value *VFuncPtr =
Builder.CreateConstInBoundsGEP1_64(VTable, ML.Index, "vfn");
OpenPOWER on IntegriCloud