]> granicus.if.org Git - clang/commitdiff
CodeGen: Update Clang to use the new type metadata.
authorPeter Collingbourne <peter@pcc.me.uk>
Fri, 24 Jun 2016 21:21:46 +0000 (21:21 +0000)
committerPeter Collingbourne <peter@pcc.me.uk>
Fri, 24 Jun 2016 21:21:46 +0000 (21:21 +0000)
Differential Revision: http://reviews.llvm.org/D21054

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@273730 91177308-0d34-0410-b5e6-96231b3b80d8

22 files changed:
docs/ControlFlowIntegrityDesign.rst
lib/CodeGen/CGClass.cpp
lib/CodeGen/CGExpr.cpp
lib/CodeGen/CGVTables.cpp
lib/CodeGen/CodeGenFunction.h
lib/CodeGen/CodeGenModule.cpp
lib/CodeGen/CodeGenModule.h
lib/CodeGen/ItaniumCXXABI.cpp
lib/CodeGen/MicrosoftCXXABI.cpp
test/CodeGen/cfi-check-fail.c
test/CodeGen/cfi-check-fail2.c
test/CodeGen/cfi-icall-cross-dso.c
test/CodeGen/cfi-icall.c
test/CodeGenCXX/bitsets.cpp [deleted file]
test/CodeGenCXX/cfi-blacklist.cpp
test/CodeGenCXX/cfi-cast.cpp
test/CodeGenCXX/cfi-cross-dso.cpp
test/CodeGenCXX/cfi-icall.cpp
test/CodeGenCXX/cfi-ms-rtti.cpp
test/CodeGenCXX/cfi-nvcall.cpp
test/CodeGenCXX/lto-visibility-inference.cpp [moved from test/CodeGenCXX/bitset-inference.cpp with 57% similarity]
test/CodeGenCXX/type-metadata.cpp [new file with mode: 0644]

index b4aacd365670510f27b020321b9c8f26bd4bb05c..38c5e5b99e3181f5dcad32dea6aa887059e35cd0 100644 (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
index dc4455fbc7d234637e4ad0461c2a97ec74e13b59..ba46541b02bc6da3e21c9b0a925e7d6864187861 100644 (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});
 }
 
index 7f8d87e925b37809d06067731d16696f00c69878..9917a6b4147fe1a1f289e735ecf32e0ec9ce8f0f 100644 (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)});
     }
index 6f749056ad6ee5852aa933530f9303c891dca981..83974e0d214ab3160a68b018647780aa19de0027 100644 (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);
 }
index af7e6114af63de2acd976faf8bff6a5688d31763..28ee621b31b605e7aeff72bea850dd6e2f0e2845 100644 (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.
index 507772707ce2ea80aaad360bbfe65291cdd00fa3..02858b3864e452761b930ce8eb2be48978c584a4 100644 (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);
   }
 }
 
index a75e4aa2a32ab847525a230035940b5877189660..94904997d629172b0c231067e37e7da6d9bcd039 100644 (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();
index 891db6df425fdf21c418eb0252d6de249a99ca71..b33ef73fa4b76a124d49cdc52e8fd6fee5d241cd 100644 (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 =
index 4482372c5de75cb489d8f5eccbc50288a4957cbb..a48e084158d38cad1ffa84599d3dd0bdbeb99eef 100644 (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");
index 4560cd8747145b524abbdf02e9ca0702bde8cfbc..b850193b54acb026ddcead7cb5b6e1ed2bc669fa 100644 (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
index 02ceb930e61832a422e971940e9d34834c60463b..5340871c2ebec04e8bab4a3ca78319b05ecab7dd 100644 (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
index 13cff1065fd802622528050e3c0748a57ef6fe9d..636a9e4aedb4d02b06d30369ea86823e4213bcc2 100644 (file)
 // 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}
+// CHECK: !{i32 4, !"Cross-DSO CFI", i32 1}
 
-// 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 that the type entries are correct.
 
-// MS: !{!"?6AX@Z", void ()* @foo, i64 0}
-// MS: !{i64 4195979634929632483, void ()* @foo, i64 0}
+// ITANIUM: [[TVOID]] = !{i64 0, !"_ZTSFvvE"}
+// ITANIUM: [[TVOID_ID]] = !{i64 0, i64 9080559750644022485}
+// ITANIUM: [[TNOPROTO]] = !{i64 0, !"_ZTSFvE"}
+// ITANIUM: [[TNOPROTO_ID]] = !{i64 0, i64 6588678392271548388}
 
-// CHECK: !{i32 4, !"Cross-DSO CFI", i32 1}
+// 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 d6cebef49a14756bddd9bc5d9ac6f6a2f4a3e4cd..ed34f4f44beb6bdbb4790976fe29481fa507838c 100644 (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"}
diff --git a/test/CodeGenCXX/bitsets.cpp b/test/CodeGenCXX/bitsets.cpp
deleted file mode 100644 (file)
index 4d11f39..0000000
+++ /dev/null
@@ -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 38b9971c90ec1c39fe59fe11d826d0c491da14ab..af8a10601d2928bf475568eb2e9c25981b1eceb2 100644 (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();
 }
index 9fe87111b388f8142384a76bb3e68b64ae070203..54641b52332bb3e8d5f7c6c56cce8c9dc3f08296 100644 (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();
 }
index 84a6879e55fc32f5234d0e2635b44aae381e9da8..d67927d4d2ed004b12dbbe071b3653db855c887d 100644 (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
index eceb92a4421cb2a1fbaa966908ae73a46f030c67..c3c6ed309cc6fb169a117cee2bde0e0b333166c4 100644 (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]]}
index 12c9868ceeee80ec8a101f8a197e394043026b76..fbebad4b1b8d47ed124c11259c4bcdec4b85a9a1 100644 (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@@"}
index ea18e216f07255488a75cc559b2645ab312bc8c3..e968f05600c296e88c241101bda7254923915dc4 100644 (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();
 }
similarity index 57%
rename from test/CodeGenCXX/bitset-inference.cpp
rename to test/CodeGenCXX/lto-visibility-inference.cpp
index d9528609ff29e7663075c3449110851161a54268..8e57ef5e0b892ede139c61ea37a0c1dbdd4adcf8 100644 (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();
 }
diff --git a/test/CodeGenCXX/type-metadata.cpp b/test/CodeGenCXX/type-metadata.cpp
new file mode 100644 (file)
index 0000000..f1edbd8
--- /dev/null
@@ -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 !{}