Index: cfe/trunk/docs/ControlFlowIntegrityDesign.rst =================================================================== --- cfe/trunk/docs/ControlFlowIntegrityDesign.rst +++ cfe/trunk/docs/ControlFlowIntegrityDesign.rst @@ -90,10 +90,10 @@ 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 @@ 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 @@ 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 @@ 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 Index: cfe/trunk/lib/CodeGen/CGClass.cpp =================================================================== --- cfe/trunk/lib/CodeGen/CGClass.cpp +++ cfe/trunk/lib/CodeGen/CGClass.cpp @@ -2485,21 +2485,21 @@ 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 @@ 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 @@ 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}); } Index: cfe/trunk/lib/CodeGen/CGExpr.cpp =================================================================== --- cfe/trunk/lib/CodeGen/CGExpr.cpp +++ cfe/trunk/lib/CodeGen/CGExpr.cpp @@ -2682,7 +2682,7 @@ 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 @@ 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)}); } Index: cfe/trunk/lib/CodeGen/CGVTables.cpp =================================================================== --- cfe/trunk/lib/CodeGen/CGVTables.cpp +++ cfe/trunk/lib/CodeGen/CGVTables.cpp @@ -709,7 +709,7 @@ VTLayout->getNumVTableThunks(), RTTI); VTable->setInitializer(Init); - CGM.EmitVTableBitSetEntries(VTable, *VTLayout.get()); + CGM.EmitVTableTypeMetadata(VTable, *VTLayout.get()); return VTable; } @@ -933,8 +933,8 @@ 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 @@ 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); } Index: cfe/trunk/lib/CodeGen/CodeGenFunction.h =================================================================== --- cfe/trunk/lib/CodeGen/CodeGenFunction.h +++ cfe/trunk/lib/CodeGen/CodeGenFunction.h @@ -1413,15 +1413,15 @@ 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. Index: cfe/trunk/lib/CodeGen/CodeGenModule.h =================================================================== --- cfe/trunk/lib/CodeGen/CodeGenModule.h +++ cfe/trunk/lib/CodeGen/CodeGenModule.h @@ -1118,29 +1118,27 @@ /// 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(); Index: cfe/trunk/lib/CodeGen/CodeGenModule.cpp =================================================================== --- cfe/trunk/lib/CodeGen/CodeGenModule.cpp +++ cfe/trunk/lib/CodeGen/CodeGenModule.cpp @@ -787,8 +787,7 @@ F->setDLLStorageClass(llvm::GlobalVariable::DefaultStorageClass); } -llvm::ConstantInt * -CodeGenModule::CreateCfiIdForTypeMetadata(llvm::Metadata *MD) { +llvm::ConstantInt *CodeGenModule::CreateCrossDsoCfiTypeId(llvm::Metadata *MD) { llvm::MDString *MDS = dyn_cast(MD); if (!MDS) return nullptr; @@ -989,8 +988,8 @@ } } -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 @@ 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 @@ 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 @@ 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 @@ !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); } } Index: cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp =================================================================== --- cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp +++ cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp @@ -1490,7 +1490,7 @@ EmitFundamentalRTTIDescriptors(); if (!VTable->isDeclarationForLinker()) - CGM.EmitVTableBitSetEntries(VTable, VTLayout); + CGM.EmitVTableTypeMetadata(VTable, VTLayout); } bool ItaniumCXXABI::isVirtualOffsetNeededForVTableField( @@ -1595,7 +1595,7 @@ auto *MethodDecl = cast(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 = Index: cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp =================================================================== --- cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp +++ cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp @@ -254,8 +254,8 @@ 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 @@ 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 @@ : 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 @@ 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 @@ VTable->setInitializer(Init); - emitVTableBitSetEntries(Info, RD, VTable); + emitVTableTypeMetadata(Info, RD, VTable); } } @@ -1819,8 +1816,8 @@ 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"); Index: cfe/trunk/test/CodeGen/cfi-check-fail.c =================================================================== --- cfe/trunk/test/CodeGen/cfi-check-fail.c +++ cfe/trunk/test/CodeGen/cfi-check-fail.c @@ -23,7 +23,7 @@ // 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 Index: cfe/trunk/test/CodeGen/cfi-check-fail2.c =================================================================== --- cfe/trunk/test/CodeGen/cfi-check-fail2.c +++ cfe/trunk/test/CodeGen/cfi-check-fail2.c @@ -23,7 +23,7 @@ // 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 Index: cfe/trunk/test/CodeGen/cfi-icall-cross-dso.c =================================================================== --- cfe/trunk/test/CodeGen/cfi-icall-cross-dso.c +++ cfe/trunk/test/CodeGen/cfi-icall-cross-dso.c @@ -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 @@ 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, +// CHECK: !{i32 4, !"Cross-DSO CFI", i32 1} -// MS: !{!"?6AX@Z", void ()* @foo, i64 0} -// MS: !{i64 4195979634929632483, void ()* @foo, i64 0} +// Check that the type entries are correct. -// CHECK: !{i32 4, !"Cross-DSO CFI", i32 1} +// 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} Index: cfe/trunk/test/CodeGen/cfi-icall.c =================================================================== --- cfe/trunk/test/CodeGen/cfi-icall.c +++ cfe/trunk/test/CodeGen/cfi-icall.c @@ -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"} Index: cfe/trunk/test/CodeGenCXX/bitset-inference.cpp =================================================================== --- cfe/trunk/test/CodeGenCXX/bitset-inference.cpp +++ cfe/trunk/test/CodeGenCXX/bitset-inference.cpp @@ -1,107 +0,0 @@ -// RUN: %clang_cc1 -flto -triple x86_64-unknown-linux -std=c++11 -fms-extensions -fvisibility hidden -fwhole-program-vtables -emit-llvm -o - %s | FileCheck --check-prefix=ITANIUM %s -// RUN: %clang_cc1 -flto -triple x86_64-pc-windows-msvc -std=c++11 -fms-extensions -fwhole-program-vtables -emit-llvm -o - %s | FileCheck --check-prefix=MS --check-prefix=MS-STD %s -// RUN: %clang_cc1 -flto -triple x86_64-pc-windows-msvc -std=c++11 -fms-extensions -fwhole-program-vtables -flto-visibility-public-std -emit-llvm -o - %s | FileCheck --check-prefix=MS --check-prefix=MS-NOSTD %s - -struct C1 { - virtual void f(); -}; - -struct __attribute__((visibility("default"))) C2 { - virtual void f(); -}; - -struct __declspec(dllexport) C3 { - virtual void f(); -}; - -struct __declspec(dllimport) C4 { - virtual void f(); -}; - -struct [[clang::lto_visibility_public]] C5 { - virtual void f(); -}; - -struct __declspec(uuid("00000000-0000-0000-0000-000000000000")) C6 { - virtual void f(); -}; - -namespace std { - -struct C7 { - virtual void f(); - struct C8 { - virtual void f(); - }; -}; - -} - -extern "C++" { - -namespace stdext { - -struct C9 { - virtual void f(); -}; - -} - -} - -namespace other { - -struct C10 { - virtual void f(); -}; - -} - -namespace { - -struct C11 { - virtual void f(); -}; - -} - -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@@" - c1->f(); - // ITANIUM-NOT: bitset.test{{.*}}!"_ZTS2C2" - // MS: bitset.test{{.*}}!"?AUC2@@" - c2->f(); - // ITANIUM: bitset.test{{.*}}!"_ZTS2C3" - // MS-NOT: bitset.test{{.*}}!"?AUC3@@" - c3->f(); - // ITANIUM: bitset.test{{.*}}!"_ZTS2C4" - // MS-NOT: bitset.test{{.*}}!"?AUC4@@" - c4->f(); - // ITANIUM-NOT: bitset.test{{.*}}!"_ZTS2C5" - // MS-NOT: bitset.test{{.*}}!"?AUC5@@" - c5->f(); - // ITANIUM-NOT: bitset.test{{.*}}!"_ZTS2C6" - // MS-NOT: bitset.test{{.*}}!"?AUC6@@" - c6->f(); - // ITANIUM: bitset.test{{.*}}!"_ZTSSt2C7" - // MS-STD: bitset.test{{.*}}!"?AUC7@std@@" - // MS-NOSTD-NOT: bitset.test{{.*}}!"?AUC7@std@@" - c7->f(); - // ITANIUM: bitset.test{{.*}}!"_ZTSNSt2C72C8E" - // MS-STD: bitset.test{{.*}}!"?AUC8@C7@std@@" - // MS-NOSTD-NOT: bitset.test{{.*}}!"?AUC8@C7@std@@" - c8->f(); - // ITANIUM: bitset.test{{.*}}!"_ZTSN6stdext2C9E" - // MS-STD: bitset.test{{.*}}!"?AUC9@stdext@@" - // MS-NOSTD-NOT: bitset.test{{.*}}!"?AUC9@stdext@@" - c9->f(); - // ITANIUM: bitset.test{{.*}}!"_ZTSN5other3C10E" - // MS: bitset.test{{.*}}!"?AUC10@other@@" - c10->f(); - // ITANIUM: bitset.test{{.*}}!{{[0-9]}} - // MS: bitset.test{{.*}}!{{[0-9]}} - C11 *c11; - c11->f(); -} Index: cfe/trunk/test/CodeGenCXX/bitsets.cpp =================================================================== --- cfe/trunk/test/CodeGenCXX/bitsets.cpp +++ cfe/trunk/test/CodeGenCXX/bitsets.cpp @@ -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} Index: cfe/trunk/test/CodeGenCXX/cfi-blacklist.cpp =================================================================== --- cfe/trunk/test/CodeGenCXX/cfi-blacklist.cpp +++ cfe/trunk/test/CodeGenCXX/cfi-blacklist.cpp @@ -15,15 +15,15 @@ } // 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(); } Index: cfe/trunk/test/CodeGenCXX/cfi-cast.cpp =================================================================== --- cfe/trunk/test/CodeGenCXX/cfi-cast.cpp +++ cfe/trunk/test/CodeGenCXX/cfi-cast.cpp @@ -19,7 +19,7 @@ // 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 @@ // 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 @@ // 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 @@ // 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 @@ // 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 @@ // 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 @@ // 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(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(); } Index: cfe/trunk/test/CodeGenCXX/cfi-cross-dso.cpp =================================================================== --- cfe/trunk/test/CodeGenCXX/cfi-cross-dso.cpp +++ cfe/trunk/test/CodeGenCXX/cfi-cross-dso.cpp @@ -30,8 +30,8 @@ // 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 Index: cfe/trunk/test/CodeGenCXX/cfi-icall.cpp =================================================================== --- cfe/trunk/test/CodeGenCXX/cfi-icall.cpp +++ cfe/trunk/test/CodeGenCXX/cfi-icall.cpp @@ -15,9 +15,12 @@ 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]]} Index: cfe/trunk/test/CodeGenCXX/cfi-ms-rtti.cpp =================================================================== --- cfe/trunk/test/CodeGenCXX/cfi-ms-rtti.cpp +++ cfe/trunk/test/CodeGenCXX/cfi-ms-rtti.cpp @@ -8,5 +8,5 @@ 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@@"} Index: cfe/trunk/test/CodeGenCXX/cfi-nvcall.cpp =================================================================== --- cfe/trunk/test/CodeGenCXX/cfi-nvcall.cpp +++ cfe/trunk/test/CodeGenCXX/cfi-nvcall.cpp @@ -17,8 +17,8 @@ // 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 @@ // 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(); } Index: cfe/trunk/test/CodeGenCXX/lto-visibility-inference.cpp =================================================================== --- cfe/trunk/test/CodeGenCXX/lto-visibility-inference.cpp +++ cfe/trunk/test/CodeGenCXX/lto-visibility-inference.cpp @@ -0,0 +1,107 @@ +// RUN: %clang_cc1 -flto -triple x86_64-unknown-linux -std=c++11 -fms-extensions -fvisibility hidden -fwhole-program-vtables -emit-llvm -o - %s | FileCheck --check-prefix=ITANIUM %s +// RUN: %clang_cc1 -flto -triple x86_64-pc-windows-msvc -std=c++11 -fms-extensions -fwhole-program-vtables -emit-llvm -o - %s | FileCheck --check-prefix=MS --check-prefix=MS-STD %s +// RUN: %clang_cc1 -flto -triple x86_64-pc-windows-msvc -std=c++11 -fms-extensions -fwhole-program-vtables -flto-visibility-public-std -emit-llvm -o - %s | FileCheck --check-prefix=MS --check-prefix=MS-NOSTD %s + +struct C1 { + virtual void f(); +}; + +struct __attribute__((visibility("default"))) C2 { + virtual void f(); +}; + +struct __declspec(dllexport) C3 { + virtual void f(); +}; + +struct __declspec(dllimport) C4 { + virtual void f(); +}; + +struct [[clang::lto_visibility_public]] C5 { + virtual void f(); +}; + +struct __declspec(uuid("00000000-0000-0000-0000-000000000000")) C6 { + virtual void f(); +}; + +namespace std { + +struct C7 { + virtual void f(); + struct C8 { + virtual void f(); + }; +}; + +} + +extern "C++" { + +namespace stdext { + +struct C9 { + virtual void f(); +}; + +} + +} + +namespace other { + +struct C10 { + virtual void f(); +}; + +} + +namespace { + +struct C11 { + virtual void f(); +}; + +} + +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: type.test{{.*}}!"_ZTS2C1" + // MS: type.test{{.*}}!"?AUC1@@" + c1->f(); + // ITANIUM-NOT: type.test{{.*}}!"_ZTS2C2" + // MS: type.test{{.*}}!"?AUC2@@" + c2->f(); + // ITANIUM: type.test{{.*}}!"_ZTS2C3" + // MS-NOT: type.test{{.*}}!"?AUC3@@" + c3->f(); + // ITANIUM: type.test{{.*}}!"_ZTS2C4" + // MS-NOT: type.test{{.*}}!"?AUC4@@" + c4->f(); + // ITANIUM-NOT: type.test{{.*}}!"_ZTS2C5" + // MS-NOT: type.test{{.*}}!"?AUC5@@" + c5->f(); + // ITANIUM-NOT: type.test{{.*}}!"_ZTS2C6" + // MS-NOT: type.test{{.*}}!"?AUC6@@" + c6->f(); + // ITANIUM: type.test{{.*}}!"_ZTSSt2C7" + // MS-STD: type.test{{.*}}!"?AUC7@std@@" + // MS-NOSTD-NOT: type.test{{.*}}!"?AUC7@std@@" + c7->f(); + // ITANIUM: type.test{{.*}}!"_ZTSNSt2C72C8E" + // MS-STD: type.test{{.*}}!"?AUC8@C7@std@@" + // MS-NOSTD-NOT: type.test{{.*}}!"?AUC8@C7@std@@" + c8->f(); + // ITANIUM: type.test{{.*}}!"_ZTSN6stdext2C9E" + // MS-STD: type.test{{.*}}!"?AUC9@stdext@@" + // MS-NOSTD-NOT: type.test{{.*}}!"?AUC9@stdext@@" + c9->f(); + // ITANIUM: type.test{{.*}}!"_ZTSN5other3C10E" + // MS: type.test{{.*}}!"?AUC10@other@@" + c10->f(); + // ITANIUM: type.test{{.*}}!{{[0-9]}} + // MS: type.test{{.*}}!{{[0-9]}} + C11 *c11; + c11->f(); +} Index: cfe/trunk/test/CodeGenCXX/type-metadata.cpp =================================================================== --- cfe/trunk/test/CodeGenCXX/type-metadata.cpp +++ cfe/trunk/test/CodeGenCXX/type-metadata.cpp @@ -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 !{}