CodeGen: Update Clang to use the new type metadata.

Differential Revision: http://reviews.llvm.org/D21054

llvm-svn: 273730
This commit is contained in:
Peter Collingbourne 2016-06-24 21:21:46 +00:00
parent 7efd750607
commit 8dd14da0dc
22 changed files with 422 additions and 441 deletions

View File

@ -90,10 +90,10 @@ For example on x86 a typical virtual call may look like this:
The compiler relies on co-operation from the linker in order to assemble
the bit vectors for the whole program. It currently does this using LLVM's
`bit sets`_ mechanism together with link-time optimization.
`type metadata`_ mechanism together with link-time optimization.
.. _address point: https://mentorembedded.github.io/cxx-abi/abi.html#vtable-general
.. _bit sets: http://llvm.org/docs/BitSets.html
.. _type metadata: http://llvm.org/docs/TypeMetadata.html
.. _ByteArrayBuilder: http://llvm.org/docs/doxygen/html/structllvm_1_1ByteArrayBuilder.html
Optimizations
@ -196,7 +196,7 @@ those sub-hierarchies need to be (see "Stripping Leading/Trailing Zeros in Bit
Vectors" above). The `GlobalLayoutBuilder`_ class is responsible for laying
out the globals efficiently to minimize the sizes of the underlying bitsets.
.. _GlobalLayoutBuilder: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Transforms/IPO/LowerBitSets.h?view=markup
.. _GlobalLayoutBuilder: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Transforms/IPO/LowerTypeTests.h?view=markup
Alignment
~~~~~~~~~
@ -297,8 +297,8 @@ file's symbol table, the symbols for the target functions also refer to the
jump table entries, so that addresses taken outside the module will pass
any verification done inside the module.
In more concrete terms, suppose we have three functions ``f``, ``g``, ``h``
which are members of a single bitset, and a function foo that returns their
In more concrete terms, suppose we have three functions ``f``, ``g``,
``h`` which are all of the same type, and a function foo that returns their
addresses:
.. code-block:: none
@ -439,10 +439,10 @@ export this information, every DSO implements
void __cfi_check(uint64 CallSiteTypeId, void *TargetAddr)
This function provides external modules with access to CFI checks for
the targets inside this DSO. For each known ``CallSiteTypeId``, this
functions performs an ``llvm.bitset.test`` with the corresponding bit
set. It aborts if the type is unknown, or if the check fails.
This function provides external modules with access to CFI checks for the
targets inside this DSO. For each known ``CallSiteTypeId``, this function
performs an ``llvm.type.test`` with the corresponding type identifier. It
aborts if the type is unknown, or if the check fails.
The basic implementation is a large switch statement over all values
of CallSiteTypeId supported by this DSO, and each case is similar to

View File

@ -2485,21 +2485,21 @@ LeastDerivedClassWithSameLayout(const CXXRecordDecl *RD) {
RD->bases_begin()->getType()->getAsCXXRecordDecl());
}
void CodeGenFunction::EmitBitSetCodeForVCall(const CXXRecordDecl *RD,
llvm::Value *VTable,
SourceLocation Loc) {
void CodeGenFunction::EmitTypeMetadataCodeForVCall(const CXXRecordDecl *RD,
llvm::Value *VTable,
SourceLocation Loc) {
if (CGM.getCodeGenOpts().WholeProgramVTables &&
CGM.HasHiddenLTOVisibility(RD)) {
llvm::Metadata *MD =
CGM.CreateMetadataIdentifierForType(QualType(RD->getTypeForDecl(), 0));
llvm::Value *BitSetName =
llvm::Value *TypeId =
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);
llvm::Value *TypeTest =
Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::type_test),
{CastedVTable, TypeId});
Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::assume), TypeTest);
}
if (SanOpts.has(SanitizerKind::CFIVCall))
@ -2595,12 +2595,11 @@ void CodeGenFunction::EmitVTablePtrCheck(const CXXRecordDecl *RD,
llvm::Metadata *MD =
CGM.CreateMetadataIdentifierForType(QualType(RD->getTypeForDecl(), 0));
llvm::Value *BitSetName = llvm::MetadataAsValue::get(getLLVMContext(), MD);
llvm::Value *TypeId = llvm::MetadataAsValue::get(getLLVMContext(), MD);
llvm::Value *CastedVTable = Builder.CreateBitCast(VTable, Int8PtrTy);
llvm::Value *BitSetTest =
Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::bitset_test),
{CastedVTable, BitSetName});
llvm::Value *TypeTest = Builder.CreateCall(
CGM.getIntrinsic(llvm::Intrinsic::type_test), {CastedVTable, TypeId});
SanitizerMask M;
switch (TCK) {
@ -2626,24 +2625,23 @@ void CodeGenFunction::EmitVTablePtrCheck(const CXXRecordDecl *RD,
EmitCheckTypeDescriptor(QualType(RD->getTypeForDecl(), 0)),
};
auto TypeId = CGM.CreateCfiIdForTypeMetadata(MD);
if (CGM.getCodeGenOpts().SanitizeCfiCrossDso && TypeId) {
EmitCfiSlowPathCheck(M, BitSetTest, TypeId, CastedVTable, StaticData);
auto CrossDsoTypeId = CGM.CreateCrossDsoCfiTypeId(MD);
if (CGM.getCodeGenOpts().SanitizeCfiCrossDso && CrossDsoTypeId) {
EmitCfiSlowPathCheck(M, TypeTest, CrossDsoTypeId, CastedVTable, StaticData);
return;
}
if (CGM.getCodeGenOpts().SanitizeTrap.has(M)) {
EmitTrapCheck(BitSetTest);
EmitTrapCheck(TypeTest);
return;
}
llvm::Value *AllVtables = llvm::MetadataAsValue::get(
CGM.getLLVMContext(),
llvm::MDString::get(CGM.getLLVMContext(), "all-vtables"));
llvm::Value *ValidVtable =
Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::bitset_test),
{CastedVTable, AllVtables});
EmitCheck(std::make_pair(BitSetTest, M), "cfi_check_fail", StaticData,
llvm::Value *ValidVtable = Builder.CreateCall(
CGM.getIntrinsic(llvm::Intrinsic::type_test), {CastedVTable, AllVtables});
EmitCheck(std::make_pair(TypeTest, M), "cfi_check_fail", StaticData,
{CastedVTable, ValidVtable});
}

View File

@ -2682,7 +2682,7 @@ void CodeGenFunction::EmitCfiCheckFail() {
CGM.getLLVMContext(),
llvm::MDString::get(CGM.getLLVMContext(), "all-vtables"));
llvm::Value *ValidVtable = Builder.CreateZExt(
Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::bitset_test),
Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::type_test),
{Addr, AllVtables}),
IntPtrTy);
@ -4050,24 +4050,23 @@ RValue CodeGenFunction::EmitCall(QualType CalleeType, llvm::Value *Callee,
EmitSanitizerStatReport(llvm::SanStat_CFI_ICall);
llvm::Metadata *MD = CGM.CreateMetadataIdentifierForType(QualType(FnType, 0));
llvm::Value *BitSetName = llvm::MetadataAsValue::get(getLLVMContext(), MD);
llvm::Value *TypeId = llvm::MetadataAsValue::get(getLLVMContext(), MD);
llvm::Value *CastedCallee = Builder.CreateBitCast(Callee, Int8PtrTy);
llvm::Value *BitSetTest =
Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::bitset_test),
{CastedCallee, BitSetName});
llvm::Value *TypeTest = Builder.CreateCall(
CGM.getIntrinsic(llvm::Intrinsic::type_test), {CastedCallee, TypeId});
auto TypeId = CGM.CreateCfiIdForTypeMetadata(MD);
auto CrossDsoTypeId = CGM.CreateCrossDsoCfiTypeId(MD);
llvm::Constant *StaticData[] = {
llvm::ConstantInt::get(Int8Ty, CFITCK_ICall),
EmitCheckSourceLocation(E->getLocStart()),
EmitCheckTypeDescriptor(QualType(FnType, 0)),
};
if (CGM.getCodeGenOpts().SanitizeCfiCrossDso && TypeId) {
EmitCfiSlowPathCheck(SanitizerKind::CFIICall, BitSetTest, TypeId,
if (CGM.getCodeGenOpts().SanitizeCfiCrossDso && CrossDsoTypeId) {
EmitCfiSlowPathCheck(SanitizerKind::CFIICall, TypeTest, CrossDsoTypeId,
CastedCallee, StaticData);
} else {
EmitCheck(std::make_pair(BitSetTest, SanitizerKind::CFIICall),
EmitCheck(std::make_pair(TypeTest, SanitizerKind::CFIICall),
"cfi_check_fail", StaticData,
{CastedCallee, llvm::UndefValue::get(IntPtrTy)});
}

View File

@ -709,7 +709,7 @@ CodeGenVTables::GenerateConstructionVTable(const CXXRecordDecl *RD,
VTLayout->getNumVTableThunks(), RTTI);
VTable->setInitializer(Init);
CGM.EmitVTableBitSetEntries(VTable, *VTLayout.get());
CGM.EmitVTableTypeMetadata(VTable, *VTLayout.get());
return VTable;
}
@ -933,8 +933,8 @@ bool CodeGenModule::HasHiddenLTOVisibility(const CXXRecordDecl *RD) {
return true;
}
void CodeGenModule::EmitVTableBitSetEntries(llvm::GlobalVariable *VTable,
const VTableLayout &VTLayout) {
void CodeGenModule::EmitVTableTypeMetadata(llvm::GlobalVariable *VTable,
const VTableLayout &VTLayout) {
if (!getCodeGenOpts().PrepareForLTO)
return;
@ -973,10 +973,7 @@ void CodeGenModule::EmitVTableBitSetEntries(llvm::GlobalVariable *VTable,
return E1.second < E2.second;
});
llvm::NamedMDNode *BitsetsMD =
getModule().getOrInsertNamedMetadata("llvm.bitsets");
for (auto BitsetEntry : BitsetEntries)
CreateVTableBitSetEntry(BitsetsMD, VTable,
PointerWidth * BitsetEntry.second,
BitsetEntry.first);
AddVTableTypeMetadata(VTable, PointerWidth * BitsetEntry.second,
BitsetEntry.first);
}

View File

@ -1413,15 +1413,15 @@ public:
CFITypeCheckKind TCK, SourceLocation Loc);
/// EmitVTablePtrCheck - Emit a check that VTable is a valid virtual table for
/// RD using llvm.bitset.test.
/// RD using llvm.type.test.
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);
/// that VTable is a member of RD's type identifier. Or, if vptr CFI is
/// enabled, emit a check that VTable is a member of RD's type identifier.
void EmitTypeMetadataCodeForVCall(const CXXRecordDecl *RD,
llvm::Value *VTable, SourceLocation Loc);
/// CanDevirtualizeMemberFunctionCalls - Checks whether virtual calls on given
/// expr can be devirtualized.

View File

@ -787,8 +787,7 @@ void CodeGenModule::setFunctionDLLStorageClass(GlobalDecl GD, llvm::Function *F)
F->setDLLStorageClass(llvm::GlobalVariable::DefaultStorageClass);
}
llvm::ConstantInt *
CodeGenModule::CreateCfiIdForTypeMetadata(llvm::Metadata *MD) {
llvm::ConstantInt *CodeGenModule::CreateCrossDsoCfiTypeId(llvm::Metadata *MD) {
llvm::MDString *MDS = dyn_cast<llvm::MDString>(MD);
if (!MDS) return nullptr;
@ -989,8 +988,8 @@ static void setLinkageAndVisibilityForGV(llvm::GlobalValue *GV,
}
}
void CodeGenModule::CreateFunctionBitSetEntry(const FunctionDecl *FD,
llvm::Function *F) {
void CodeGenModule::CreateFunctionTypeMetadata(const FunctionDecl *FD,
llvm::Function *F) {
// Only if we are checking indirect calls.
if (!LangOpts.Sanitize.has(SanitizerKind::CFIICall))
return;
@ -1011,25 +1010,13 @@ void CodeGenModule::CreateFunctionBitSetEntry(const FunctionDecl *FD,
return;
}
llvm::NamedMDNode *BitsetsMD =
getModule().getOrInsertNamedMetadata("llvm.bitsets");
llvm::Metadata *MD = CreateMetadataIdentifierForType(FD->getType());
llvm::Metadata *BitsetOps[] = {
MD, llvm::ConstantAsMetadata::get(F),
llvm::ConstantAsMetadata::get(llvm::ConstantInt::get(Int64Ty, 0))};
BitsetsMD->addOperand(llvm::MDTuple::get(getLLVMContext(), BitsetOps));
F->addTypeMetadata(0, MD);
// Emit a hash-based bit set entry for cross-DSO calls.
if (CodeGenOpts.SanitizeCfiCrossDso) {
if (auto TypeId = CreateCfiIdForTypeMetadata(MD)) {
llvm::Metadata *BitsetOps2[] = {
llvm::ConstantAsMetadata::get(TypeId),
llvm::ConstantAsMetadata::get(F),
llvm::ConstantAsMetadata::get(llvm::ConstantInt::get(Int64Ty, 0))};
BitsetsMD->addOperand(llvm::MDTuple::get(getLLVMContext(), BitsetOps2));
}
}
if (CodeGenOpts.SanitizeCfiCrossDso)
if (auto CrossDsoTypeId = CreateCrossDsoCfiTypeId(MD))
F->addTypeMetadata(0, llvm::ConstantAsMetadata::get(CrossDsoTypeId));
}
void CodeGenModule::SetFunctionAttributes(GlobalDecl GD, llvm::Function *F,
@ -1090,7 +1077,7 @@ void CodeGenModule::SetFunctionAttributes(GlobalDecl GD, llvm::Function *F,
if (MD->isVirtual())
F->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global);
CreateFunctionBitSetEntry(FD, F);
CreateFunctionTypeMetadata(FD, F);
}
void CodeGenModule::addUsedGlobal(llvm::GlobalValue *GV) {
@ -4219,8 +4206,8 @@ llvm::Metadata *CodeGenModule::CreateMetadataIdentifierForType(QualType T) {
return InternalId;
}
/// Returns whether this module needs the "all-vtables" bitset.
bool CodeGenModule::NeedAllVtablesBitSet() const {
/// Returns whether this module needs the "all-vtables" type identifier.
bool CodeGenModule::NeedAllVtablesTypeId() const {
// Returns true if at least one of vtable-based CFI checkers is enabled and
// is not in the trapping mode.
return ((LangOpts.Sanitize.has(SanitizerKind::CFIVCall) &&
@ -4233,38 +4220,21 @@ bool CodeGenModule::NeedAllVtablesBitSet() const {
!CodeGenOpts.SanitizeTrap.has(SanitizerKind::CFIUnrelatedCast)));
}
void CodeGenModule::CreateVTableBitSetEntry(llvm::NamedMDNode *BitsetsMD,
llvm::GlobalVariable *VTable,
CharUnits Offset,
const CXXRecordDecl *RD) {
void CodeGenModule::AddVTableTypeMetadata(llvm::GlobalVariable *VTable,
CharUnits Offset,
const CXXRecordDecl *RD) {
llvm::Metadata *MD =
CreateMetadataIdentifierForType(QualType(RD->getTypeForDecl(), 0));
llvm::Metadata *BitsetOps[] = {
MD, llvm::ConstantAsMetadata::get(VTable),
llvm::ConstantAsMetadata::get(
llvm::ConstantInt::get(Int64Ty, Offset.getQuantity()))};
BitsetsMD->addOperand(llvm::MDTuple::get(getLLVMContext(), BitsetOps));
VTable->addTypeMetadata(Offset.getQuantity(), MD);
if (CodeGenOpts.SanitizeCfiCrossDso) {
if (auto TypeId = CreateCfiIdForTypeMetadata(MD)) {
llvm::Metadata *BitsetOps2[] = {
llvm::ConstantAsMetadata::get(TypeId),
llvm::ConstantAsMetadata::get(VTable),
llvm::ConstantAsMetadata::get(
llvm::ConstantInt::get(Int64Ty, Offset.getQuantity()))};
BitsetsMD->addOperand(llvm::MDTuple::get(getLLVMContext(), BitsetOps2));
}
}
if (CodeGenOpts.SanitizeCfiCrossDso)
if (auto CrossDsoTypeId = CreateCrossDsoCfiTypeId(MD))
VTable->addTypeMetadata(Offset.getQuantity(),
llvm::ConstantAsMetadata::get(CrossDsoTypeId));
if (NeedAllVtablesBitSet()) {
if (NeedAllVtablesTypeId()) {
llvm::Metadata *MD = llvm::MDString::get(getLLVMContext(), "all-vtables");
llvm::Metadata *BitsetOps[] = {
MD, llvm::ConstantAsMetadata::get(VTable),
llvm::ConstantAsMetadata::get(
llvm::ConstantInt::get(Int64Ty, Offset.getQuantity()))};
// Avoid adding a node to BitsetsMD twice.
if (!llvm::MDTuple::getIfExists(getLLVMContext(), BitsetOps))
BitsetsMD->addOperand(llvm::MDTuple::get(getLLVMContext(), BitsetOps));
VTable->addTypeMetadata(Offset.getQuantity(), MD);
}
}

View File

@ -1118,29 +1118,27 @@ public:
/// optimization.
bool HasHiddenLTOVisibility(const CXXRecordDecl *RD);
/// Emit bit set entries for the given vtable using the given layout if
/// vptr CFI is enabled.
void EmitVTableBitSetEntries(llvm::GlobalVariable *VTable,
const VTableLayout &VTLayout);
/// Emit type metadata for the given vtable using the given layout.
void EmitVTableTypeMetadata(llvm::GlobalVariable *VTable,
const VTableLayout &VTLayout);
/// Generate a cross-DSO type identifier for type.
llvm::ConstantInt *CreateCfiIdForTypeMetadata(llvm::Metadata *MD);
/// Generate a cross-DSO type identifier for MD.
llvm::ConstantInt *CreateCrossDsoCfiTypeId(llvm::Metadata *MD);
/// Create a metadata identifier for the given type. This may either be an
/// MDString (for external identifiers) or a distinct unnamed MDNode (for
/// internal identifiers).
llvm::Metadata *CreateMetadataIdentifierForType(QualType T);
/// Create a bitset entry for the given function and add it to BitsetsMD.
void CreateFunctionBitSetEntry(const FunctionDecl *FD, llvm::Function *F);
/// Create and attach type metadata to the given function.
void CreateFunctionTypeMetadata(const FunctionDecl *FD, llvm::Function *F);
/// Returns whether this module needs the "all-vtables" bitset.
bool NeedAllVtablesBitSet() const;
/// Returns whether this module needs the "all-vtables" type identifier.
bool NeedAllVtablesTypeId() const;
/// Create a bitset entry for the given vtable and add it to BitsetsMD.
void CreateVTableBitSetEntry(llvm::NamedMDNode *BitsetsMD,
llvm::GlobalVariable *VTable, CharUnits Offset,
const CXXRecordDecl *RD);
/// Create and attach type metadata for the given vtable.
void AddVTableTypeMetadata(llvm::GlobalVariable *VTable, CharUnits Offset,
const CXXRecordDecl *RD);
/// \breif Get the declaration of std::terminate for the platform.
llvm::Constant *getTerminateFn();

View File

@ -1490,7 +1490,7 @@ void ItaniumCXXABI::emitVTableDefinitions(CodeGenVTables &CGVT,
EmitFundamentalRTTIDescriptors();
if (!VTable->isDeclarationForLinker())
CGM.EmitVTableBitSetEntries(VTable, VTLayout);
CGM.EmitVTableTypeMetadata(VTable, VTLayout);
}
bool ItaniumCXXABI::isVirtualOffsetNeededForVTableField(
@ -1595,7 +1595,7 @@ llvm::Value *ItaniumCXXABI::getVirtualFunctionPointer(CodeGenFunction &CGF,
auto *MethodDecl = cast<CXXMethodDecl>(GD.getDecl());
llvm::Value *VTable = CGF.GetVTablePtr(This, Ty, MethodDecl->getParent());
CGF.EmitBitSetCodeForVCall(MethodDecl->getParent(), VTable, Loc);
CGF.EmitTypeMetadataCodeForVCall(MethodDecl->getParent(), VTable, Loc);
uint64_t VTableIndex = CGM.getItaniumVTableContext().getMethodVTableIndex(GD);
llvm::Value *VFuncPtr =

View File

@ -254,8 +254,8 @@ public:
CXXDtorType Type, bool ForVirtualBase,
bool Delegating, Address This) override;
void emitVTableBitSetEntries(VPtrInfo *Info, const CXXRecordDecl *RD,
llvm::GlobalVariable *VTable);
void emitVTableTypeMetadata(VPtrInfo *Info, const CXXRecordDecl *RD,
llvm::GlobalVariable *VTable);
void emitVTableDefinitions(CodeGenVTables &CGVT,
const CXXRecordDecl *RD) override;
@ -1502,15 +1502,12 @@ void MicrosoftCXXABI::EmitDestructorCall(CodeGenFunction &CGF,
getFromDtorType(Type));
}
void MicrosoftCXXABI::emitVTableBitSetEntries(VPtrInfo *Info,
const CXXRecordDecl *RD,
llvm::GlobalVariable *VTable) {
void MicrosoftCXXABI::emitVTableTypeMetadata(VPtrInfo *Info,
const CXXRecordDecl *RD,
llvm::GlobalVariable *VTable) {
if (!CGM.getCodeGenOpts().PrepareForLTO)
return;
llvm::NamedMDNode *BitsetsMD =
CGM.getModule().getOrInsertNamedMetadata("llvm.bitsets");
// The location of the first virtual function pointer in the virtual table,
// aka the "address point" on Itanium. This is at offset 0 if RTTI is
// disabled, or sizeof(void*) if RTTI is enabled.
@ -1521,13 +1518,13 @@ void MicrosoftCXXABI::emitVTableBitSetEntries(VPtrInfo *Info,
: CharUnits::Zero();
if (Info->PathToBaseWithVPtr.empty()) {
CGM.CreateVTableBitSetEntry(BitsetsMD, VTable, AddressPoint, RD);
CGM.AddVTableTypeMetadata(VTable, AddressPoint, RD);
return;
}
// Add a bitset entry for the least derived base belonging to this vftable.
CGM.CreateVTableBitSetEntry(BitsetsMD, VTable, AddressPoint,
Info->PathToBaseWithVPtr.back());
CGM.AddVTableTypeMetadata(VTable, AddressPoint,
Info->PathToBaseWithVPtr.back());
// Add a bitset entry for each derived class that is laid out at the same
// offset as the least derived base.
@ -1545,12 +1542,12 @@ void MicrosoftCXXABI::emitVTableBitSetEntries(VPtrInfo *Info,
Offset = VBI->second.VBaseOffset;
if (!Offset.isZero())
return;
CGM.CreateVTableBitSetEntry(BitsetsMD, VTable, AddressPoint, DerivedRD);
CGM.AddVTableTypeMetadata(VTable, AddressPoint, DerivedRD);
}
// Finally do the same for the most derived class.
if (Info->FullOffsetInMDC.isZero())
CGM.CreateVTableBitSetEntry(BitsetsMD, VTable, AddressPoint, RD);
CGM.AddVTableTypeMetadata(VTable, AddressPoint, RD);
}
void MicrosoftCXXABI::emitVTableDefinitions(CodeGenVTables &CGVT,
@ -1578,7 +1575,7 @@ void MicrosoftCXXABI::emitVTableDefinitions(CodeGenVTables &CGVT,
VTable->setInitializer(Init);
emitVTableBitSetEntries(Info, RD, VTable);
emitVTableTypeMetadata(Info, RD, VTable);
}
}
@ -1819,8 +1816,8 @@ llvm::Value *MicrosoftCXXABI::getVirtualFunctionPointer(CodeGenFunction &CGF,
MicrosoftVTableContext::MethodVFTableLocation ML =
CGM.getMicrosoftVTableContext().getMethodVFTableLocation(GD);
if (CGM.getCodeGenOpts().PrepareForLTO)
CGF.EmitBitSetCodeForVCall(getClassAtVTableLocation(getContext(), GD, ML),
VTable, Loc);
CGF.EmitTypeMetadataCodeForVCall(
getClassAtVTableLocation(getContext(), GD, ML), VTable, Loc);
llvm::Value *VFuncPtr =
Builder.CreateConstInBoundsGEP1_64(VTable, ML.Index, "vfn");

View File

@ -23,7 +23,7 @@ void caller(void (*f)()) {
// CHECK: %[[A:.*]] = bitcast i8* %[[DATA]] to { i8, { i8*, i32, i32 }, i8* }*
// CHECK: %[[KINDPTR:.*]] = getelementptr {{.*}} %[[A]], i32 0, i32 0
// CHECK: %[[KIND:.*]] = load i8, i8* %[[KINDPTR]], align 4
// CHECK: %[[VTVALID0:.*]] = call i1 @llvm.bitset.test(i8* %[[ADDR]], metadata !"all-vtables")
// CHECK: %[[VTVALID0:.*]] = call i1 @llvm.type.test(i8* %[[ADDR]], metadata !"all-vtables")
// CHECK: %[[VTVALID:.*]] = zext i1 %[[VTVALID0]] to i64
// CHECK: %[[NOT_0:.*]] = icmp ne i8 %[[KIND]], 0
// CHECK: br i1 %[[NOT_0]], label %[[CONT1:.*]], label %[[HANDLE0:.*]], !prof

View File

@ -23,7 +23,7 @@ void caller(void (*f)()) {
// CHECK: %[[A:.*]] = bitcast i8* %[[DATA]] to { i8, { i8*, i32, i32 }, i8* }*
// CHECK: %[[KINDPTR:.*]] = getelementptr {{.*}} %[[A]], i32 0, i32 0
// CHECK: %[[KIND:.*]] = load i8, i8* %[[KINDPTR]], align 4
// CHECK: %[[VTVALID0:.*]] = call i1 @llvm.bitset.test(i8* %[[ADDR]], metadata !"all-vtables")
// CHECK: %[[VTVALID0:.*]] = call i1 @llvm.type.test(i8* %[[ADDR]], metadata !"all-vtables")
// CHECK: %[[VTVALID:.*]] = zext i1 %[[VTVALID0]] to i64
// CHECK: %[[NOT_0:.*]] = icmp ne i8 %[[KIND]], 0
// CHECK: br i1 %[[NOT_0]], label %[[CONT1:.*]], label %[[HANDLE0:.*]], !prof

View File

@ -26,11 +26,30 @@
// RUN: --check-prefix=MS --check-prefix=MS-TRAP \
// RUN: %s
// CHECK-DIAG: @[[SRC:.*]] = private unnamed_addr constant {{.*}}cfi-icall-cross-dso.c\00
// CHECK-DIAG: @[[TYPE:.*]] = private unnamed_addr constant { i16, i16, [{{.*}} x i8] } { i16 -1, i16 0, [{{.*}} x i8] c"'void ()'\00"
// CHECK-DIAG: @[[DATA:.*]] = private unnamed_addr global {{.*}}@[[SRC]]{{.*}}@[[TYPE]]
// ITANIUM: call i1 @llvm.type.test(i8* %{{.*}}, metadata !"_ZTSFvE"), !nosanitize
// ITANIUM-DIAG: call void @__cfi_slowpath_diag(i64 6588678392271548388, i8* %{{.*}}, {{.*}}@[[DATA]]{{.*}}) {{.*}}, !nosanitize
// ITANIUM-TRAP: call void @__cfi_slowpath(i64 6588678392271548388, i8* %{{.*}}) {{.*}}, !nosanitize
// MS: call i1 @llvm.type.test(i8* %{{.*}}, metadata !"?6AX@Z"), !nosanitize
// MS-DIAG: call void @__cfi_slowpath_diag(i64 4195979634929632483, i8* %{{.*}}, {{.*}}@[[DATA]]{{.*}}) {{.*}}, !nosanitize
// MS-TRAP: call void @__cfi_slowpath(i64 4195979634929632483, i8* %{{.*}}) {{.*}}, !nosanitize
void caller(void (*f)()) {
f();
}
// Check that we emit both string and hash based type entries for static void g(),
// and don't emit them for the declaration of h().
// CHECK: define internal void @g({{.*}} !type [[TVOID:![0-9]+]] !type [[TVOID_ID:![0-9]+]]
static void g(void) {}
// CHECK: declare void @h({{[^!]*$}}
void h(void);
typedef void (*Fn)(void);
@ -41,41 +60,22 @@ Fn h1() {
return &h;
}
// CHECK: define void @bar({{.*}} !type [[TNOPROTO:![0-9]+]] !type [[TNOPROTO_ID:![0-9]+]]
// ITANIUM: define available_externally void @foo({{[^!]*$}}
// MS: define linkonce_odr void @foo({{.*}} !type [[TNOPROTO]] !type [[TNOPROTO_ID]]
inline void foo() {}
void bar() { foo(); }
// CHECK-DIAG: @[[SRC:.*]] = private unnamed_addr constant {{.*}}cfi-icall-cross-dso.c\00
// CHECK-DIAG: @[[TYPE:.*]] = private unnamed_addr constant { i16, i16, [{{.*}} x i8] } { i16 -1, i16 0, [{{.*}} x i8] c"'void ()'\00"
// CHECK-DIAG: @[[DATA:.*]] = private unnamed_addr global {{.*}}@[[SRC]]{{.*}}@[[TYPE]]
// ITANIUM: call i1 @llvm.bitset.test(i8* %{{.*}}, metadata !"_ZTSFvE"), !nosanitize
// ITANIUM-DIAG: call void @__cfi_slowpath_diag(i64 6588678392271548388, i8* %{{.*}}, {{.*}}@[[DATA]]{{.*}}) {{.*}}, !nosanitize
// ITANIUM-TRAP: call void @__cfi_slowpath(i64 6588678392271548388, i8* %{{.*}}) {{.*}}, !nosanitize
// MS: call i1 @llvm.bitset.test(i8* %{{.*}}, metadata !"?6AX@Z"), !nosanitize
// MS-DIAG: call void @__cfi_slowpath_diag(i64 4195979634929632483, i8* %{{.*}}, {{.*}}@[[DATA]]{{.*}}) {{.*}}, !nosanitize
// MS-TRAP: call void @__cfi_slowpath(i64 4195979634929632483, i8* %{{.*}}) {{.*}}, !nosanitize
// ITANIUM: define available_externally void @foo()
// MS: define linkonce_odr void @foo()
// Check that we emit both string and hash based bit set entries for static void g(),
// and don't emit them for the declaration of h().
// CHECK-NOT: !{!"{{.*}}", void ()* @h, i64 0}
// CHECK: !{!"{{.*}}", void ()* @g, i64 0}
// CHECK-NOT: !{!"{{.*}}", void ()* @h, i64 0}
// CHECK: !{i64 {{.*}}, void ()* @g, i64 0}
// CHECK-NOT: !{!"{{.*}}", void ()* @h, i64 0}
// ITANIUM-NOT: !{!{{.*}}, void ()* @foo,
// ITANIUM: !{!"_ZTSFvE", void ()* @bar, i64 0}
// ITANIUM-NOT: !{!{{.*}}, void ()* @foo,
// ITANIUM: !{i64 6588678392271548388, void ()* @bar, i64 0}
// ITANIUM-NOT: !{!{{.*}}, void ()* @foo,
// MS: !{!"?6AX@Z", void ()* @foo, i64 0}
// MS: !{i64 4195979634929632483, void ()* @foo, i64 0}
// CHECK: !{i32 4, !"Cross-DSO CFI", i32 1}
// Check that the type entries are correct.
// ITANIUM: [[TVOID]] = !{i64 0, !"_ZTSFvvE"}
// ITANIUM: [[TVOID_ID]] = !{i64 0, i64 9080559750644022485}
// ITANIUM: [[TNOPROTO]] = !{i64 0, !"_ZTSFvE"}
// ITANIUM: [[TNOPROTO_ID]] = !{i64 0, i64 6588678392271548388}
// MS: [[TVOID]] = !{i64 0, !"?6AXXZ"}
// MS: [[TVOID_ID]] = !{i64 0, i64 5113650790573562461}
// MS: [[TNOPROTO]] = !{i64 0, !"?6AX@Z"}
// MS: [[TNOPROTO_ID]] = !{i64 0, i64 4195979634929632483}

View File

@ -1,20 +1,24 @@
// RUN: %clang_cc1 -triple x86_64-unknown-linux -fsanitize=cfi-icall -fsanitize-trap=cfi-icall -emit-llvm -o - %s | FileCheck --check-prefix=ITANIUM %s
// RUN: %clang_cc1 -triple x86_64-pc-windows-msvc -fsanitize=cfi-icall -fsanitize-trap=cfi-icall -emit-llvm -o - %s | FileCheck --check-prefix=MS %s
// RUN: %clang_cc1 -triple x86_64-unknown-linux -fsanitize=cfi-icall -fsanitize-trap=cfi-icall -emit-llvm -o - %s | FileCheck --check-prefix=CHECK --check-prefix=ITANIUM %s
// RUN: %clang_cc1 -triple x86_64-pc-windows-msvc -fsanitize=cfi-icall -fsanitize-trap=cfi-icall -emit-llvm -o - %s | FileCheck --check-prefix=CHECK --check-prefix=MS %s
// Tests that we assign appropriate identifiers to unprototyped functions.
// CHECK: define void @f({{.*}} !type [[TVOID:![0-9]+]]
void f() {
}
void xf();
// CHECK: define void @g({{.*}} !type [[TINT:![0-9]+]]
void g(int b) {
void (*fp)() = b ? f : xf;
// ITANIUM: call i1 @llvm.bitset.test(i8* {{.*}}, metadata !"_ZTSFvE")
// ITANIUM: call i1 @llvm.type.test(i8* {{.*}}, metadata !"_ZTSFvE")
fp();
}
// ITANIUM-DAG: !{!"_ZTSFvE", void ()* @f, i64 0}
// ITANIUM-DAG: !{!"_ZTSFvE", void (...)* @xf, i64 0}
// MS-DAG: !{!"?6AX@Z", void ()* @f, i64 0}
// MS-DAG: !{!"?6AX@Z", void (...)* @xf, i64 0}
// CHECK: declare !type [[TVOID:![0-9]+]] void @xf({{.*}}
// ITANIUM-DAG: [[TVOID]] = !{i64 0, !"_ZTSFvE"}
// ITANIUM-DAG: [[TINT]] = !{i64 0, !"_ZTSFviE"}
// MS-DAG: [[TVOID]] = !{i64 0, !"?6AX@Z"}
// MS-DAG: [[TINT]] = !{i64 0, !"?6AXH@Z"}

View File

@ -1,211 +0,0 @@
// Tests for the cfi-vcall feature:
// RUN: %clang_cc1 -flto -triple x86_64-unknown-linux -fvisibility hidden -fsanitize=cfi-vcall -fsanitize-trap=cfi-vcall -emit-llvm -o - %s | FileCheck --check-prefix=CFI --check-prefix=ITANIUM --check-prefix=ITANIUM-NDIAG --check-prefix=NDIAG %s
// RUN: %clang_cc1 -flto -triple x86_64-unknown-linux -fvisibility hidden -fsanitize=cfi-vcall -emit-llvm -o - %s | FileCheck --check-prefix=CFI --check-prefix=ITANIUM --check-prefix=ITANIUM-DIAG --check-prefix=DIAG --check-prefix=DIAG-ABORT %s
// RUN: %clang_cc1 -flto -triple x86_64-unknown-linux -fvisibility hidden -fsanitize=cfi-vcall -fsanitize-recover=cfi-vcall -emit-llvm -o - %s | FileCheck --check-prefix=CFI --check-prefix=ITANIUM --check-prefix=DIAG --check-prefix=DIAG-RECOVER %s
// RUN: %clang_cc1 -flto -triple x86_64-pc-windows-msvc -fsanitize=cfi-vcall -fsanitize-trap=cfi-vcall -emit-llvm -o - %s | FileCheck --check-prefix=CFI --check-prefix=MS --check-prefix=NDIAG %s
// Tests for the whole-program-vtables feature:
// RUN: %clang_cc1 -flto -triple x86_64-unknown-linux -fvisibility hidden -fwhole-program-vtables -emit-llvm -o - %s | FileCheck --check-prefix=VTABLE-OPT --check-prefix=ITANIUM %s
// RUN: %clang_cc1 -flto -triple x86_64-pc-windows-msvc -fwhole-program-vtables -emit-llvm -o - %s | FileCheck --check-prefix=VTABLE-OPT --check-prefix=MS %s
// MS: @[[VTA:[0-9]*]] {{.*}} comdat($"\01??_7A@@6B@")
// MS: @[[VTB:[0-9]*]] {{.*}} comdat($"\01??_7B@@6B0@@")
// MS: @[[VTAinB:[0-9]*]] {{.*}} comdat($"\01??_7B@@6BA@@@")
// MS: @[[VTAinC:[0-9]*]] {{.*}} comdat($"\01??_7C@@6B@")
// MS: @[[VTBinD:[0-9]*]] {{.*}} comdat($"\01??_7D@?A@@6BB@@@")
// MS: @[[VTAinBinD:[0-9]*]] {{.*}} comdat($"\01??_7D@?A@@6BA@@@")
// MS: @[[VTFA:[0-9]*]] {{.*}} comdat($"\01??_7FA@?1??foo@@YAXXZ@6B@")
struct A {
A();
virtual void f();
};
struct B : virtual A {
B();
virtual void g();
virtual void h();
};
struct C : virtual A {
C();
};
namespace {
struct D : B, C {
D();
virtual void f();
virtual void h();
};
}
A::A() {}
B::B() {}
C::C() {}
D::D() {}
void A::f() {
}
void B::g() {
}
void D::f() {
}
void D::h() {
}
// DIAG: @[[SRC:.*]] = private unnamed_addr constant [{{.*}} x i8] c"{{.*}}bitsets.cpp\00", align 1
// DIAG: @[[TYPE:.*]] = private unnamed_addr constant { i16, i16, [4 x i8] } { i16 -1, i16 0, [4 x i8] c"'A'\00" }
// DIAG: @[[BADTYPESTATIC:.*]] = private unnamed_addr global { i8, { [{{.*}} x i8]*, i32, i32 }, { i16, i16, [4 x i8] }* } { i8 0, { [{{.*}} x i8]*, i32, i32 } { [{{.*}} x i8]* @[[SRC]], i32 [[@LINE+24]], i32 3 }, { i16, i16, [4 x i8] }* @[[TYPE]] }
// ITANIUM: define hidden void @_Z2afP1A
// MS: define void @"\01?af@@YAXPEAUA@@@Z"
void af(A *a) {
// ITANIUM: [[P:%[^ ]*]] = call i1 @llvm.bitset.test(i8* [[VT:%[^ ]*]], metadata !"_ZTS1A")
// MS: [[P:%[^ ]*]] = call i1 @llvm.bitset.test(i8* [[VT:%[^ ]*]], metadata !"?AUA@@")
// DIAG-NEXT: [[VTVALID0:%[^ ]*]] = call i1 @llvm.bitset.test(i8* [[VT]], metadata !"all-vtables")
// VTABLE-OPT: call void @llvm.assume(i1 [[P]])
// CFI-NEXT: br i1 [[P]], label %[[CONTBB:[^ ,]*]], label %[[TRAPBB:[^ ,]*]]
// CFI-NEXT: {{^$}}
// CFI: [[TRAPBB]]
// NDIAG-NEXT: call void @llvm.trap()
// NDIAG-NEXT: unreachable
// DIAG-NEXT: [[VTINT:%[^ ]*]] = ptrtoint i8* [[VT]] to i64
// DIAG-NEXT: [[VTVALID:%[^ ]*]] = zext i1 [[VTVALID0]] to i64
// DIAG-ABORT-NEXT: call void @__ubsan_handle_cfi_check_fail_abort(i8* getelementptr inbounds ({{.*}} @[[BADTYPESTATIC]], i32 0, i32 0), i64 [[VTINT]], i64 [[VTVALID]])
// DIAG-ABORT-NEXT: unreachable
// DIAG-RECOVER-NEXT: call void @__ubsan_handle_cfi_check_fail(i8* getelementptr inbounds ({{.*}} @[[BADTYPESTATIC]], i32 0, i32 0), i64 [[VTINT]], i64 [[VTVALID]])
// DIAG-RECOVER-NEXT: br label %[[CONTBB]]
// CFI: [[CONTBB]]
// CFI: call void %
a->f();
}
// ITANIUM: define internal void @_Z3df1PN12_GLOBAL__N_11DE
// MS: define internal void @"\01?df1@@YAXPEAUD@?A@@@Z"
void df1(D *d) {
// ITANIUM: {{%[^ ]*}} = call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata ![[DTYPE:[0-9]+]])
// MS: {{%[^ ]*}} = call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"?AUA@@")
d->f();
}
// ITANIUM: define internal void @_Z3dg1PN12_GLOBAL__N_11DE
// MS: define internal void @"\01?dg1@@YAXPEAUD@?A@@@Z"
void dg1(D *d) {
// ITANIUM: {{%[^ ]*}} = call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"_ZTS1B")
// MS: {{%[^ ]*}} = call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"?AUB@@")
d->g();
}
// ITANIUM: define internal void @_Z3dh1PN12_GLOBAL__N_11DE
// MS: define internal void @"\01?dh1@@YAXPEAUD@?A@@@Z"
void dh1(D *d) {
// ITANIUM: {{%[^ ]*}} = call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata ![[DTYPE]])
// MS: {{%[^ ]*}} = call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata ![[DTYPE:[0-9]+]])
d->h();
}
// ITANIUM: define internal void @_Z3df2PN12_GLOBAL__N_11DE
// MS: define internal void @"\01?df2@@YAXPEAUD@?A@@@Z"
__attribute__((no_sanitize("cfi")))
void df2(D *d) {
// CFI-NOT: call i1 @llvm.bitset.test
d->f();
}
// ITANIUM: define internal void @_Z3df3PN12_GLOBAL__N_11DE
// MS: define internal void @"\01?df3@@YAXPEAUD@?A@@@Z"
__attribute__((no_sanitize("address"))) __attribute__((no_sanitize("cfi-vcall")))
void df3(D *d) {
// CFI-NOT: call i1 @llvm.bitset.test
d->f();
}
D d;
void foo() {
df1(&d);
dg1(&d);
dh1(&d);
df2(&d);
df3(&d);
struct FA : A {
void f() {}
} fa;
af(&fa);
}
namespace test2 {
struct A {
virtual void m_fn1();
};
struct B {
virtual void m_fn2();
};
struct C : B, A {};
struct D : C {
void m_fn1();
};
// ITANIUM: define hidden void @_ZN5test21fEPNS_1DE
// MS: define void @"\01?f@test2@@YAXPEAUD@1@@Z"
void f(D *d) {
// ITANIUM: {{%[^ ]*}} = call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"_ZTSN5test21DE")
// MS: {{%[^ ]*}} = call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"?AUA@test2@@")
d->m_fn1();
}
}
// Check for the expected number of elements (15 or 23 respectively).
// MS-NDIAG: !llvm.bitsets = !{[[X:[^,]*(,[^,]*){9}]]}
// MS-DIAG: !llvm.bitsets = !{[[X:[^,]*(,[^,]*){15}]]}
// ITANIUM-NDIAG: !llvm.bitsets = !{[[X:[^,]*(,[^,]*){14}]]}
// ITANIUM-DIAG: !llvm.bitsets = !{[[X:[^,]*(,[^,]*){23}]]}
// ITANIUM-DAG: !{!"_ZTS1A", [3 x i8*]* @_ZTV1A, i64 16}
// ITANIUM-DIAG-DAG: !{!"all-vtables", [3 x i8*]* @_ZTV1A, i64 16}
// ITANIUM-DAG: !{!"_ZTS1A", [7 x i8*]* @_ZTCN12_GLOBAL__N_11DE0_1B, i64 32}
// ITANIUM-DIAG-DAG: !{!"all-vtables", [7 x i8*]* @_ZTCN12_GLOBAL__N_11DE0_1B, i64 32}
// ITANIUM-DAG: !{!"_ZTS1B", [7 x i8*]* @_ZTCN12_GLOBAL__N_11DE0_1B, i64 32}
// ITANIUM-DAG: !{!"_ZTS1A", [9 x i8*]* @_ZTCN12_GLOBAL__N_11DE8_1C, i64 64}
// ITANIUM-DIAG-DAG: !{!"all-vtables", [9 x i8*]* @_ZTCN12_GLOBAL__N_11DE8_1C, i64 64}
// ITANIUM-DAG: !{!"_ZTS1C", [9 x i8*]* @_ZTCN12_GLOBAL__N_11DE8_1C, i64 32}
// ITANIUM-DAG: !{!"_ZTS1A", [12 x i8*]* @_ZTVN12_GLOBAL__N_11DE, i64 32}
// ITANIUM-DIAG-DAG: !{!"all-vtables", [12 x i8*]* @_ZTVN12_GLOBAL__N_11DE, i64 32}
// ITANIUM-DAG: !{!"_ZTS1B", [12 x i8*]* @_ZTVN12_GLOBAL__N_11DE, i64 32}
// ITANIUM-DAG: !{!"_ZTS1C", [12 x i8*]* @_ZTVN12_GLOBAL__N_11DE, i64 88}
// ITANIUM-DIAG-DAG: !{!"all-vtables", [12 x i8*]* @_ZTVN12_GLOBAL__N_11DE, i64 88}
// ITANIUM-DAG: !{![[DTYPE]], [12 x i8*]* @_ZTVN12_GLOBAL__N_11DE, i64 32}
// ITANIUM-DAG: !{!"_ZTS1A", [7 x i8*]* @_ZTV1B, i64 32}
// ITANIUM-DIAG-DAG: !{!"all-vtables", [7 x i8*]* @_ZTV1B, i64 32}
// ITANIUM-DAG: !{!"_ZTS1B", [7 x i8*]* @_ZTV1B, i64 32}
// ITANIUM-DAG: !{!"_ZTS1A", [5 x i8*]* @_ZTV1C, i64 32}
// ITANIUM-DAG: !{!"_ZTS1C", [5 x i8*]* @_ZTV1C, i64 32}
// ITANIUM-DAG: !{!"_ZTS1A", [3 x i8*]* @_ZTVZ3foovE2FA, i64 16}
// ITANIUM-DAG: !{!{{[0-9]+}}, [3 x i8*]* @_ZTVZ3foovE2FA, i64 16}
// MS-DAG: !{!"?AUA@@", [2 x i8*]* @[[VTA]], i64 8}
// MS-DIAG-DAG: !{!"all-vtables", [2 x i8*]* @[[VTA]], i64 8}
// MS-DAG: !{!"?AUB@@", [3 x i8*]* @[[VTB]], i64 8}
// MS-DIAG-DAG: !{!"all-vtables", [3 x i8*]* @[[VTB]], i64 8}
// MS-DAG: !{!"?AUA@@", [2 x i8*]* @[[VTAinB]], i64 8}
// MS-DIAG-DAG: !{!"all-vtables", [2 x i8*]* @[[VTAinB]], i64 8}
// MS-DAG: !{!"?AUA@@", [2 x i8*]* @[[VTAinC]], i64 8}
// MS-DIAG-DAG: !{!"all-vtables", [2 x i8*]* @[[VTAinC]], i64 8}
// MS-DAG: !{!"?AUB@@", [3 x i8*]* @[[VTBinD]], i64 8}
// MS-DIAG-DAG: !{!"all-vtables", [3 x i8*]* @[[VTBinD]], i64 8}
// MS-DAG: !{![[DTYPE]], [3 x i8*]* @[[VTBinD]], i64 8}
// MS-DAG: !{!"?AUA@@", [2 x i8*]* @[[VTAinBinD]], i64 8}
// MS-DIAG-DAG: !{!"all-vtables", [2 x i8*]* @[[VTAinBinD]], i64 8}
// MS-DAG: !{!"?AUA@@", [2 x i8*]* @[[VTFA]], i64 8}
// MS-DIAG-DAG: !{!"all-vtables", [2 x i8*]* @[[VTFA]], i64 8}
// MS-DAG: !{!{{[0-9]+}}, [2 x i8*]* @[[VTFA]], i64 8}

View File

@ -15,15 +15,15 @@ struct S2 {
}
// CHECK: define{{.*}}s1f
// NOBL: llvm.bitset.test
// NOSTD: llvm.bitset.test
// NOBL: llvm.type.test
// NOSTD: llvm.type.test
void s1f(S1 *s1) {
s1->f();
}
// CHECK: define{{.*}}s2f
// NOBL: llvm.bitset.test
// NOSTD-NOT: llvm.bitset.test
// NOBL: llvm.type.test
// NOSTD-NOT: llvm.type.test
void s2f(std::S2 *s2) {
s2->f();
}

View File

@ -19,7 +19,7 @@ struct C : A {};
// CHECK-DCAST-LABEL: define hidden void @_Z3abpP1A
void abp(A *a) {
// CHECK-DCAST: [[P:%[^ ]*]] = call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"_ZTS1B")
// CHECK-DCAST: [[P:%[^ ]*]] = call i1 @llvm.type.test(i8* {{%[^ ]*}}, metadata !"_ZTS1B")
// CHECK-DCAST-NEXT: br i1 [[P]], label %[[CONTBB:[^ ]*]], label %[[TRAPBB:[^ ,]*]]
// CHECK-DCAST: [[TRAPBB]]
@ -33,7 +33,7 @@ void abp(A *a) {
// CHECK-DCAST-LABEL: define hidden void @_Z3abrR1A
void abr(A &a) {
// CHECK-DCAST: [[P:%[^ ]*]] = call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"_ZTS1B")
// CHECK-DCAST: [[P:%[^ ]*]] = call i1 @llvm.type.test(i8* {{%[^ ]*}}, metadata !"_ZTS1B")
// CHECK-DCAST-NEXT: br i1 [[P]], label %[[CONTBB:[^ ]*]], label %[[TRAPBB:[^ ,]*]]
// CHECK-DCAST: [[TRAPBB]]
@ -47,7 +47,7 @@ void abr(A &a) {
// CHECK-DCAST-LABEL: define hidden void @_Z4abrrO1A
void abrr(A &&a) {
// CHECK-DCAST: [[P:%[^ ]*]] = call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"_ZTS1B")
// CHECK-DCAST: [[P:%[^ ]*]] = call i1 @llvm.type.test(i8* {{%[^ ]*}}, metadata !"_ZTS1B")
// CHECK-DCAST-NEXT: br i1 [[P]], label %[[CONTBB:[^ ]*]], label %[[TRAPBB:[^ ,]*]]
// CHECK-DCAST: [[TRAPBB]]
@ -61,7 +61,7 @@ void abrr(A &&a) {
// CHECK-UCAST-LABEL: define hidden void @_Z3vbpPv
void vbp(void *p) {
// CHECK-UCAST: [[P:%[^ ]*]] = call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"_ZTS1B")
// CHECK-UCAST: [[P:%[^ ]*]] = call i1 @llvm.type.test(i8* {{%[^ ]*}}, metadata !"_ZTS1B")
// CHECK-UCAST-NEXT: br i1 [[P]], label %[[CONTBB:[^ ]*]], label %[[TRAPBB:[^ ,]*]]
// CHECK-UCAST: [[TRAPBB]]
@ -75,7 +75,7 @@ void vbp(void *p) {
// CHECK-UCAST-LABEL: define hidden void @_Z3vbrRc
void vbr(char &r) {
// CHECK-UCAST: [[P:%[^ ]*]] = call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"_ZTS1B")
// CHECK-UCAST: [[P:%[^ ]*]] = call i1 @llvm.type.test(i8* {{%[^ ]*}}, metadata !"_ZTS1B")
// CHECK-UCAST-NEXT: br i1 [[P]], label %[[CONTBB:[^ ]*]], label %[[TRAPBB:[^ ,]*]]
// CHECK-UCAST: [[TRAPBB]]
@ -89,7 +89,7 @@ void vbr(char &r) {
// CHECK-UCAST-LABEL: define hidden void @_Z4vbrrOc
void vbrr(char &&r) {
// CHECK-UCAST: [[P:%[^ ]*]] = call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"_ZTS1B")
// CHECK-UCAST: [[P:%[^ ]*]] = call i1 @llvm.type.test(i8* {{%[^ ]*}}, metadata !"_ZTS1B")
// CHECK-UCAST-NEXT: br i1 [[P]], label %[[CONTBB:[^ ]*]], label %[[TRAPBB:[^ ,]*]]
// CHECK-UCAST: [[TRAPBB]]
@ -104,31 +104,31 @@ void vbrr(char &&r) {
// CHECK-UCAST-LABEL: define hidden void @_Z3vcpPv
// CHECK-UCAST-STRICT-LABEL: define hidden void @_Z3vcpPv
void vcp(void *p) {
// CHECK-UCAST: call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"_ZTS1A")
// CHECK-UCAST-STRICT: call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"_ZTS1C")
// CHECK-UCAST: call i1 @llvm.type.test(i8* {{%[^ ]*}}, metadata !"_ZTS1A")
// CHECK-UCAST-STRICT: call i1 @llvm.type.test(i8* {{%[^ ]*}}, metadata !"_ZTS1C")
(void)static_cast<C*>(p);
}
// CHECK-UCAST-LABEL: define hidden void @_Z3bcpP1B
// CHECK-UCAST-STRICT-LABEL: define hidden void @_Z3bcpP1B
void bcp(B *p) {
// CHECK-UCAST: call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"_ZTS1A")
// CHECK-UCAST-STRICT: call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"_ZTS1C")
// CHECK-UCAST: call i1 @llvm.type.test(i8* {{%[^ ]*}}, metadata !"_ZTS1A")
// CHECK-UCAST-STRICT: call i1 @llvm.type.test(i8* {{%[^ ]*}}, metadata !"_ZTS1C")
(void)(C *)p;
}
// CHECK-UCAST-LABEL: define hidden void @_Z8bcp_callP1B
// CHECK-UCAST-STRICT-LABEL: define hidden void @_Z8bcp_callP1B
void bcp_call(B *p) {
// CHECK-UCAST: call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"_ZTS1A")
// CHECK-UCAST-STRICT: call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"_ZTS1C")
// CHECK-UCAST: call i1 @llvm.type.test(i8* {{%[^ ]*}}, metadata !"_ZTS1A")
// CHECK-UCAST-STRICT: call i1 @llvm.type.test(i8* {{%[^ ]*}}, metadata !"_ZTS1C")
((C *)p)->f();
}
// CHECK-UCAST-LABEL: define hidden i32 @_Z6a_callP1A
// CHECK-UCAST-STRICT-LABEL: define hidden i32 @_Z6a_callP1A
int a_call(A *a) {
// CHECK-UCAST-NOT: @llvm.bitset.test
// CHECK-UCAST-STRICT-NOT: @llvm.bitset.test
// CHECK-UCAST-NOT: @llvm.type.test
// CHECK-UCAST-STRICT-NOT: @llvm.type.test
return a->i();
}

View File

@ -30,8 +30,8 @@ void g() {
// CHECK: %[[VT:.*]] = load void (%struct.A*)**, void (%struct.A*)***
// CHECK: %[[VT2:.*]] = bitcast {{.*}}%[[VT]] to i8*, !nosanitize
// ITANIUM: %[[TEST:.*]] = call i1 @llvm.bitset.test(i8* %[[VT2]], metadata !"_ZTS1A"), !nosanitize
// MS: %[[TEST:.*]] = call i1 @llvm.bitset.test(i8* %[[VT2]], metadata !"?AUA@@"), !nosanitize
// ITANIUM: %[[TEST:.*]] = call i1 @llvm.type.test(i8* %[[VT2]], metadata !"_ZTS1A"), !nosanitize
// MS: %[[TEST:.*]] = call i1 @llvm.type.test(i8* %[[VT2]], metadata !"?AUA@@"), !nosanitize
// CHECK: br i1 %[[TEST]], label %[[CONT:.*]], label %[[SLOW:.*]], {{.*}} !nosanitize
// CHECK: [[SLOW]]
// ITANIUM: call void @__cfi_slowpath_diag(i64 7004155349499253778, i8* %[[VT2]], {{.*}}) {{.*}} !nosanitize

View File

@ -15,9 +15,12 @@ void f(S *s) {
void g() {
void (*fp)(S *) = f;
// CHECK: call i1 @llvm.bitset.test(i8* {{.*}}, metadata ![[VOIDS:[0-9]+]])
// CHECK: call i1 @llvm.type.test(i8* {{.*}}, metadata [[VOIDS:![0-9]+]])
fp(0);
}
// ITANIUM: !{![[VOIDS]], void (%"struct.(anonymous namespace)::S"*)* @_ZN12_GLOBAL__N_11fEPNS_1SE, i64 0}
// MS: !{![[VOIDS]], void (%"struct.(anonymous namespace)::S"*)* @"\01?f@?A@@YAXPEAUS@?A@@@Z", i64 0}
// ITANIUM: define internal void @_ZN12_GLOBAL__N_11fEPNS_1SE({{.*}} !type [[TS:![0-9]+]]
// MS: define internal void @"\01?f@?A@@YAXPEAUS@?A@@@Z"({{.*}} !type [[TS:![0-9]+]]
// CHECK: [[VOIDS]] = distinct !{}
// CHECK: [[TS]] = !{i64 0, [[VOIDS]]}

View File

@ -8,5 +8,5 @@ struct A {
A::A() {}
// RTTI: !{!"?AUA@@", [2 x i8*]* {{.*}}, i64 8}
// NO-RTTI: !{!"?AUA@@", [1 x i8*]* {{.*}}, i64 0}
// RTTI: !{i64 8, !"?AUA@@"}
// NO-RTTI: !{i64 0, !"?AUA@@"}

View File

@ -17,8 +17,8 @@ struct C : A {
// CHECK-LABEL: @bg
// CHECK-STRICT-LABEL: @bg
extern "C" void bg(B *b) {
// CHECK: call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"_ZTS1B")
// CHECK-STRICT: call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"_ZTS1B")
// CHECK: call i1 @llvm.type.test(i8* {{%[^ ]*}}, metadata !"_ZTS1B")
// CHECK-STRICT: call i1 @llvm.type.test(i8* {{%[^ ]*}}, metadata !"_ZTS1B")
b->g();
}
@ -29,7 +29,7 @@ extern "C" void cg(C *c) {
// In this case C's layout is the same as its base class, so we allow
// c to be of type A in non-strict mode.
// CHECK: call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"_ZTS1A")
// CHECK-STRICT: call i1 @llvm.bitset.test(i8* {{%[^ ]*}}, metadata !"_ZTS1C")
// CHECK: call i1 @llvm.type.test(i8* {{%[^ ]*}}, metadata !"_ZTS1A")
// CHECK-STRICT: call i1 @llvm.type.test(i8* {{%[^ ]*}}, metadata !"_ZTS1C")
c->g();
}

View File

@ -67,41 +67,41 @@ struct C11 {
void f(C1 *c1, C2 *c2, C3 *c3, C4 *c4, C5 *c5, C6 *c6, std::C7 *c7,
std::C7::C8 *c8, stdext::C9 *c9, other::C10 *c10) {
// ITANIUM: bitset.test{{.*}}!"_ZTS2C1"
// MS: bitset.test{{.*}}!"?AUC1@@"
// ITANIUM: type.test{{.*}}!"_ZTS2C1"
// MS: type.test{{.*}}!"?AUC1@@"
c1->f();
// ITANIUM-NOT: bitset.test{{.*}}!"_ZTS2C2"
// MS: bitset.test{{.*}}!"?AUC2@@"
// ITANIUM-NOT: type.test{{.*}}!"_ZTS2C2"
// MS: type.test{{.*}}!"?AUC2@@"
c2->f();
// ITANIUM: bitset.test{{.*}}!"_ZTS2C3"
// MS-NOT: bitset.test{{.*}}!"?AUC3@@"
// ITANIUM: type.test{{.*}}!"_ZTS2C3"
// MS-NOT: type.test{{.*}}!"?AUC3@@"
c3->f();
// ITANIUM: bitset.test{{.*}}!"_ZTS2C4"
// MS-NOT: bitset.test{{.*}}!"?AUC4@@"
// ITANIUM: type.test{{.*}}!"_ZTS2C4"
// MS-NOT: type.test{{.*}}!"?AUC4@@"
c4->f();
// ITANIUM-NOT: bitset.test{{.*}}!"_ZTS2C5"
// MS-NOT: bitset.test{{.*}}!"?AUC5@@"
// ITANIUM-NOT: type.test{{.*}}!"_ZTS2C5"
// MS-NOT: type.test{{.*}}!"?AUC5@@"
c5->f();
// ITANIUM-NOT: bitset.test{{.*}}!"_ZTS2C6"
// MS-NOT: bitset.test{{.*}}!"?AUC6@@"
// ITANIUM-NOT: type.test{{.*}}!"_ZTS2C6"
// MS-NOT: type.test{{.*}}!"?AUC6@@"
c6->f();
// ITANIUM: bitset.test{{.*}}!"_ZTSSt2C7"
// MS-STD: bitset.test{{.*}}!"?AUC7@std@@"
// MS-NOSTD-NOT: bitset.test{{.*}}!"?AUC7@std@@"
// ITANIUM: type.test{{.*}}!"_ZTSSt2C7"
// MS-STD: type.test{{.*}}!"?AUC7@std@@"
// MS-NOSTD-NOT: type.test{{.*}}!"?AUC7@std@@"
c7->f();
// ITANIUM: bitset.test{{.*}}!"_ZTSNSt2C72C8E"
// MS-STD: bitset.test{{.*}}!"?AUC8@C7@std@@"
// MS-NOSTD-NOT: bitset.test{{.*}}!"?AUC8@C7@std@@"
// ITANIUM: type.test{{.*}}!"_ZTSNSt2C72C8E"
// MS-STD: type.test{{.*}}!"?AUC8@C7@std@@"
// MS-NOSTD-NOT: type.test{{.*}}!"?AUC8@C7@std@@"
c8->f();
// ITANIUM: bitset.test{{.*}}!"_ZTSN6stdext2C9E"
// MS-STD: bitset.test{{.*}}!"?AUC9@stdext@@"
// MS-NOSTD-NOT: bitset.test{{.*}}!"?AUC9@stdext@@"
// ITANIUM: type.test{{.*}}!"_ZTSN6stdext2C9E"
// MS-STD: type.test{{.*}}!"?AUC9@stdext@@"
// MS-NOSTD-NOT: type.test{{.*}}!"?AUC9@stdext@@"
c9->f();
// ITANIUM: bitset.test{{.*}}!"_ZTSN5other3C10E"
// MS: bitset.test{{.*}}!"?AUC10@other@@"
// ITANIUM: type.test{{.*}}!"_ZTSN5other3C10E"
// MS: type.test{{.*}}!"?AUC10@other@@"
c10->f();
// ITANIUM: bitset.test{{.*}}!{{[0-9]}}
// MS: bitset.test{{.*}}!{{[0-9]}}
// ITANIUM: type.test{{.*}}!{{[0-9]}}
// MS: type.test{{.*}}!{{[0-9]}}
C11 *c11;
c11->f();
}

View File

@ -0,0 +1,226 @@
// Tests for the cfi-vcall feature:
// RUN: %clang_cc1 -flto -triple x86_64-unknown-linux -fvisibility hidden -fsanitize=cfi-vcall -fsanitize-trap=cfi-vcall -emit-llvm -o - %s | FileCheck --check-prefix=CFI --check-prefix=ITANIUM --check-prefix=ITANIUM-NDIAG --check-prefix=NDIAG %s
// RUN: %clang_cc1 -flto -triple x86_64-unknown-linux -fvisibility hidden -fsanitize=cfi-vcall -emit-llvm -o - %s | FileCheck --check-prefix=CFI --check-prefix=ITANIUM --check-prefix=ITANIUM-DIAG --check-prefix=DIAG --check-prefix=DIAG-ABORT %s
// RUN: %clang_cc1 -flto -triple x86_64-unknown-linux -fvisibility hidden -fsanitize=cfi-vcall -fsanitize-recover=cfi-vcall -emit-llvm -o - %s | FileCheck --check-prefix=CFI --check-prefix=ITANIUM --check-prefix=ITANIUM-DIAG --check-prefix=DIAG --check-prefix=DIAG-RECOVER %s
// RUN: %clang_cc1 -flto -triple x86_64-pc-windows-msvc -fsanitize=cfi-vcall -fsanitize-trap=cfi-vcall -emit-llvm -o - %s | FileCheck --check-prefix=CFI --check-prefix=MS --check-prefix=NDIAG %s
// Tests for the whole-program-vtables feature:
// RUN: %clang_cc1 -flto -triple x86_64-unknown-linux -fvisibility hidden -fwhole-program-vtables -emit-llvm -o - %s | FileCheck --check-prefix=VTABLE-OPT --check-prefix=ITANIUM %s
// RUN: %clang_cc1 -flto -triple x86_64-pc-windows-msvc -fwhole-program-vtables -emit-llvm -o - %s | FileCheck --check-prefix=VTABLE-OPT --check-prefix=MS %s
// ITANIUM: @_ZTV1A = {{[^!]*}}, !type [[A16:![0-9]+]]
// ITANIUM-DIAG-SAME: !type [[ALL16:![0-9]+]]
// ITANIUM: @_ZTV1B = {{[^!]*}}, !type [[A32:![0-9]+]]
// ITANIUM-DIAG-SAME: !type [[ALL32:![0-9]+]]
// ITANIUM-SAME: !type [[B32:![0-9]+]]
// ITANIUM-DIAG-SAME: !type [[ALL32]]
// ITANIUM: @_ZTV1C = {{[^!]*}}, !type [[A32]]
// ITANIUM-DIAG-SAME: !type [[ALL32]]
// ITANIUM-SAME: !type [[C32:![0-9]+]]
// ITANIUM-DIAG-SAME: !type [[ALL32]]
// DIAG: @[[SRC:.*]] = private unnamed_addr constant [{{.*}} x i8] c"{{.*}}type-metadata.cpp\00", align 1
// DIAG: @[[TYPE:.*]] = private unnamed_addr constant { i16, i16, [4 x i8] } { i16 -1, i16 0, [4 x i8] c"'A'\00" }
// DIAG: @[[BADTYPESTATIC:.*]] = private unnamed_addr global { i8, { [{{.*}} x i8]*, i32, i32 }, { i16, i16, [4 x i8] }* } { i8 0, { [{{.*}} x i8]*, i32, i32 } { [{{.*}} x i8]* @[[SRC]], i32 123, i32 3 }, { i16, i16, [4 x i8] }* @[[TYPE]] }
// ITANIUM: @_ZTVN12_GLOBAL__N_11DE = {{[^!]*}}, !type [[A32]]
// ITANIUM-DIAG-SAME: !type [[ALL32]]
// ITANIUM-SAME: !type [[B32]]
// ITANIUM-DIAG-SAME: !type [[ALL32]]
// ITANIUM-SAME: !type [[C88:![0-9]+]]
// ITANIUM-DIAG-SAME: !type [[ALL88:![0-9]+]]
// ITANIUM-SAME: !type [[D32:![0-9]+]]
// ITANIUM-DIAG-SAME: !type [[ALL32]]
// ITANIUM: @_ZTCN12_GLOBAL__N_11DE0_1B = {{[^!]*}}, !type [[A32]]
// ITANIUM-DIAG-SAME: !type [[ALL32]]
// ITANIUM-SAME: !type [[B32]]
// ITANIUM-DIAG-SAME: !type [[ALL32]]
// ITANIUM: @_ZTCN12_GLOBAL__N_11DE8_1C = {{[^!]*}}, !type [[A64:![0-9]+]]
// ITANIUM-DIAG-SAME: !type [[ALL64:![0-9]+]]
// ITANIUM-SAME: !type [[C32]]
// ITANIUM-DIAG-SAME: !type [[ALL32]]
// ITANIUM: @_ZTVZ3foovE2FA = {{[^!]*}}, !type [[A16]]
// ITANIUM-DIAG-SAME: !type [[ALL16]]
// ITANIUM-SAME: !type [[FA16:![0-9]+]]
// ITANIUM-DIAG-SAME: !type [[ALL16]]
// MS: comdat($"\01??_7A@@6B@"), !type [[A8:![0-9]+]]
// MS: comdat($"\01??_7B@@6B0@@"), !type [[B8:![0-9]+]]
// MS: comdat($"\01??_7B@@6BA@@@"), !type [[A8]]
// MS: comdat($"\01??_7C@@6B@"), !type [[A8]]
// MS: comdat($"\01??_7D@?A@@6BB@@@"), !type [[B8]], !type [[D8:![0-9]+]]
// MS: comdat($"\01??_7D@?A@@6BA@@@"), !type [[A8]]
// MS: comdat($"\01??_7FA@?1??foo@@YAXXZ@6B@"), !type [[A8]], !type [[FA8:![0-9]+]]
struct A {
A();
virtual void f();
};
struct B : virtual A {
B();
virtual void g();
virtual void h();
};
struct C : virtual A {
C();
};
namespace {
struct D : B, C {
D();
virtual void f();
virtual void h();
};
}
A::A() {}
B::B() {}
C::C() {}
D::D() {}
void A::f() {
}
void B::g() {
}
void D::f() {
}
void D::h() {
}
// ITANIUM: define hidden void @_Z2afP1A
// MS: define void @"\01?af@@YAXPEAUA@@@Z"
void af(A *a) {
// ITANIUM: [[P:%[^ ]*]] = call i1 @llvm.type.test(i8* [[VT:%[^ ]*]], metadata !"_ZTS1A")
// MS: [[P:%[^ ]*]] = call i1 @llvm.type.test(i8* [[VT:%[^ ]*]], metadata !"?AUA@@")
// DIAG-NEXT: [[VTVALID0:%[^ ]*]] = call i1 @llvm.type.test(i8* [[VT]], metadata !"all-vtables")
// VTABLE-OPT: call void @llvm.assume(i1 [[P]])
// CFI-NEXT: br i1 [[P]], label %[[CONTBB:[^ ,]*]], label %[[TRAPBB:[^ ,]*]]
// CFI-NEXT: {{^$}}
// CFI: [[TRAPBB]]
// NDIAG-NEXT: call void @llvm.trap()
// NDIAG-NEXT: unreachable
// DIAG-NEXT: [[VTINT:%[^ ]*]] = ptrtoint i8* [[VT]] to i64
// DIAG-NEXT: [[VTVALID:%[^ ]*]] = zext i1 [[VTVALID0]] to i64
// DIAG-ABORT-NEXT: call void @__ubsan_handle_cfi_check_fail_abort(i8* getelementptr inbounds ({{.*}} @[[BADTYPESTATIC]], i32 0, i32 0), i64 [[VTINT]], i64 [[VTVALID]])
// DIAG-ABORT-NEXT: unreachable
// DIAG-RECOVER-NEXT: call void @__ubsan_handle_cfi_check_fail(i8* getelementptr inbounds ({{.*}} @[[BADTYPESTATIC]], i32 0, i32 0), i64 [[VTINT]], i64 [[VTVALID]])
// DIAG-RECOVER-NEXT: br label %[[CONTBB]]
// CFI: [[CONTBB]]
// CFI: call void %
#line 123
a->f();
}
// ITANIUM: define internal void @_Z3df1PN12_GLOBAL__N_11DE
// MS: define internal void @"\01?df1@@YAXPEAUD@?A@@@Z"
void df1(D *d) {
// ITANIUM: {{%[^ ]*}} = call i1 @llvm.type.test(i8* {{%[^ ]*}}, metadata ![[DTYPE:[0-9]+]])
// MS: {{%[^ ]*}} = call i1 @llvm.type.test(i8* {{%[^ ]*}}, metadata !"?AUA@@")
d->f();
}
// ITANIUM: define internal void @_Z3dg1PN12_GLOBAL__N_11DE
// MS: define internal void @"\01?dg1@@YAXPEAUD@?A@@@Z"
void dg1(D *d) {
// ITANIUM: {{%[^ ]*}} = call i1 @llvm.type.test(i8* {{%[^ ]*}}, metadata !"_ZTS1B")
// MS: {{%[^ ]*}} = call i1 @llvm.type.test(i8* {{%[^ ]*}}, metadata !"?AUB@@")
d->g();
}
// ITANIUM: define internal void @_Z3dh1PN12_GLOBAL__N_11DE
// MS: define internal void @"\01?dh1@@YAXPEAUD@?A@@@Z"
void dh1(D *d) {
// ITANIUM: {{%[^ ]*}} = call i1 @llvm.type.test(i8* {{%[^ ]*}}, metadata ![[DTYPE]])
// MS: {{%[^ ]*}} = call i1 @llvm.type.test(i8* {{%[^ ]*}}, metadata ![[DTYPE:[0-9]+]])
d->h();
}
// ITANIUM: define internal void @_Z3df2PN12_GLOBAL__N_11DE
// MS: define internal void @"\01?df2@@YAXPEAUD@?A@@@Z"
__attribute__((no_sanitize("cfi")))
void df2(D *d) {
// CFI-NOT: call i1 @llvm.type.test
d->f();
}
// ITANIUM: define internal void @_Z3df3PN12_GLOBAL__N_11DE
// MS: define internal void @"\01?df3@@YAXPEAUD@?A@@@Z"
__attribute__((no_sanitize("address"))) __attribute__((no_sanitize("cfi-vcall")))
void df3(D *d) {
// CFI-NOT: call i1 @llvm.type.test
d->f();
}
D d;
void foo() {
df1(&d);
dg1(&d);
dh1(&d);
df2(&d);
df3(&d);
struct FA : A {
void f() {}
} fa;
af(&fa);
}
namespace test2 {
struct A {
virtual void m_fn1();
};
struct B {
virtual void m_fn2();
};
struct C : B, A {};
struct D : C {
void m_fn1();
};
// ITANIUM: define hidden void @_ZN5test21fEPNS_1DE
// MS: define void @"\01?f@test2@@YAXPEAUD@1@@Z"
void f(D *d) {
// ITANIUM: {{%[^ ]*}} = call i1 @llvm.type.test(i8* {{%[^ ]*}}, metadata !"_ZTSN5test21DE")
// MS: {{%[^ ]*}} = call i1 @llvm.type.test(i8* {{%[^ ]*}}, metadata !"?AUA@test2@@")
d->m_fn1();
}
}
// ITANIUM: [[A16]] = !{i64 16, !"_ZTS1A"}
// ITANIUM-DIAG: [[ALL16]] = !{i64 16, !"all-vtables"}
// ITANIUM: [[A32]] = !{i64 32, !"_ZTS1A"}
// ITANIUM-DIAG: [[ALL32]] = !{i64 32, !"all-vtables"}
// ITANIUM: [[B32]] = !{i64 32, !"_ZTS1B"}
// ITANIUM: [[C32]] = !{i64 32, !"_ZTS1C"}
// ITANIUM: [[C88]] = !{i64 88, !"_ZTS1C"}
// ITANIUM-DIAG: [[ALL88]] = !{i64 88, !"all-vtables"}
// ITANIUM: [[D32]] = !{i64 32, [[D_ID:![0-9]+]]}
// ITANIUM: [[D_ID]] = distinct !{}
// ITANIUM: [[A64]] = !{i64 64, !"_ZTS1A"}
// ITANIUM-DIAG: [[ALL64]] = !{i64 64, !"all-vtables"}
// ITANIUM: [[FA16]] = !{i64 16, [[FA_ID:![0-9]+]]}
// ITANIUM: [[FA_ID]] = distinct !{}
// MS: [[A8]] = !{i64 8, !"?AUA@@"}
// MS: [[B8]] = !{i64 8, !"?AUB@@"}
// MS: [[D8]] = !{i64 8, [[D_ID:![0-9]+]]}
// MS: [[D_ID]] = distinct !{}
// MS: [[FA8]] = !{i64 8, [[FA_ID:![0-9]+]]}
// MS: [[FA_ID]] = distinct !{}