diff options
59 files changed, 893 insertions, 1015 deletions
diff --git a/llvm/docs/BitSets.rst b/llvm/docs/BitSets.rst deleted file mode 100644 index b35493486b1..00000000000 --- a/llvm/docs/BitSets.rst +++ /dev/null @@ -1,221 +0,0 @@ -======= -Bitsets -======= - -This is a mechanism that allows IR modules to co-operatively build pointer -sets corresponding to addresses within a given set of globals. One example -of a use case for this is to allow a C++ program to efficiently verify (at -each call site) that a vtable pointer is in the set of valid vtable pointers -for the type of the class or its derived classes. - -To use the mechanism, a client creates a global metadata node named -``llvm.bitsets``. Each element is a metadata node with three elements: - -1. a metadata object representing an identifier for the bitset -2. either a global variable or a function -3. a byte offset into the global (generally zero for functions) - -Each bitset must exclusively contain either global variables or functions. - -.. admonition:: Limitation - - The current implementation only supports functions as members of bitsets on - the x86-32 and x86-64 architectures. - -An intrinsic, :ref:`llvm.bitset.test <bitset.test>`, is used to test -whether a given pointer is a member of a bitset. - -Representing Type Information using Bitsets -=========================================== - -This section describes how Clang represents C++ type information associated with -virtual tables using bitsets. - -Consider the following inheritance hierarchy: - -.. code-block:: c++ - - struct A { - virtual void f(); - }; - - struct B : A { - virtual void f(); - virtual void g(); - }; - - struct C { - virtual void h(); - }; - - struct D : A, C { - virtual void f(); - virtual void h(); - }; - -The virtual table objects for A, B, C and D look like this (under the Itanium ABI): - -.. csv-table:: Virtual Table Layout for A, B, C, D - :header: Class, 0, 1, 2, 3, 4, 5, 6 - - A, A::offset-to-top, &A::rtti, &A::f - B, B::offset-to-top, &B::rtti, &B::f, &B::g - C, C::offset-to-top, &C::rtti, &C::h - D, D::offset-to-top, &D::rtti, &D::f, &D::h, D::offset-to-top, &D::rtti, thunk for &D::h - -When an object of type A is constructed, the address of ``&A::f`` in A's -virtual table object is stored in the object's vtable pointer. In ABI parlance -this address is known as an `address point`_. Similarly, when an object of type -B is constructed, the address of ``&B::f`` is stored in the vtable pointer. In -this way, the vtable in B's virtual table object is compatible with A's vtable. - -D is a little more complicated, due to the use of multiple inheritance. Its -virtual table object contains two vtables, one compatible with A's vtable and -the other compatible with C's vtable. Objects of type D contain two virtual -pointers, one belonging to the A subobject and containing the address of -the vtable compatible with A's vtable, and the other belonging to the C -subobject and containing the address of the vtable compatible with C's vtable. - -The full set of compatibility information for the above class hierarchy is -shown below. The following table shows the name of a class, the offset of an -address point within that class's vtable and the name of one of the classes -with which that address point is compatible. - -.. csv-table:: Bitsets for A, B, C, D - :header: VTable for, Offset, Compatible Class - - A, 16, A - B, 16, A - , , B - C, 16, C - D, 16, A - , , D - , 48, C - -The next step is to encode this compatibility information into the IR. The way -this is done is to create bitsets named after each of the compatible classes, -into which we add each of the compatible address points in each vtable. -For example, these bitset entries encode the compatibility information for -the above hierarchy: - -:: - - !0 = !{!"_ZTS1A", [3 x i8*]* @_ZTV1A, i64 16} - !1 = !{!"_ZTS1A", [4 x i8*]* @_ZTV1B, i64 16} - !2 = !{!"_ZTS1B", [4 x i8*]* @_ZTV1B, i64 16} - !3 = !{!"_ZTS1C", [3 x i8*]* @_ZTV1C, i64 16} - !4 = !{!"_ZTS1A", [7 x i8*]* @_ZTV1D, i64 16} - !5 = !{!"_ZTS1D", [7 x i8*]* @_ZTV1D, i64 16} - !6 = !{!"_ZTS1C", [7 x i8*]* @_ZTV1D, i64 48} - -With these bitsets, we can now use the ``llvm.bitset.test`` intrinsic to test -whether a given pointer is compatible with a bitset. Working backwards, -if ``llvm.bitset.test`` returns true for a particular pointer, we can also -statically determine the identities of the virtual functions that a particular -virtual call may call. For example, if a program assumes a pointer to be in the -``!"_ZST1A"`` bitset, we know that the address can be only be one of ``_ZTV1A+16``, -``_ZTV1B+16`` or ``_ZTV1D+16`` (i.e. the address points of the vtables of A, -B and D respectively). If we then load an address from that pointer, we know -that the address can only be one of ``&A::f``, ``&B::f`` or ``&D::f``. - -.. _address point: https://mentorembedded.github.io/cxx-abi/abi.html#vtable-general - -Testing Bitset Addresses -======================== - -If a program tests an address using ``llvm.bitset.test``, this will cause -a link-time optimization pass, ``LowerBitSets``, to replace calls to this -intrinsic with efficient code to perform bitset tests. At a high level, -the pass will lay out referenced globals in a consecutive memory region in -the object file, construct bit vectors that map onto that memory region, -and generate code at each of the ``llvm.bitset.test`` call sites to test -pointers against those bit vectors. Because of the layout manipulation, the -globals' definitions must be available at LTO time. For more information, -see the `control flow integrity design document`_. - -A bit set containing functions is transformed into a jump table, which is a -block of code consisting of one branch instruction for each of the functions -in the bit set that branches to the target function. The pass will redirect -any taken function addresses to the corresponding jump table entry. In the -object file's symbol table, the jump table entries take the identities of -the original functions, so that addresses taken outside the module will pass -any verification done inside the module. - -Jump tables may call external functions, so their definitions need not -be available at LTO time. Note that if an externally defined function is a -member of a bitset, there is no guarantee that its identity within the module -will be the same as its identity outside of the module, as the former will -be the jump table entry if a jump table is necessary. - -The `GlobalLayoutBuilder`_ class is responsible for laying out the globals -efficiently to minimize the sizes of the underlying bitsets. - -.. _control flow integrity design document: http://clang.llvm.org/docs/ControlFlowIntegrityDesign.html - -:Example: - -:: - - target datalayout = "e-p:32:32" - - @a = internal global i32 0 - @b = internal global i32 0 - @c = internal global i32 0 - @d = internal global [2 x i32] [i32 0, i32 0] - - define void @e() { - ret void - } - - define void @f() { - ret void - } - - declare void @g() - - !llvm.bitsets = !{!0, !1, !2, !3, !4, !5, !6} - - !0 = !{!"bitset1", i32* @a, i32 0} - !1 = !{!"bitset1", i32* @b, i32 0} - !2 = !{!"bitset2", i32* @b, i32 0} - !3 = !{!"bitset2", i32* @c, i32 0} - !4 = !{!"bitset2", i32* @d, i32 4} - !5 = !{!"bitset3", void ()* @e, i32 0} - !6 = !{!"bitset3", void ()* @g, i32 0} - - declare i1 @llvm.bitset.test(i8* %ptr, metadata %bitset) nounwind readnone - - define i1 @foo(i32* %p) { - %pi8 = bitcast i32* %p to i8* - %x = call i1 @llvm.bitset.test(i8* %pi8, metadata !"bitset1") - ret i1 %x - } - - define i1 @bar(i32* %p) { - %pi8 = bitcast i32* %p to i8* - %x = call i1 @llvm.bitset.test(i8* %pi8, metadata !"bitset2") - ret i1 %x - } - - define i1 @baz(void ()* %p) { - %pi8 = bitcast void ()* %p to i8* - %x = call i1 @llvm.bitset.test(i8* %pi8, metadata !"bitset3") - ret i1 %x - } - - define void @main() { - %a1 = call i1 @foo(i32* @a) ; returns 1 - %b1 = call i1 @foo(i32* @b) ; returns 1 - %c1 = call i1 @foo(i32* @c) ; returns 0 - %a2 = call i1 @bar(i32* @a) ; returns 0 - %b2 = call i1 @bar(i32* @b) ; returns 1 - %c2 = call i1 @bar(i32* @c) ; returns 1 - %d02 = call i1 @bar(i32* getelementptr ([2 x i32]* @d, i32 0, i32 0)) ; returns 0 - %d12 = call i1 @bar(i32* getelementptr ([2 x i32]* @d, i32 0, i32 1)) ; returns 1 - %e = call i1 @baz(void ()* @e) ; returns 1 - %f = call i1 @baz(void ()* @f) ; returns 0 - %g = call i1 @baz(void ()* @g) ; returns 1 - ret void - } - -.. _GlobalLayoutBuilder: http://llvm.org/klaus/llvm/blob/master/include/llvm/Transforms/IPO/LowerBitSets.h diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst index 42ee5bf7262..3cdddcb1eb6 100644 --- a/llvm/docs/LangRef.rst +++ b/llvm/docs/LangRef.rst @@ -4839,12 +4839,6 @@ the loop identifier metadata node directly: !1 = !{!1} ; an identifier for the inner loop !2 = !{!2} ; an identifier for the outer loop -'``llvm.bitsets``' -^^^^^^^^^^^^^^^^^^ - -The ``llvm.bitsets`` global metadata is used to implement -:doc:`bitsets <BitSets>`. - '``invariant.group``' Metadata ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -12274,9 +12268,9 @@ sufficient overall improvement in code quality. For this reason, that the optimizer can otherwise deduce or facts that are of little use to the optimizer. -.. _bitset.test: +.. _type.test: -'``llvm.bitset.test``' Intrinsic +'``llvm.type.test``' Intrinsic ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Syntax: @@ -12284,20 +12278,20 @@ Syntax: :: - declare i1 @llvm.bitset.test(i8* %ptr, metadata %bitset) nounwind readnone + declare i1 @llvm.type.test(i8* %ptr, metadata %type) nounwind readnone Arguments: """""""""" The first argument is a pointer to be tested. The second argument is a -metadata object representing an identifier for a :doc:`bitset <BitSets>`. +metadata object representing a :doc:`type identifier <TypeMetadata>`. Overview: """"""""" -The ``llvm.bitset.test`` intrinsic tests whether the given pointer is a -member of the given bitset. +The ``llvm.type.test`` intrinsic tests whether the given pointer is associated +with the given type identifier. '``llvm.donothing``' Intrinsic ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/llvm/docs/TypeMetadata.rst b/llvm/docs/TypeMetadata.rst new file mode 100644 index 00000000000..98d58b71a6d --- /dev/null +++ b/llvm/docs/TypeMetadata.rst @@ -0,0 +1,226 @@ +============= +Type Metadata +============= + +Type metadata is a mechanism that allows IR modules to co-operatively build +pointer sets corresponding to addresses within a given set of globals. LLVM's +`control flow integrity`_ implementation uses this metadata to efficiently +check (at each call site) that a given address corresponds to either a +valid vtable or function pointer for a given class or function type, and its +whole-program devirtualization pass uses the metadata to identify potential +callees for a given virtual call. + +To use the mechanism, a client creates metadata nodes with two elements: + +1. a byte offset into the global (generally zero for functions) +2. a metadata object representing an identifier for the type + +These metadata nodes are associated with globals by using global object +metadata attachments with the ``!type`` metadata kind. + +Each type identifier must exclusively identify either global variables +or functions. + +.. admonition:: Limitation + + The current implementation only supports attaching metadata to functions on + the x86-32 and x86-64 architectures. + +An intrinsic, :ref:`llvm.type.test <type.test>`, is used to test whether a +given pointer is associated with a type identifier. + +.. _control flow integrity: http://clang.llvm.org/docs/ControlFlowIntegrity.html + +Representing Type Information using Type Metadata +================================================= + +This section describes how Clang represents C++ type information associated with +virtual tables using type metadata. + +Consider the following inheritance hierarchy: + +.. code-block:: c++ + + struct A { + virtual void f(); + }; + + struct B : A { + virtual void f(); + virtual void g(); + }; + + struct C { + virtual void h(); + }; + + struct D : A, C { + virtual void f(); + virtual void h(); + }; + +The virtual table objects for A, B, C and D look like this (under the Itanium ABI): + +.. csv-table:: Virtual Table Layout for A, B, C, D + :header: Class, 0, 1, 2, 3, 4, 5, 6 + + A, A::offset-to-top, &A::rtti, &A::f + B, B::offset-to-top, &B::rtti, &B::f, &B::g + C, C::offset-to-top, &C::rtti, &C::h + D, D::offset-to-top, &D::rtti, &D::f, &D::h, D::offset-to-top, &D::rtti, thunk for &D::h + +When an object of type A is constructed, the address of ``&A::f`` in A's +virtual table object is stored in the object's vtable pointer. In ABI parlance +this address is known as an `address point`_. Similarly, when an object of type +B is constructed, the address of ``&B::f`` is stored in the vtable pointer. In +this way, the vtable in B's virtual table object is compatible with A's vtable. + +D is a little more complicated, due to the use of multiple inheritance. Its +virtual table object contains two vtables, one compatible with A's vtable and +the other compatible with C's vtable. Objects of type D contain two virtual +pointers, one belonging to the A subobject and containing the address of +the vtable compatible with A's vtable, and the other belonging to the C +subobject and containing the address of the vtable compatible with C's vtable. + +The full set of compatibility information for the above class hierarchy is +shown below. The following table shows the name of a class, the offset of an +address point within that class's vtable and the name of one of the classes +with which that address point is compatible. + +.. csv-table:: Type Offsets for A, B, C, D + :header: VTable for, Offset, Compatible Class + + A, 16, A + B, 16, A + , , B + C, 16, C + D, 16, A + , , D + , 48, C + +The next step is to encode this compatibility information into the IR. The way +this is done is to create type metadata named after each of the compatible +classes, with which we associate each of the compatible address points in +each vtable. For example, these type metadata entries encode the compatibility +information for the above hierarchy: + +:: + + @_ZTV1A = constant [...], !type !0 + @_ZTV1B = constant [...], !type !0, !type !1 + @_ZTV1C = constant [...], !type !2 + @_ZTV1D = constant [...], !type !0, !type !3, !type !4 + + !0 = !{i64 16, !"_ZTS1A"} + !1 = !{i64 16, !"_ZTS1B"} + !2 = !{i64 16, !"_ZTS1C"} + !3 = !{i64 16, !"_ZTS1D"} + !4 = !{i64 48, !"_ZTS1C"} + +With this type metadata, we can now use the ``llvm.type.test`` intrinsic to +test whether a given pointer is compatible with a type identifier. Working +backwards, if ``llvm.type.test`` returns true for a particular pointer, +we can also statically determine the identities of the virtual functions +that a particular virtual call may call. For example, if a program assumes +a pointer to be a member of ``!"_ZST1A"``, we know that the address can +be only be one of ``_ZTV1A+16``, ``_ZTV1B+16`` or ``_ZTV1D+16`` (i.e. the +address points of the vtables of A, B and D respectively). If we then load +an address from that pointer, we know that the address can only be one of +``&A::f``, ``&B::f`` or ``&D::f``. + +.. _address point: https://mentorembedded.github.io/cxx-abi/abi.html#vtable-general + +Testing Addresses For Type Membership +===================================== + +If a program tests an address using ``llvm.type.test``, this will cause +a link-time optimization pass, ``LowerTypeTests``, to replace calls to this +intrinsic with efficient code to perform type member tests. At a high level, +the pass will lay out referenced globals in a consecutive memory region in +the object file, construct bit vectors that map onto that memory region, +and generate code at each of the ``llvm.type.test`` call sites to test +pointers against those bit vectors. Because of the layout manipulation, the +globals' definitions must be available at LTO time. For more information, +see the `control flow integrity design document`_. + +A type identifier that identifies functions is transformed into a jump table, +which is a block of code consisting of one branch instruction for each +of the functions associated with the type identifier that branches to the +target function. The pass will redirect any taken function addresses to the +corresponding jump table entry. In the object file's symbol table, the jump +table entries take the identities of the original functions, so that addresses +taken outside the module will pass any verification done inside the module. + +Jump tables may call external functions, so their definitions need not +be available at LTO time. Note that if an externally defined function is +associated with a type identifier, there is no guarantee that its identity +within the module will be the same as its identity outside of the module, +as the former will be the jump table entry if a jump table is necessary. + +The `GlobalLayoutBuilder`_ class is responsible for laying out the globals +efficiently to minimize the sizes of the underlying bitsets. + +.. _control flow integrity design document: http://clang.llvm.org/docs/ControlFlowIntegrityDesign.html + +:Example: + +:: + + target datalayout = "e-p:32:32" + + @a = internal global i32 0, !type !0 + @b = internal global i32 0, !type !0, !type !1 + @c = internal global i32 0, !type !1 + @d = internal global [2 x i32] [i32 0, i32 0], !type !2 + + define void @e() !type !3 { + ret void + } + + define void @f() { + ret void + } + + declare void @g() !type !3 + + !0 = !{i32 0, !"typeid1"} + !1 = !{i32 0, !"typeid2"} + !2 = !{i32 4, !"typeid2"} + !3 = !{i32 0, !"typeid3"} + + declare i1 @llvm.type.test(i8* %ptr, metadata %typeid) nounwind readnone + + define i1 @foo(i32* %p) { + %pi8 = bitcast i32* %p to i8* + %x = call i1 @llvm.type.test(i8* %pi8, metadata !"typeid1") + ret i1 %x + } + + define i1 @bar(i32* %p) { + %pi8 = bitcast i32* %p to i8* + %x = call i1 @llvm.type.test(i8* %pi8, metadata !"typeid2") + ret i1 %x + } + + define i1 @baz(void ()* %p) { + %pi8 = bitcast void ()* %p to i8* + %x = call i1 @llvm.type.test(i8* %pi8, metadata !"typeid3") + ret i1 %x + } + + define void @main() { + %a1 = call i1 @foo(i32* @a) ; returns 1 + %b1 = call i1 @foo(i32* @b) ; returns 1 + %c1 = call i1 @foo(i32* @c) ; returns 0 + %a2 = call i1 @bar(i32* @a) ; returns 0 + %b2 = call i1 @bar(i32* @b) ; returns 1 + %c2 = call i1 @bar(i32* @c) ; returns 1 + %d02 = call i1 @bar(i32* getelementptr ([2 x i32]* @d, i32 0, i32 0)) ; returns 0 + %d12 = call i1 @bar(i32* getelementptr ([2 x i32]* @d, i32 0, i32 1)) ; returns 1 + %e = call i1 @baz(void ()* @e) ; returns 1 + %f = call i1 @baz(void ()* @f) ; returns 0 + %g = call i1 @baz(void ()* @g) ; returns 1 + ret void + } + +.. _GlobalLayoutBuilder: http://llvm.org/klaus/llvm/blob/master/include/llvm/Transforms/IPO/LowerTypeTests.h diff --git a/llvm/docs/index.rst b/llvm/docs/index.rst index 1780b072a7e..54e695b5453 100644 --- a/llvm/docs/index.rst +++ b/llvm/docs/index.rst @@ -261,7 +261,7 @@ For API clients and LLVM developers. CoverageMappingFormat Statepoints MergeFunctions - BitSets + TypeMetadata FaultMaps MIRLangRef diff --git a/llvm/include/llvm/Analysis/BitSetUtils.h b/llvm/include/llvm/Analysis/TypeMetadataUtils.h index 8f799482b80..49607874edc 100644 --- a/llvm/include/llvm/Analysis/BitSetUtils.h +++ b/llvm/include/llvm/Analysis/TypeMetadataUtils.h @@ -1,4 +1,4 @@ -//===- BitSetUtils.h - Utilities related to pointer bitsets ------*- C++ -*-==// +//===- TypeMetadataUtils.h - Utilities related to type metadata --*- C++ -*-==// // // The LLVM Compiler Infrastructure // @@ -7,13 +7,13 @@ // //===----------------------------------------------------------------------===// // -// This file contains functions that make it easier to manipulate bitsets for -// devirtualization. +// This file contains functions that make it easier to manipulate type metadata +// for devirtualization. // //===----------------------------------------------------------------------===// -#ifndef LLVM_ANALYSIS_BITSETUTILS_H -#define LLVM_ANALYSIS_BITSETUTILS_H +#ifndef LLVM_ANALYSIS_TYPEMETADATAUTILS_H +#define LLVM_ANALYSIS_TYPEMETADATAUTILS_H #include "llvm/ADT/SmallVector.h" #include "llvm/IR/CallSite.h" @@ -28,7 +28,7 @@ struct DevirtCallSite { CallSite CS; }; -/// Given a call to the intrinsic @llvm.bitset.test, find all devirtualizable +/// Given a call to the intrinsic @llvm.type.test, find all devirtualizable /// call sites based on the call and return them in DevirtCalls. void findDevirtualizableCalls(SmallVectorImpl<DevirtCallSite> &DevirtCalls, SmallVectorImpl<CallInst *> &Assumes, diff --git a/llvm/include/llvm/IR/GlobalObject.h b/llvm/include/llvm/IR/GlobalObject.h index 6414ca5b147..04737a045ae 100644 --- a/llvm/include/llvm/IR/GlobalObject.h +++ b/llvm/include/llvm/IR/GlobalObject.h @@ -21,6 +21,7 @@ namespace llvm { class Comdat; class MDNode; +class Metadata; class Module; class GlobalObject : public GlobalValue { @@ -114,8 +115,10 @@ public: /// Erase all metadata attachments with the given kind. void eraseMetadata(unsigned KindID); - /// Copy metadata from Src. - void copyMetadata(const GlobalObject *Src); + /// Copy metadata from Src, adjusting offsets by Offset. + void copyMetadata(const GlobalObject *Src, unsigned Offset); + + void addTypeMetadata(unsigned Offset, Metadata *TypeID); void copyAttributesFrom(const GlobalValue *Src) override; diff --git a/llvm/include/llvm/IR/Intrinsics.td b/llvm/include/llvm/IR/Intrinsics.td index 78a1fb98965..fdda4e2eeb2 100644 --- a/llvm/include/llvm/IR/Intrinsics.td +++ b/llvm/include/llvm/IR/Intrinsics.td @@ -663,9 +663,9 @@ def int_masked_scatter: Intrinsic<[], LLVMVectorSameWidth<0, llvm_i1_ty>], [IntrArgMemOnly]>; -// Intrinsics to support bit sets. -def int_bitset_test : Intrinsic<[llvm_i1_ty], [llvm_ptr_ty, llvm_metadata_ty], - [IntrNoMem]>; +// Test whether a pointer is associated with a type metadata identifier. +def int_type_test : Intrinsic<[llvm_i1_ty], [llvm_ptr_ty, llvm_metadata_ty], + [IntrNoMem]>; def int_load_relative: Intrinsic<[llvm_ptr_ty], [llvm_ptr_ty, llvm_anyint_ty], [IntrReadMem, IntrArgMemOnly]>; diff --git a/llvm/include/llvm/IR/LLVMContext.h b/llvm/include/llvm/IR/LLVMContext.h index c1999184722..6f7a9503745 100644 --- a/llvm/include/llvm/IR/LLVMContext.h +++ b/llvm/include/llvm/IR/LLVMContext.h @@ -68,6 +68,7 @@ public: MD_invariant_group = 16, // "invariant.group" MD_align = 17, // "align" MD_loop = 18, // "llvm.loop" + MD_type = 19, // "type" }; /// Known operand bundle tag IDs, which always have the same value. All diff --git a/llvm/include/llvm/InitializePasses.h b/llvm/include/llvm/InitializePasses.h index 5d34f40c750..b78fdc24e0f 100644 --- a/llvm/include/llvm/InitializePasses.h +++ b/llvm/include/llvm/InitializePasses.h @@ -192,13 +192,13 @@ void initializeLoopVectorizePass(PassRegistry&); void initializeLoopVersioningLICMPass(PassRegistry&); void initializeLoopVersioningPassPass(PassRegistry &); void initializeLowerAtomicLegacyPassPass(PassRegistry &); -void initializeLowerBitSetsPass(PassRegistry&); void initializeLowerEmuTLSPass(PassRegistry&); void initializeLowerExpectIntrinsicPass(PassRegistry&); void initializeLowerGuardIntrinsicPass(PassRegistry&); void initializeLowerIntrinsicsPass(PassRegistry&); void initializeLowerInvokePass(PassRegistry&); void initializeLowerSwitchPass(PassRegistry&); +void initializeLowerTypeTestsPass(PassRegistry&); void initializeMIRPrintingPassPass(PassRegistry&); void initializeMachineBlockFrequencyInfoPass(PassRegistry&); void initializeMachineBlockPlacementPass(PassRegistry&); diff --git a/llvm/include/llvm/Transforms/IPO.h b/llvm/include/llvm/Transforms/IPO.h index ca464ff3925..f6731884870 100644 --- a/llvm/include/llvm/Transforms/IPO.h +++ b/llvm/include/llvm/Transforms/IPO.h @@ -214,14 +214,14 @@ ModulePass *createMetaRenamerPass(); /// manager. ModulePass *createBarrierNoopPass(); -/// \brief This pass lowers bitset metadata and the llvm.bitset.test intrinsic -/// to bitsets. -ModulePass *createLowerBitSetsPass(); +/// \brief This pass lowers type metadata and the llvm.type.test intrinsic to +/// bitsets. +ModulePass *createLowerTypeTestsPass(); /// \brief This pass export CFI checks for use by external modules. ModulePass *createCrossDSOCFIPass(); -/// \brief This pass implements whole-program devirtualization using bitset +/// \brief This pass implements whole-program devirtualization using type /// metadata. ModulePass *createWholeProgramDevirtPass(); diff --git a/llvm/include/llvm/Transforms/IPO/LowerBitSets.h b/llvm/include/llvm/Transforms/IPO/LowerTypeTests.h index 677867f38bd..4da2a06aa94 100644 --- a/llvm/include/llvm/Transforms/IPO/LowerBitSets.h +++ b/llvm/include/llvm/Transforms/IPO/LowerTypeTests.h @@ -1,4 +1,4 @@ -//===- LowerBitSets.h - Bitset lowering pass --------------------*- C++ -*-===// +//===- LowerTypeTests.h - type metadata lowering pass -----------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -7,13 +7,13 @@ // //===----------------------------------------------------------------------===// // -// This file defines parts of the bitset lowering pass implementation that may -// be usefully unit tested. +// This file defines parts of the type test lowering pass implementation that +// may be usefully unit tested. // //===----------------------------------------------------------------------===// -#ifndef LLVM_TRANSFORMS_IPO_LOWERBITSETS_H -#define LLVM_TRANSFORMS_IPO_LOWERBITSETS_H +#ifndef LLVM_TRANSFORMS_IPO_LOWERTYPETESTS_H +#define LLVM_TRANSFORMS_IPO_LOWERTYPETESTS_H #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallVector.h" @@ -31,7 +31,7 @@ class GlobalObject; class Value; class raw_ostream; -namespace lowerbitsets { +namespace lowertypetests { struct BitSetInfo { // The indices of the set bits in the bitset. @@ -199,7 +199,7 @@ struct ByteArrayBuilder { uint64_t &AllocByteOffset, uint8_t &AllocMask); }; -} // end namespace lowerbitsets +} // end namespace lowertypetests } // end namespace llvm -#endif // LLVM_TRANSFORMS_IPO_LOWERBITSETS_H +#endif // LLVM_TRANSFORMS_IPO_LOWERTYPETESTS_H diff --git a/llvm/include/llvm/Transforms/IPO/WholeProgramDevirt.h b/llvm/include/llvm/Transforms/IPO/WholeProgramDevirt.h index bcffb618fdc..2bd20c95702 100644 --- a/llvm/include/llvm/Transforms/IPO/WholeProgramDevirt.h +++ b/llvm/include/llvm/Transforms/IPO/WholeProgramDevirt.h @@ -99,32 +99,33 @@ struct VTableBits { AccumBitVector After; }; -// Information about an entry in a particular bitset. -struct BitSetInfo { +// Information about a member of a particular type identifier. +struct TypeMemberInfo { // The VTableBits for the vtable. VTableBits *Bits; // The offset in bytes from the start of the vtable (i.e. the address point). uint64_t Offset; - bool operator<(const BitSetInfo &other) const { + bool operator<(const TypeMemberInfo &other) const { return Bits < other.Bits || (Bits == other.Bits && Offset < other.Offset); } }; // A virtual call target, i.e. an entry in a particular vtable. struct VirtualCallTarget { - VirtualCallTarget(Function *Fn, const BitSetInfo *BS); + VirtualCallTarget(Function *Fn, const TypeMemberInfo *TM); // For testing only. - VirtualCallTarget(const BitSetInfo *BS, bool IsBigEndian) - : Fn(nullptr), BS(BS), IsBigEndian(IsBigEndian) {} + VirtualCallTarget(const TypeMemberInfo *TM, bool IsBigEndian) + : Fn(nullptr), TM(TM), IsBigEndian(IsBigEndian) {} // The function stored in the vtable. Function *Fn; - // A pointer to the bitset through which the pointer to Fn is accessed. - const BitSetInfo *BS; + // A pointer to the type identifier member through which the pointer to Fn is + // accessed. + const TypeMemberInfo *TM; // When doing virtual constant propagation, this stores the return value for // the function when passed the currently considered argument list. @@ -137,37 +138,37 @@ struct VirtualCallTarget { // the vtable object before the address point (e.g. RTTI, access-to-top, // vtables for other base classes) and is equal to the offset from the start // of the vtable object to the address point. - uint64_t minBeforeBytes() const { return BS->Offset; } + uint64_t minBeforeBytes() const { return TM->Offset; } // The minimum byte offset after the address point. This covers the bytes in // the vtable object after the address point (e.g. the vtable for the current // class and any later base classes) and is equal to the size of the vtable // object minus the offset from the start of the vtable object to the address // point. - uint64_t minAfterBytes() const { return BS->Bits->ObjectSize - BS->Offset; } + uint64_t minAfterBytes() const { return TM->Bits->ObjectSize - TM->Offset; } // The number of bytes allocated (for the vtable plus the byte array) before // the address point. uint64_t allocatedBeforeBytes() const { - return minBeforeBytes() + BS->Bits->Before.Bytes.size(); + return minBeforeBytes() + TM->Bits->Before.Bytes.size(); } // The number of bytes allocated (for the vtable plus the byte array) after // the address point. uint64_t allocatedAfterBytes() const { - return minAfterBytes() + BS->Bits->After.Bytes.size(); + return minAfterBytes() + TM->Bits->After.Bytes.size(); } // Set the bit at position Pos before the address point to RetVal. void setBeforeBit(uint64_t Pos) { assert(Pos >= 8 * minBeforeBytes()); - BS->Bits->Before.setBit(Pos - 8 * minBeforeBytes(), RetVal); + TM->Bits->Before.setBit(Pos - 8 * minBeforeBytes(), RetVal); } // Set the bit at position Pos after the address point to RetVal. void setAfterBit(uint64_t Pos) { assert(Pos >= 8 * minAfterBytes()); - BS->Bits->After.setBit(Pos - 8 * minAfterBytes(), RetVal); + TM->Bits->After.setBit(Pos - 8 * minAfterBytes(), RetVal); } // Set the bytes at position Pos before the address point to RetVal. @@ -176,18 +177,18 @@ struct VirtualCallTarget { void setBeforeBytes(uint64_t Pos, uint8_t Size) { assert(Pos >= 8 * minBeforeBytes()); if (IsBigEndian) - BS->Bits->Before.setLE(Pos - 8 * minBeforeBytes(), RetVal, Size); + TM->Bits->Before.setLE(Pos - 8 * minBeforeBytes(), RetVal, Size); else - BS->Bits->Before.setBE(Pos - 8 * minBeforeBytes(), RetVal, Size); + TM->Bits->Before.setBE(Pos - 8 * minBeforeBytes(), RetVal, Size); } // Set the bytes at position Pos after the address point to RetVal. void setAfterBytes(uint64_t Pos, uint8_t Size) { assert(Pos >= 8 * minAfterBytes()); if (IsBigEndian) - BS->Bits->After.setBE(Pos - 8 * minAfterBytes(), RetVal, Size); + TM->Bits->After.setBE(Pos - 8 * minAfterBytes(), RetVal, Size); else - BS->Bits->After.setLE(Pos - 8 * minAfterBytes(), RetVal, Size); + TM->Bits->After.setLE(Pos - 8 * minAfterBytes(), RetVal, Size); } }; diff --git a/llvm/lib/Analysis/CMakeLists.txt b/llvm/lib/Analysis/CMakeLists.txt index a4233df4fb4..56ab9a0b384 100644 --- a/llvm/lib/Analysis/CMakeLists.txt +++ b/llvm/lib/Analysis/CMakeLists.txt @@ -5,7 +5,6 @@ add_llvm_library(LLVMAnalysis Analysis.cpp AssumptionCache.cpp BasicAliasAnalysis.cpp - BitSetUtils.cpp BlockFrequencyInfo.cpp BlockFrequencyInfoImpl.cpp BranchProbabilityInfo.cpp @@ -71,6 +70,7 @@ add_llvm_library(LLVMAnalysis TargetTransformInfo.cpp Trace.cpp TypeBasedAliasAnalysis.cpp + TypeMetadataUtils.cpp ScopedNoAliasAA.cpp ValueTracking.cpp VectorUtils.cpp diff --git a/llvm/lib/Analysis/BitSetUtils.cpp b/llvm/lib/Analysis/TypeMetadataUtils.cpp index d83dca60cce..750cce33856 100644 --- a/llvm/lib/Analysis/BitSetUtils.cpp +++ b/llvm/lib/Analysis/TypeMetadataUtils.cpp @@ -1,4 +1,4 @@ -//===- BitSetUtils.cpp - Utilities related to pointer bitsets -------------===// +//===- TypeMetadataUtils.cpp - Utilities related to type metadata ---------===// // // The LLVM Compiler Infrastructure // @@ -7,12 +7,12 @@ // //===----------------------------------------------------------------------===// // -// This file contains functions that make it easier to manipulate bitsets for -// devirtualization. +// This file contains functions that make it easier to manipulate type metadata +// for devirtualization. // //===----------------------------------------------------------------------===// -#include "llvm/Analysis/BitSetUtils.h" +#include "llvm/Analysis/TypeMetadataUtils.h" #include "llvm/IR/Intrinsics.h" #include "llvm/IR/Module.h" @@ -60,11 +60,11 @@ findLoadCallsAtConstantOffset(Module *M, void llvm::findDevirtualizableCalls( SmallVectorImpl<DevirtCallSite> &DevirtCalls, SmallVectorImpl<CallInst *> &Assumes, CallInst *CI) { - assert(CI->getCalledFunction()->getIntrinsicID() == Intrinsic::bitset_test); + assert(CI->getCalledFunction()->getIntrinsicID() == Intrinsic::type_test); Module *M = CI->getParent()->getParent()->getParent(); - // Find llvm.assume intrinsics for this llvm.bitset.test call. + // Find llvm.assume intrinsics for this llvm.type.test call. for (const Use &CIU : CI->uses()) { auto AssumeCI = dyn_cast<CallInst>(CIU.getUser()); if (AssumeCI) { diff --git a/llvm/lib/IR/LLVMContext.cpp b/llvm/lib/IR/LLVMContext.cpp index 9f8680cf6c0..c7ba400ced1 100644 --- a/llvm/lib/IR/LLVMContext.cpp +++ b/llvm/lib/IR/LLVMContext.cpp @@ -134,6 +134,10 @@ LLVMContext::LLVMContext() : pImpl(new LLVMContextImpl(*this)) { assert(LoopID == MD_loop && "llvm.loop kind id drifted"); (void)LoopID; + unsigned TypeID = getMDKindID("type"); + assert(TypeID == MD_type && "type kind id drifted"); + (void)TypeID; + auto *DeoptEntry = pImpl->getOrInsertBundleTag("deopt"); assert(DeoptEntry->second == LLVMContext::OB_deopt && "deopt operand bundle id drifted!"); diff --git a/llvm/lib/IR/Metadata.cpp b/llvm/lib/IR/Metadata.cpp index 3b5f87a2b40..965f9737629 100644 --- a/llvm/lib/IR/Metadata.cpp +++ b/llvm/lib/IR/Metadata.cpp @@ -1393,11 +1393,32 @@ MDNode *GlobalObject::getMetadata(StringRef Kind) const { return getMetadata(getContext().getMDKindID(Kind)); } -void GlobalObject::copyMetadata(const GlobalObject *Other) { +void GlobalObject::copyMetadata(const GlobalObject *Other, unsigned Offset) { SmallVector<std::pair<unsigned, MDNode *>, 8> MDs; Other->getAllMetadata(MDs); - for (auto &MD : MDs) + for (auto &MD : MDs) { + // We need to adjust the type metadata offset. + if (Offset != 0 && MD.first == LLVMContext::MD_type) { + auto *OffsetConst = cast<ConstantInt>( + cast<ConstantAsMetadata>(MD.second->getOperand(0))->getValue()); + Metadata *TypeId = MD.second->getOperand(1); + auto *NewOffsetMD = ConstantAsMetadata::get(ConstantInt::get( + OffsetConst->getType(), OffsetConst->getValue() + Offset)); + addMetadata(LLVMContext::MD_type, + *MDNode::get(getContext(), {NewOffsetMD, TypeId})); + continue; + } addMetadata(MD.first, *MD.second); + } +} + +void GlobalObject::addTypeMetadata(unsigned Offset, Metadata *TypeID) { + addMetadata( + LLVMContext::MD_type, + *MDTuple::get(getContext(), + {llvm::ConstantAsMetadata::get(llvm::ConstantInt::get( + Type::getInt64Ty(getContext()), Offset)), + TypeID})); } void Function::setSubprogram(DISubprogram *SP) { diff --git a/llvm/lib/Linker/IRMover.cpp b/llvm/lib/Linker/IRMover.cpp index 2f3813f6184..4935868c00f 100644 --- a/llvm/lib/Linker/IRMover.cpp +++ b/llvm/lib/Linker/IRMover.cpp @@ -641,7 +641,7 @@ GlobalValue *IRLinker::copyGlobalValueProto(const GlobalValue *SGV, if (auto *NewGO = dyn_cast<GlobalObject>(NewGV)) { // Metadata for global variables and function declarations is copied eagerly. if (isa<GlobalVariable>(SGV) || SGV->isDeclaration()) - NewGO->copyMetadata(cast<GlobalObject>(SGV)); + NewGO->copyMetadata(cast<GlobalObject>(SGV), 0); } // Remove these copied constants in case this stays a declaration, since @@ -967,7 +967,7 @@ Error IRLinker::linkFunctionBody(Function &Dst, Function &Src) { Dst.setPersonalityFn(Src.getPersonalityFn()); // Copy over the metadata attachments without remapping. - Dst.copyMetadata(&Src); + Dst.copyMetadata(&Src, 0); // Steal arguments and splice the body of Src into Dst. Dst.stealArgumentListFrom(Src); diff --git a/llvm/lib/Transforms/IPO/CMakeLists.txt b/llvm/lib/Transforms/IPO/CMakeLists.txt index 367b395d7e3..d6782c738cb 100644 --- a/llvm/lib/Transforms/IPO/CMakeLists.txt +++ b/llvm/lib/Transforms/IPO/CMakeLists.txt @@ -19,7 +19,7 @@ add_llvm_library(LLVMipo Inliner.cpp Internalize.cpp LoopExtractor.cpp - LowerBitSets.cpp + LowerTypeTests.cpp MergeFunctions.cpp PartialInlining.cpp PassManagerBuilder.cpp diff --git a/llvm/lib/Transforms/IPO/CrossDSOCFI.cpp b/llvm/lib/Transforms/IPO/CrossDSOCFI.cpp index 4c62cbe2da5..99d58333954 100644 --- a/llvm/lib/Transforms/IPO/CrossDSOCFI.cpp +++ b/llvm/lib/Transforms/IPO/CrossDSOCFI.cpp @@ -36,7 +36,7 @@ using namespace llvm; #define DEBUG_TYPE "cross-dso-cfi" -STATISTIC(TypeIds, "Number of unique type identifiers"); +STATISTIC(NumTypeIds, "Number of unique type identifiers"); namespace { @@ -49,7 +49,7 @@ struct CrossDSOCFI : public ModulePass { Module *M; MDNode *VeryLikelyWeights; - ConstantInt *extractBitSetTypeId(MDNode *MD); + ConstantInt *extractNumericTypeId(MDNode *MD); void buildCFICheck(); bool doInitialization(Module &M) override; @@ -73,10 +73,10 @@ bool CrossDSOCFI::doInitialization(Module &Mod) { return false; } -/// extractBitSetTypeId - Extracts TypeId from a hash-based bitset MDNode. -ConstantInt *CrossDSOCFI::extractBitSetTypeId(MDNode *MD) { +/// Extracts a numeric type identifier from an MDNode containing type metadata. +ConstantInt *CrossDSOCFI::extractNumericTypeId(MDNode *MD) { // This check excludes vtables for classes inside anonymous namespaces. - auto TM = dyn_cast<ValueAsMetadata>(MD->getOperand(0)); + auto TM = dyn_cast<ValueAsMetadata>(MD->getOperand(1)); if (!TM) return nullptr; auto C = dyn_cast_or_null<ConstantInt>(TM->getValue()); @@ -84,29 +84,27 @@ ConstantInt *CrossDSOCFI::extractBitSetTypeId(MDNode *MD) { // We are looking for i64 constants. if (C->getBitWidth() != 64) return nullptr; - // Sanity check. - auto FM = dyn_cast_or_null<ValueAsMetadata>(MD->getOperand(1)); - // Can be null if a function was removed by an optimization. - if (FM) { - auto F = dyn_cast<Function>(FM->getValue()); - // But can never be a function declaration. - assert(!F || !F->isDeclaration()); - (void)F; // Suppress unused variable warning in the no-asserts build. - } return C; } /// buildCFICheck - emits __cfi_check for the current module. void CrossDSOCFI::buildCFICheck() { // FIXME: verify that __cfi_check ends up near the end of the code section, - // but before the jump slots created in LowerBitSets. - llvm::DenseSet<uint64_t> BitSetIds; - NamedMDNode *BitSetNM = M->getNamedMetadata("llvm.bitsets"); - - if (BitSetNM) - for (unsigned I = 0, E = BitSetNM->getNumOperands(); I != E; ++I) - if (ConstantInt *TypeId = extractBitSetTypeId(BitSetNM->getOperand(I))) - BitSetIds.insert(TypeId->getZExtValue()); + // but before the jump slots created in LowerTypeTests. + llvm::DenseSet<uint64_t> TypeIds; + SmallVector<MDNode *, 2> Types; + for (GlobalObject &GO : M->global_objects()) { + Types.clear(); + GO.getMetadata(LLVMContext::MD_type, Types); + for (MDNode *Type : Types) { + // Sanity check. GO must not be a function declaration. + auto F = dyn_cast<Function>(&GO); + assert(!F || !F->isDeclaration()); + + if (ConstantInt *TypeId = extractNumericTypeId(Type)) + TypeIds.insert(TypeId->getZExtValue()); + } + } LLVMContext &Ctx = M->getContext(); Constant *C = M->getOrInsertFunction( @@ -138,13 +136,12 @@ void CrossDSOCFI::buildCFICheck() { IRBExit.CreateRetVoid(); IRBuilder<> IRB(BB); - SwitchInst *SI = IRB.CreateSwitch(&CallSiteTypeId, TrapBB, BitSetIds.size()); - for (uint64_t TypeId : BitSetIds) { + SwitchInst *SI = IRB.CreateSwitch(&CallSiteTypeId, TrapBB, TypeIds.size()); + for (uint64_t TypeId : TypeIds) { ConstantInt *CaseTypeId = ConstantInt::get(Type::getInt64Ty(Ctx), TypeId); BasicBlock *TestBB = BasicBlock::Create(Ctx, "test", F); IRBuilder<> IRBTest(TestBB); - Function *BitsetTestFn = - Intrinsic::getDeclaration(M, Intrinsic::bitset_test); + Function *BitsetTestFn = Intrinsic::getDeclaration(M, Intrinsic::type_test); Value *Test = IRBTest.CreateCall( BitsetTestFn, {&Addr, MetadataAsValue::get( @@ -153,7 +150,7 @@ void CrossDSOCFI::buildCFICheck() { BI->setMetadata(LLVMContext::MD_prof, VeryLikelyWeights); SI->addCase(CaseTypeId, TestBB); - ++TypeIds; + ++NumTypeIds; } } diff --git a/llvm/lib/Transforms/IPO/IPO.cpp b/llvm/lib/Transforms/IPO/IPO.cpp index c80f08787bf..35520e4a27e 100644 --- a/llvm/lib/Transforms/IPO/IPO.cpp +++ b/llvm/lib/Transforms/IPO/IPO.cpp @@ -39,7 +39,7 @@ void llvm::initializeIPO(PassRegistry &Registry) { initializeLoopExtractorPass(Registry); initializeBlockExtractorPassPass(Registry); initializeSingleLoopExtractorPass(Registry); - initializeLowerBitSetsPass(Registry); + initializeLowerTypeTestsPass(Registry); initializeMergeFunctionsPass(Registry); initializePartialInlinerPass(Registry); initializePostOrderFunctionAttrsLegacyPassPass(Registry); diff --git a/llvm/lib/Transforms/IPO/LowerBitSets.cpp b/llvm/lib/Transforms/IPO/LowerTypeTests.cpp index 78981fdedad..06e66468c83 100644 --- a/llvm/lib/Transforms/IPO/LowerBitSets.cpp +++ b/llvm/lib/Transforms/IPO/LowerTypeTests.cpp @@ -1,4 +1,4 @@ -//===-- LowerBitSets.cpp - Bitset lowering pass ---------------------------===// +//===-- LowerTypeTests.cpp - type metadata lowering pass ------------------===// // // The LLVM Compiler Infrastructure // @@ -7,12 +7,12 @@ // //===----------------------------------------------------------------------===// // -// This pass lowers bitset metadata and calls to the llvm.bitset.test intrinsic. -// See http://llvm.org/docs/LangRef.html#bitsets for more information. +// This pass lowers type metadata and calls to the llvm.type.test intrinsic. +// See http://llvm.org/docs/TypeMetadata.html for more information. // //===----------------------------------------------------------------------===// -#include "llvm/Transforms/IPO/LowerBitSets.h" +#include "llvm/Transforms/IPO/LowerTypeTests.h" #include "llvm/Transforms/IPO.h" #include "llvm/ADT/EquivalenceClasses.h" #include "llvm/ADT/Statistic.h" @@ -33,18 +33,18 @@ #include "llvm/Transforms/Utils/BasicBlockUtils.h" using namespace llvm; -using namespace lowerbitsets; +using namespace lowertypetests; -#define DEBUG_TYPE "lowerbitsets" +#define DEBUG_TYPE "lowertypetests" STATISTIC(ByteArraySizeBits, "Byte array size in bits"); STATISTIC(ByteArraySizeBytes, "Byte array size in bytes"); STATISTIC(NumByteArraysCreated, "Number of byte arrays created"); -STATISTIC(NumBitSetCallsLowered, "Number of bitset calls lowered"); -STATISTIC(NumBitSetDisjointSets, "Number of disjoint sets of bitsets"); +STATISTIC(NumTypeTestCallsLowered, "Number of type test calls lowered"); +STATISTIC(NumTypeIdDisjointSets, "Number of disjoint sets of type identifiers"); static cl::opt<bool> AvoidReuse( - "lowerbitsets-avoid-reuse", + "lowertypetests-avoid-reuse", cl::desc("Try to avoid reuse of byte array addresses using aliases"), cl::Hidden, cl::init(true)); @@ -204,10 +204,10 @@ struct ByteArrayInfo { Constant *Mask; }; -struct LowerBitSets : public ModulePass { +struct LowerTypeTests : public ModulePass { static char ID; - LowerBitSets() : ModulePass(ID) { - initializeLowerBitSetsPass(*PassRegistry::getPassRegistry()); + LowerTypeTests() : ModulePass(ID) { + initializeLowerTypeTestsPass(*PassRegistry::getPassRegistry()); } Module *M; @@ -222,41 +222,37 @@ struct LowerBitSets : public ModulePass { IntegerType *Int64Ty; IntegerType *IntPtrTy; - // The llvm.bitsets named metadata. - NamedMDNode *BitSetNM; - - // Mapping from bitset identifiers to the call sites that test them. - DenseMap<Metadata *, std::vector<CallInst *>> BitSetTestCallSites; + // Mapping from type identifiers to the call sites that test them. + DenseMap<Metadata *, std::vector<CallInst *>> TypeTestCallSites; std::vector<ByteArrayInfo> ByteArrayInfos; BitSetInfo - buildBitSet(Metadata *BitSet, + buildBitSet(Metadata *TypeId, const DenseMap<GlobalObject *, uint64_t> &GlobalLayout); ByteArrayInfo *createByteArray(BitSetInfo &BSI); void allocateByteArrays(); Value *createBitSetTest(IRBuilder<> &B, BitSetInfo &BSI, ByteArrayInfo *&BAI, Value *BitOffset); - void lowerBitSetCalls(ArrayRef<Metadata *> BitSets, - Constant *CombinedGlobalAddr, - const DenseMap<GlobalObject *, uint64_t> &GlobalLayout); + void + lowerTypeTestCalls(ArrayRef<Metadata *> TypeIds, Constant *CombinedGlobalAddr, + const DenseMap<GlobalObject *, uint64_t> &GlobalLayout); Value * lowerBitSetCall(CallInst *CI, BitSetInfo &BSI, ByteArrayInfo *&BAI, Constant *CombinedGlobal, const DenseMap<GlobalObject *, uint64_t> &GlobalLayout); - void buildBitSetsFromGlobalVariables(ArrayRef<Metadata *> BitSets, + void buildBitSetsFromGlobalVariables(ArrayRef<Metadata *> TypeIds, ArrayRef<GlobalVariable *> Globals); unsigned getJumpTableEntrySize(); Type *getJumpTableEntryType(); Constant *createJumpTableEntry(GlobalObject *Src, Function *Dest, unsigned Distance); - void verifyBitSetMDNode(MDNode *Op); - void buildBitSetsFromFunctions(ArrayRef<Metadata *> BitSets, + void verifyTypeMDNode(GlobalObject *GO, MDNode *Type); + void buildBitSetsFromFunctions(ArrayRef<Metadata *> TypeIds, ArrayRef<Function *> Functions); - void buildBitSetsFromDisjointSet(ArrayRef<Metadata *> BitSets, + void buildBitSetsFromDisjointSet(ArrayRef<Metadata *> TypeIds, ArrayRef<GlobalObject *> Globals); - bool buildBitSets(); - bool eraseBitSetMetadata(); + bool lower(); bool doInitialization(Module &M) override; bool runOnModule(Module &M) override; @@ -264,15 +260,13 @@ struct LowerBitSets : public ModulePass { } // anonymous namespace -INITIALIZE_PASS_BEGIN(LowerBitSets, "lowerbitsets", - "Lower bitset metadata", false, false) -INITIALIZE_PASS_END(LowerBitSets, "lowerbitsets", - "Lower bitset metadata", false, false) -char LowerBitSets::ID = 0; +INITIALIZE_PASS(LowerTypeTests, "lowertypetests", "Lower type metadata", false, + false) +char LowerTypeTests::ID = 0; -ModulePass *llvm::createLowerBitSetsPass() { return new LowerBitSets; } +ModulePass *llvm::createLowerTypeTestsPass() { return new LowerTypeTests; } -bool LowerBitSets::doInitialization(Module &Mod) { +bool LowerTypeTests::doInitialization(Module &Mod) { M = &Mod; const DataLayout &DL = Mod.getDataLayout(); @@ -288,39 +282,31 @@ bool LowerBitSets::doInitialization(Module &Mod) { Int64Ty = Type::getInt64Ty(M->getContext()); IntPtrTy = DL.getIntPtrType(M->getContext(), 0); - BitSetNM = M->getNamedMetadata("llvm.bitsets"); - - BitSetTestCallSites.clear(); + TypeTestCallSites.clear(); return false; } -/// Build a bit set for BitSet using the object layouts in +/// Build a bit set for TypeId using the object layouts in /// GlobalLayout. -BitSetInfo LowerBitSets::buildBitSet( - Metadata *BitSet, +BitSetInfo LowerTypeTests::buildBitSet( + Metadata *TypeId, const DenseMap<GlobalObject *, uint64_t> &GlobalLayout) { BitSetBuilder BSB; - // Compute the byte offset of each element of this bitset. - if (BitSetNM) { - for (MDNode *Op : BitSetNM->operands()) { - if (Op->getOperand(0) != BitSet || !Op->getOperand(1)) - continue; - Constant *OpConst = - cast<ConstantAsMetadata>(Op->getOperand(1))->getValue(); - if (auto GA = dyn_cast<GlobalAlias>(OpConst)) - OpConst = GA->getAliasee(); - auto OpGlobal = dyn_cast<GlobalObject>(OpConst); - if (!OpGlobal) + // Compute the byte offset of each address associated with this type + // identifier. + SmallVector<MDNode *, 2> Types; + for (auto &GlobalAndOffset : GlobalLayout) { + Types.clear(); + GlobalAndOffset.first->getMetadata(LLVMContext::MD_type, Types); + for (MDNode *Type : Types) { + if (Type->getOperand(1) != TypeId) continue; uint64_t Offset = - cast<ConstantInt>(cast<ConstantAsMetadata>(Op->getOperand(2)) + cast<ConstantInt>(cast<ConstantAsMetadata>(Type->getOperand(0)) ->getValue())->getZExtValue(); - - Offset += GlobalLayout.find(OpGlobal)->second; - - BSB.addOffset(Offset); + BSB.addOffset(GlobalAndOffset.second + Offset); } } @@ -342,7 +328,7 @@ static Value *createMaskedBitTest(IRBuilder<> &B, Value *Bits, return B.CreateICmpNE(MaskedBits, ConstantInt::get(BitsType, 0)); } -ByteArrayInfo *LowerBitSets::createByteArray(BitSetInfo &BSI) { +ByteArrayInfo *LowerTypeTests::createByteArray(BitSetInfo &BSI) { // Create globals to stand in for byte arrays and masks. These never actually // get initialized, we RAUW and erase them later in allocateByteArrays() once // we know the offset and mask to use. @@ -361,7 +347,7 @@ ByteArrayInfo *LowerBitSets::createByteArray(BitSetInfo &BSI) { return BAI; } -void LowerBitSets::allocateByteArrays() { +void LowerTypeTests::allocateByteArrays() { std::stable_sort(ByteArrayInfos.begin(), ByteArrayInfos.end(), [](const ByteArrayInfo &BAI1, const ByteArrayInfo &BAI2) { return BAI1.BitSize > BAI2.BitSize; @@ -414,8 +400,8 @@ void LowerBitSets::allocateByteArrays() { /// Build a test that bit BitOffset is set in BSI, where /// BitSetGlobal is a global containing the bits in BSI. -Value *LowerBitSets::createBitSetTest(IRBuilder<> &B, BitSetInfo &BSI, - ByteArrayInfo *&BAI, Value *BitOffset) { +Value *LowerTypeTests::createBitSetTest(IRBuilder<> &B, BitSetInfo &BSI, + ByteArrayInfo *&BAI, Value *BitOffset) { if (BSI.BitSize <= 64) { // If the bit set is sufficiently small, we can avoid a load by bit testing // a constant. @@ -455,9 +441,9 @@ Value *LowerBitSets::createBitSetTest(IRBuilder<> &B, BitSetInfo &BSI, } } -/// Lower a llvm.bitset.test call to its implementation. Returns the value to +/// Lower a llvm.type.test call to its implementation. Returns the value to /// replace the call with. -Value *LowerBitSets::lowerBitSetCall( +Value *LowerTypeTests::lowerBitSetCall( CallInst *CI, BitSetInfo &BSI, ByteArrayInfo *&BAI, Constant *CombinedGlobalIntAddr, const DenseMap<GlobalObject *, uint64_t> &GlobalLayout) { @@ -525,10 +511,10 @@ Value *LowerBitSets::lowerBitSetCall( return P; } -/// Given a disjoint set of bitsets and globals, layout the globals, build the -/// bit sets and lower the llvm.bitset.test calls. -void LowerBitSets::buildBitSetsFromGlobalVariables( - ArrayRef<Metadata *> BitSets, ArrayRef<GlobalVariable *> Globals) { +/// Given a disjoint set of type identifiers and globals, lay out the globals, +/// build the bit sets and lower the llvm.type.test calls. +void LowerTypeTests::buildBitSetsFromGlobalVariables( + ArrayRef<Metadata *> TypeIds, ArrayRef<GlobalVariable *> Globals) { // Build a new global with the combined contents of the referenced globals. // This global is a struct whose even-indexed elements contain the original // contents of the referenced globals and whose odd-indexed elements contain @@ -566,7 +552,7 @@ void LowerBitSets::buildBitSetsFromGlobalVariables( // Multiply by 2 to account for padding elements. GlobalLayout[Globals[I]] = CombinedGlobalLayout->getElementOffset(I * 2); - lowerBitSetCalls(BitSets, CombinedGlobal, GlobalLayout); + lowerTypeTestCalls(TypeIds, CombinedGlobal, GlobalLayout); // Build aliases pointing to offsets into the combined global for each // global from which we built the combined global, and replace references @@ -592,19 +578,19 @@ void LowerBitSets::buildBitSetsFromGlobalVariables( } } -void LowerBitSets::lowerBitSetCalls( - ArrayRef<Metadata *> BitSets, Constant *CombinedGlobalAddr, +void LowerTypeTests::lowerTypeTestCalls( + ArrayRef<Metadata *> TypeIds, Constant *CombinedGlobalAddr, const DenseMap<GlobalObject *, uint64_t> &GlobalLayout) { Constant *CombinedGlobalIntAddr = ConstantExpr::getPtrToInt(CombinedGlobalAddr, IntPtrTy); - // For each bitset in this disjoint set... - for (Metadata *BS : BitSets) { + // For each type identifier in this disjoint set... + for (Metadata *TypeId : TypeIds) { // Build the bitset. - BitSetInfo BSI = buildBitSet(BS, GlobalLayout); + BitSetInfo BSI = buildBitSet(TypeId, GlobalLayout); DEBUG({ - if (auto BSS = dyn_cast<MDString>(BS)) - dbgs() << BSS->getString() << ": "; + if (auto MDS = dyn_cast<MDString>(TypeId)) + dbgs() << MDS->getString() << ": "; else dbgs() << "<unnamed>: "; BSI.print(dbgs()); @@ -612,9 +598,9 @@ void LowerBitSets::lowerBitSetCalls( ByteArrayInfo *BAI = nullptr; - // Lower each call to llvm.bitset.test for this bitset. - for (CallInst *CI : BitSetTestCallSites[BS]) { - ++NumBitSetCallsLowered; + // Lower each call to llvm.type.test for this type identifier. + for (CallInst *CI : TypeTestCallSites[TypeId]) { + ++NumTypeTestCallsLowered; Value *Lowered = lowerBitSetCall(CI, BSI, BAI, CombinedGlobalIntAddr, GlobalLayout); CI->replaceAllUsesWith(Lowered); @@ -623,40 +609,32 @@ void LowerBitSets::lowerBitSetCalls( } } -void LowerBitSets::verifyBitSetMDNode(MDNode *Op) { - if (Op->getNumOperands() != 3) +void LowerTypeTests::verifyTypeMDNode(GlobalObject *GO, MDNode *Type) { + if (Type->getNumOperands() != 2) report_fatal_error( - "All operands of llvm.bitsets metadata must have 3 elements"); - if (!Op->getOperand(1)) - return; + "All operands of type metadata must have 2 elements"); - auto OpConstMD = dyn_cast<ConstantAsMetadata>(Op->getOperand(1)); - if (!OpConstMD) - report_fatal_error("Bit set element must be a constant"); - auto OpGlobal = dyn_cast<GlobalObject>(OpConstMD->getValue()); - if (!OpGlobal) - return; - - if (OpGlobal->isThreadLocal()) + if (GO->isThreadLocal()) report_fatal_error("Bit set element may not be thread-local"); - if (isa<GlobalVariable>(OpGlobal) && OpGlobal->hasSection()) + if (isa<GlobalVariable>(GO) && GO->hasSection()) report_fatal_error( - "Bit set global var element may not have an explicit section"); + "A member of a type identifier may not have an explicit section"); - if (isa<GlobalVariable>(OpGlobal) && OpGlobal->isDeclarationForLinker()) - report_fatal_error("Bit set global var element must be a definition"); + if (isa<GlobalVariable>(GO) && GO->isDeclarationForLinker()) + report_fatal_error( + "A global var member of a type identifier must be a definition"); - auto OffsetConstMD = dyn_cast<ConstantAsMetadata>(Op->getOperand(2)); + auto OffsetConstMD = dyn_cast<ConstantAsMetadata>(Type->getOperand(0)); if (!OffsetConstMD) - report_fatal_error("Bit set element offset must be a constant"); + report_fatal_error("Type offset must be a constant"); auto OffsetInt = dyn_cast<ConstantInt>(OffsetConstMD->getValue()); if (!OffsetInt) - report_fatal_error("Bit set element offset must be an integer constant"); + report_fatal_error("Type offset must be an integer constant"); } static const unsigned kX86JumpTableEntrySize = 8; -unsigned LowerBitSets::getJumpTableEntrySize() { +unsigned LowerTypeTests::getJumpTableEntrySize() { if (Arch != Triple::x86 && Arch != Triple::x86_64) report_fatal_error("Unsupported architecture for jump tables"); @@ -667,8 +645,9 @@ unsigned LowerBitSets::getJumpTableEntrySize() { // consists of an instruction sequence containing a relative branch to Dest. The // constant will be laid out at address Src+(Len*Distance) where Len is the // target-specific jump table entry size. -Constant *LowerBitSets::createJumpTableEntry(GlobalObject *Src, Function *Dest, - unsigned Distance) { +Constant *LowerTypeTests::createJumpTableEntry(GlobalObject *Src, + Function *Dest, + unsigned Distance) { if (Arch != Triple::x86 && Arch != Triple::x86_64) report_fatal_error("Unsupported architecture for jump tables"); @@ -695,7 +674,7 @@ Constant *LowerBitSets::createJumpTableEntry(GlobalObject *Src, Function *Dest, return ConstantStruct::getAnon(Fields, /*Packed=*/true); } -Type *LowerBitSets::getJumpTableEntryType() { +Type *LowerTypeTests::getJumpTableEntryType() { if (Arch != Triple::x86 && Arch != Triple::x86_64) report_fatal_error("Unsupported architecture for jump tables"); @@ -704,10 +683,10 @@ Type *LowerBitSets::getJumpTableEntryType() { /*Packed=*/true); } -/// Given a disjoint set of bitsets and functions, build a jump table for the -/// functions, build the bit sets and lower the llvm.bitset.test calls. -void LowerBitSets::buildBitSetsFromFunctions(ArrayRef<Metadata *> BitSets, - ArrayRef<Function *> Functions) { +/// Given a disjoint set of type identifiers and functions, build a jump table +/// for the functions, build the bit sets and lower the llvm.type.test calls. +void LowerTypeTests::buildBitSetsFromFunctions(ArrayRef<Metadata *> TypeIds, + ArrayRef<Function *> Functions) { // Unlike the global bitset builder, the function bitset builder cannot // re-arrange functions in a particular order and base its calculations on the // layout of the functions' entry points, as we have no idea how large a @@ -721,8 +700,7 @@ void LowerBitSets::buildBitSetsFromFunctions(ArrayRef<Metadata *> BitSets, // 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 - // addresses: + // of the same type, and a function foo that returns their addresses: // // f: // mov 0, %eax @@ -805,7 +783,7 @@ void LowerBitSets::buildBitSetsFromFunctions(ArrayRef<Metadata *> BitSets, JumpTable->setSection(ObjectFormat == Triple::MachO ? "__TEXT,__text,regular,pure_instructions" : ".text"); - lowerBitSetCalls(BitSets, JumpTable, GlobalLayout); + lowerTypeTestCalls(TypeIds, JumpTable, GlobalLayout); // Build aliases pointing to offsets into the jump table, and replace // references to the original functions with references to the aliases. @@ -840,39 +818,32 @@ void LowerBitSets::buildBitSetsFromFunctions(ArrayRef<Metadata *> BitSets, ConstantArray::get(JumpTableType, JumpTableEntries)); } -void LowerBitSets::buildBitSetsFromDisjointSet( - ArrayRef<Metadata *> BitSets, ArrayRef<GlobalObject *> Globals) { - llvm::DenseMap<Metadata *, uint64_t> BitSetIndices; - llvm::DenseMap<GlobalObject *, uint64_t> GlobalIndices; - for (unsigned I = 0; I != BitSets.size(); ++I) - BitSetIndices[BitSets[I]] = I; - for (unsigned I = 0; I != Globals.size(); ++I) - GlobalIndices[Globals[I]] = I; - - // For each bitset, build a set of indices that refer to globals referenced by - // the bitset. - std::vector<std::set<uint64_t>> BitSetMembers(BitSets.size()); - if (BitSetNM) { - for (MDNode *Op : BitSetNM->operands()) { - // Op = { bitset name, global, offset } - if (!Op->getOperand(1)) - continue; - auto I = BitSetIndices.find(Op->getOperand(0)); - if (I == BitSetIndices.end()) - continue; - - auto OpGlobal = dyn_cast<GlobalObject>( - cast<ConstantAsMetadata>(Op->getOperand(1))->getValue()); - if (!OpGlobal) - continue; - BitSetMembers[I->second].insert(GlobalIndices[OpGlobal]); +void LowerTypeTests::buildBitSetsFromDisjointSet( + ArrayRef<Metadata *> TypeIds, ArrayRef<GlobalObject *> Globals) { + llvm::DenseMap<Metadata *, uint64_t> TypeIdIndices; + for (unsigned I = 0; I != TypeIds.size(); ++I) + TypeIdIndices[TypeIds[I]] = I; + + // For each type identifier, build a set of indices that refer to members of + // the type identifier. + std::vector<std::set<uint64_t>> TypeMembers(TypeIds.size()); + SmallVector<MDNode *, 2> Types; + unsigned GlobalIndex = 0; + for (GlobalObject *GO : Globals) { + Types.clear(); + GO->getMetadata(LLVMContext::MD_type, Types); + for (MDNode *Type : Types) { + // Type = { offset, type identifier } + unsigned TypeIdIndex = TypeIdIndices[Type->getOperand(1)]; + TypeMembers[TypeIdIndex].insert(GlobalIndex); } + GlobalIndex++; } // Order the sets of indices by size. The GlobalLayoutBuilder works best // when given small index sets first. std::stable_sort( - BitSetMembers.begin(), BitSetMembers.end(), + TypeMembers.begin(), TypeMembers.end(), [](const std::set<uint64_t> &O1, const std::set<uint64_t> &O2) { return O1.size() < O2.size(); }); @@ -881,7 +852,7 @@ void LowerBitSets::buildBitSetsFromDisjointSet( // fragments. The GlobalLayoutBuilder tries to lay out members of fragments as // close together as possible. GlobalLayoutBuilder GLB(Globals.size()); - for (auto &&MemSet : BitSetMembers) + for (auto &&MemSet : TypeMembers) GLB.addFragment(MemSet); // Build the bitsets from this disjoint set. @@ -893,13 +864,13 @@ void LowerBitSets::buildBitSetsFromDisjointSet( for (auto &&Offset : F) { auto GV = dyn_cast<GlobalVariable>(Globals[Offset]); if (!GV) - report_fatal_error( - "Bit set may not contain both global variables and functions"); + report_fatal_error("Type identifier may not contain both global " + "variables and functions"); *OGI++ = GV; } } - buildBitSetsFromGlobalVariables(BitSets, OrderedGVs); + buildBitSetsFromGlobalVariables(TypeIds, OrderedGVs); } else { // Build a vector of functions with the computed layout. std::vector<Function *> OrderedFns(Globals.size()); @@ -908,102 +879,97 @@ void LowerBitSets::buildBitSetsFromDisjointSet( for (auto &&Offset : F) { auto Fn = dyn_cast<Function>(Globals[Offset]); if (!Fn) - report_fatal_error( - "Bit set may not contain both global variables and functions"); + report_fatal_error("Type identifier may not contain both global " + "variables and functions"); *OFI++ = Fn; } } - buildBitSetsFromFunctions(BitSets, OrderedFns); + buildBitSetsFromFunctions(TypeIds, OrderedFns); } } -/// Lower all bit sets in this module. -bool LowerBitSets::buildBitSets() { - Function *BitSetTestFunc = - M->getFunction(Intrinsic::getName(Intrinsic::bitset_test)); - if (!BitSetTestFunc || BitSetTestFunc->use_empty()) +/// Lower all type tests in this module. +bool LowerTypeTests::lower() { + Function *TypeTestFunc = + M->getFunction(Intrinsic::getName(Intrinsic::type_test)); + if (!TypeTestFunc || TypeTestFunc->use_empty()) return false; - // Equivalence class set containing bitsets and the globals they reference. - // This is used to partition the set of bitsets in the module into disjoint - // sets. + // Equivalence class set containing type identifiers and the globals that + // reference them. This is used to partition the set of type identifiers in + // the module into disjoint sets. typedef EquivalenceClasses<PointerUnion<GlobalObject *, Metadata *>> GlobalClassesTy; GlobalClassesTy GlobalClasses; - // Verify the bitset metadata and build a mapping from bitset identifiers to - // their last observed index in BitSetNM. This will used later to - // deterministically order the list of bitset identifiers. - llvm::DenseMap<Metadata *, unsigned> BitSetIdIndices; - if (BitSetNM) { - for (unsigned I = 0, E = BitSetNM->getNumOperands(); I != E; ++I) { - MDNode *Op = BitSetNM->getOperand(I); - verifyBitSetMDNode(Op); - BitSetIdIndices[Op->getOperand(0)] = I; + // Verify the type metadata and build a mapping from type identifiers to their + // last observed index in the list of globals. This will be used later to + // deterministically order the list of type identifiers. + llvm::DenseMap<Metadata *, unsigned> TypeIdIndices; + unsigned I = 0; + SmallVector<MDNode *, 2> Types; + for (GlobalObject &GO : M->global_objects()) { + Types.clear(); + GO.getMetadata(LLVMContext::MD_type, Types); + for (MDNode *Type : Types) { + verifyTypeMDNode(&GO, Type); + TypeIdIndices[cast<MDNode>(Type)->getOperand(1)] = ++I; } } - for (const Use &U : BitSetTestFunc->uses()) { + for (const Use &U : TypeTestFunc->uses()) { auto CI = cast<CallInst>(U.getUser()); auto BitSetMDVal = dyn_cast<MetadataAsValue>(CI->getArgOperand(1)); if (!BitSetMDVal) report_fatal_error( - "Second argument of llvm.bitset.test must be metadata"); + "Second argument of llvm.type.test must be metadata"); auto BitSet = BitSetMDVal->getMetadata(); - // Add the call site to the list of call sites for this bit set. We also use - // BitSetTestCallSites to keep track of whether we have seen this bit set - // before. If we have, we don't need to re-add the referenced globals to the - // equivalence class. - std::pair<DenseMap<Metadata *, std::vector<CallInst *>>::iterator, - bool> Ins = - BitSetTestCallSites.insert( + // Add the call site to the list of call sites for this type identifier. We + // also use TypeTestCallSites to keep track of whether we have seen this + // type identifier before. If we have, we don't need to re-add the + // referenced globals to the equivalence class. + std::pair<DenseMap<Metadata *, std::vector<CallInst *>>::iterator, bool> + Ins = TypeTestCallSites.insert( std::make_pair(BitSet, std::vector<CallInst *>())); Ins.first->second.push_back(CI); if (!Ins.second) continue; - // Add the bitset to the equivalence class. + // Add the type identifier to the equivalence class. GlobalClassesTy::iterator GCI = GlobalClasses.insert(BitSet); GlobalClassesTy::member_iterator CurSet = GlobalClasses.findLeader(GCI); - if (!BitSetNM) - continue; - - // Add the referenced globals to the bitset's equivalence class. - for (MDNode *Op : BitSetNM->operands()) { - if (Op->getOperand(0) != BitSet || !Op->getOperand(1)) - continue; - - auto OpGlobal = dyn_cast<GlobalObject>( - cast<ConstantAsMetadata>(Op->getOperand(1))->getValue()); - if (!OpGlobal) - continue; - - CurSet = GlobalClasses.unionSets( - CurSet, GlobalClasses.findLeader(GlobalClasses.insert(OpGlobal))); + // Add the referenced globals to the type identifier's equivalence class. + for (GlobalObject &GO : M->global_objects()) { + Types.clear(); + GO.getMetadata(LLVMContext::MD_type, Types); + for (MDNode *Type : Types) + if (Type->getOperand(1) == BitSet) + CurSet = GlobalClasses.unionSets( + CurSet, GlobalClasses.findLeader(GlobalClasses.insert(&GO))); } } if (GlobalClasses.empty()) return false; - // Build a list of disjoint sets ordered by their maximum BitSetNM index - // for determinism. + // Build a list of disjoint sets ordered by their maximum global index for + // determinism. std::vector<std::pair<GlobalClassesTy::iterator, unsigned>> Sets; for (GlobalClassesTy::iterator I = GlobalClasses.begin(), E = GlobalClasses.end(); I != E; ++I) { if (!I->isLeader()) continue; - ++NumBitSetDisjointSets; + ++NumTypeIdDisjointSets; unsigned MaxIndex = 0; for (GlobalClassesTy::member_iterator MI = GlobalClasses.member_begin(I); MI != GlobalClasses.member_end(); ++MI) { if ((*MI).is<Metadata *>()) - MaxIndex = std::max(MaxIndex, BitSetIdIndices[MI->get<Metadata *>()]); + MaxIndex = std::max(MaxIndex, TypeIdIndices[MI->get<Metadata *>()]); } Sets.emplace_back(I, MaxIndex); } @@ -1015,26 +981,26 @@ bool LowerBitSets::buildBitSets() { // For each disjoint set we found... for (const auto &S : Sets) { - // Build the list of bitsets in this disjoint set. - std::vector<Metadata *> BitSets; + // Build the list of type identifiers in this disjoint set. + std::vector<Metadata *> TypeIds; std::vector<GlobalObject *> Globals; for (GlobalClassesTy::member_iterator MI = GlobalClasses.member_begin(S.first); MI != GlobalClasses.member_end(); ++MI) { if ((*MI).is<Metadata *>()) - BitSets.push_back(MI->get<Metadata *>()); + TypeIds.push_back(MI->get<Metadata *>()); else Globals.push_back(MI->get<GlobalObject *>()); } - // Order bitsets by BitSetNM index for determinism. This ordering is stable - // as there is a one-to-one mapping between metadata and indices. - std::sort(BitSets.begin(), BitSets.end(), [&](Metadata *M1, Metadata *M2) { - return BitSetIdIndices[M1] < BitSetIdIndices[M2]; + // Order type identifiers by global index for determinism. This ordering is + // stable as there is a one-to-one mapping between metadata and indices. + std::sort(TypeIds.begin(), TypeIds.end(), [&](Metadata *M1, Metadata *M2) { + return TypeIdIndices[M1] < TypeIdIndices[M2]; }); - // Lower the bitsets in this disjoint set. - buildBitSetsFromDisjointSet(BitSets, Globals); + // Build bitsets for this disjoint set. + buildBitSetsFromDisjointSet(TypeIds, Globals); } allocateByteArrays(); @@ -1042,19 +1008,9 @@ bool LowerBitSets::buildBitSets() { return true; } -bool LowerBitSets::eraseBitSetMetadata() { - if (!BitSetNM) - return false; - - M->eraseNamedMetadata(BitSetNM); - return true; -} - -bool LowerBitSets::runOnModule(Module &M) { +bool LowerTypeTests::runOnModule(Module &M) { if (skipModule(M)) return false; - bool Changed = buildBitSets(); - Changed |= eraseBitSetMetadata(); - return Changed; + return lower(); } diff --git a/llvm/lib/Transforms/IPO/PassManagerBuilder.cpp b/llvm/lib/Transforms/IPO/PassManagerBuilder.cpp index 094dda8cc1f..2a209b34ccf 100644 --- a/llvm/lib/Transforms/IPO/PassManagerBuilder.cpp +++ b/llvm/lib/Transforms/IPO/PassManagerBuilder.cpp @@ -748,10 +748,10 @@ void PassManagerBuilder::populateLTOPassManager(legacy::PassManagerBase &PM) { // in the current module. PM.add(createCrossDSOCFIPass()); - // Lower bit sets to globals. This pass supports Clang's control flow - // integrity mechanisms (-fsanitize=cfi*) and needs to run at link time if CFI - // is enabled. The pass does nothing if CFI is disabled. - PM.add(createLowerBitSetsPass()); + // Lower type metadata and the type.test intrinsic. This pass supports Clang's + // control flow integrity mechanisms (-fsanitize=cfi*) and needs to run at + // link time if CFI is enabled. The pass does nothing if CFI is disabled. + PM.add(createLowerTypeTestsPass()); if (OptLevel != 0) addLateLTOOptimizationPasses(PM); diff --git a/llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp b/llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp index 93ee07cf64e..c19c667a51e 100644 --- a/llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp +++ b/llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp @@ -8,7 +8,7 @@ //===----------------------------------------------------------------------===// // // This pass implements whole program optimization of virtual calls in cases -// where we know (via bitset information) that the list of callee is fixed. This +// where we know (via !type metadata) that the list of callees is fixed. This // includes the following: // - Single implementation devirtualization: if a virtual call has a single // possible callee, replace all calls with a direct call to that callee. @@ -31,7 +31,7 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/MapVector.h" -#include "llvm/Analysis/BitSetUtils.h" +#include "llvm/Analysis/TypeMetadataUtils.h" #include "llvm/IR/CallSite.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DataLayout.h" @@ -89,8 +89,8 @@ wholeprogramdevirt::findLowestOffset(ArrayRef<VirtualCallTarget> Targets, // at MinByte. std::vector<ArrayRef<uint8_t>> Used; for (const VirtualCallTarget &Target : Targets) { - ArrayRef<uint8_t> VTUsed = IsAfter ? Target.BS->Bits->After.BytesUsed - : Target.BS->Bits->Before.BytesUsed; + ArrayRef<uint8_t> VTUsed = IsAfter ? Target.TM->Bits->After.BytesUsed + : Target.TM->Bits->Before.BytesUsed; uint64_t Offset = IsAfter ? MinByte - Target.minAfterBytes() : MinByte - Target.minBeforeBytes(); @@ -163,17 +163,17 @@ void wholeprogramdevirt::setAfterReturnValues( } } -VirtualCallTarget::VirtualCallTarget(Function *Fn, const BitSetInfo *BS) - : Fn(Fn), BS(BS), +VirtualCallTarget::VirtualCallTarget(Function *Fn, const TypeMemberInfo *TM) + : Fn(Fn), TM(TM), IsBigEndian(Fn->getParent()->getDataLayout().isBigEndian()) {} namespace { -// A slot in a set of virtual tables. The BitSetID identifies the set of virtual +// A slot in a set of virtual tables. The TypeID identifies the set of virtual // tables, and the ByteOffset is the offset in bytes from the address point to // the virtual function pointer. struct VTableSlot { - Metadata *BitSetID; + Metadata *TypeID; uint64_t ByteOffset; }; @@ -191,12 +191,12 @@ template <> struct DenseMapInfo<VTableSlot> { DenseMapInfo<uint64_t>::getTombstoneKey()}; } static unsigned getHashValue(const VTableSlot &I) { - return DenseMapInfo<Metadata *>::getHashValue(I.BitSetID) ^ + return DenseMapInfo<Metadata *>::getHashValue(I.TypeID) ^ DenseMapInfo<uint64_t>::getHashValue(I.ByteOffset); } static bool isEqual(const VTableSlot &LHS, const VTableSlot &RHS) { - return LHS.BitSetID == RHS.BitSetID && LHS.ByteOffset == RHS.ByteOffset; + return LHS.TypeID == RHS.TypeID && LHS.ByteOffset == RHS.ByteOffset; } }; @@ -233,11 +233,13 @@ struct DevirtModule { Int8PtrTy(Type::getInt8PtrTy(M.getContext())), Int32Ty(Type::getInt32Ty(M.getContext())) {} - void buildBitSets(std::vector<VTableBits> &Bits, - DenseMap<Metadata *, std::set<BitSetInfo>> &BitSets); - bool tryFindVirtualCallTargets(std::vector<VirtualCallTarget> &TargetsForSlot, - const std::set<BitSetInfo> &BitSetInfos, - uint64_t ByteOffset); + void buildTypeIdentifierMap( + std::vector<VTableBits> &Bits, + DenseMap<Metadata *, std::set<TypeMemberInfo>> &TypeIdMap); + bool + tryFindVirtualCallTargets(std::vector<VirtualCallTarget> &TargetsForSlot, + const std::set<TypeMemberInfo> &TypeMemberInfos, + uint64_t ByteOffset); bool trySingleImplDevirt(ArrayRef<VirtualCallTarget> TargetsForSlot, MutableArrayRef<VirtualCallSite> CallSites); bool tryEvaluateFunctionsWithArgs( @@ -287,60 +289,55 @@ PreservedAnalyses WholeProgramDevirtPass::run(Module &M, return PreservedAnalyses::none(); } -void DevirtModule::buildBitSets( +void DevirtModule::buildTypeIdentifierMap( std::vector<VTableBits> &Bits, - DenseMap<Metadata *, std::set<BitSetInfo>> &BitSets) { - NamedMDNode *BitSetNM = M.getNamedMetadata("llvm.bitsets"); - if (!BitSetNM) - return; - + DenseMap<Metadata *, std::set<TypeMemberInfo>> &TypeIdMap) { DenseMap<GlobalVariable *, VTableBits *> GVToBits; - Bits.reserve(BitSetNM->getNumOperands()); - for (auto Op : BitSetNM->operands()) { - auto OpConstMD = dyn_cast_or_null<ConstantAsMetadata>(Op->getOperand(1)); - if (!OpConstMD) + Bits.reserve(M.getGlobalList().size()); + SmallVector<MDNode *, 2> Types; + for (GlobalVariable &GV : M.globals()) { + Types.clear(); + GV.getMetadata(LLVMContext::MD_type, Types); + if (Types.empty()) continue; - auto BitSetID = Op->getOperand(0).get(); - - Constant *OpConst = OpConstMD->getValue(); - if (auto GA = dyn_cast<GlobalAlias>(OpConst)) - OpConst = GA->getAliasee(); - auto OpGlobal = dyn_cast<GlobalVariable>(OpConst); - if (!OpGlobal) - continue; - - uint64_t Offset = - cast<ConstantInt>( - cast<ConstantAsMetadata>(Op->getOperand(2))->getValue()) - ->getZExtValue(); - VTableBits *&BitsPtr = GVToBits[OpGlobal]; + VTableBits *&BitsPtr = GVToBits[&GV]; if (!BitsPtr) { Bits.emplace_back(); - Bits.back().GV = OpGlobal; - Bits.back().ObjectSize = M.getDataLayout().getTypeAllocSize( - OpGlobal->getInitializer()->getType()); + Bits.back().GV = &GV; + Bits.back().ObjectSize = + M.getDataLayout().getTypeAllocSize(GV.getInitializer()->getType()); BitsPtr = &Bits.back(); } - BitSets[BitSetID].insert({BitsPtr, Offset}); + + for (MDNode *Type : Types) { + auto TypeID = Type->getOperand(1).get(); + + uint64_t Offset = + cast<ConstantInt>( + cast<ConstantAsMetadata>(Type->getOperand(0))->getValue()) + ->getZExtValue(); + + TypeIdMap[TypeID].insert({BitsPtr, Offset}); + } } } bool DevirtModule::tryFindVirtualCallTargets( std::vector<VirtualCallTarget> &TargetsForSlot, - const std::set<BitSetInfo> &BitSetInfos, uint64_t ByteOffset) { - for (const BitSetInfo &BS : BitSetInfos) { - if (!BS.Bits->GV->isConstant()) + const std::set<TypeMemberInfo> &TypeMemberInfos, uint64_t ByteOffset) { + for (const TypeMemberInfo &TM : TypeMemberInfos) { + if (!TM.Bits->GV->isConstant()) return false; - auto Init = dyn_cast<ConstantArray>(BS.Bits->GV->getInitializer()); + auto Init = dyn_cast<ConstantArray>(TM.Bits->GV->getInitializer()); if (!Init) return false; ArrayType *VTableTy = Init->getType(); uint64_t ElemSize = M.getDataLayout().getTypeAllocSize(VTableTy->getElementType()); - uint64_t GlobalSlotOffset = BS.Offset + ByteOffset; + uint64_t GlobalSlotOffset = TM.Offset + ByteOffset; if (GlobalSlotOffset % ElemSize != 0) return false; @@ -357,7 +354,7 @@ bool DevirtModule::tryFindVirtualCallTargets( if (Fn->getName() == "__cxa_pure_virtual") continue; - TargetsForSlot.push_back({Fn, &BS}); + TargetsForSlot.push_back({Fn, &TM}); } // Give up if we couldn't find any targets. @@ -430,24 +427,24 @@ bool DevirtModule::tryUniqueRetValOpt( MutableArrayRef<VirtualCallSite> CallSites) { // IsOne controls whether we look for a 0 or a 1. auto tryUniqueRetValOptFor = [&](bool IsOne) { - const BitSetInfo *UniqueBitSet = 0; + const TypeMemberInfo *UniqueMember = 0; for (const VirtualCallTarget &Target : TargetsForSlot) { if (Target.RetVal == (IsOne ? 1 : 0)) { - if (UniqueBitSet) + if (UniqueMember) return false; - UniqueBitSet = Target.BS; + UniqueMember = Target.TM; } } - // We should have found a unique bit set or bailed out by now. We already + // We should have found a unique member or bailed out by now. We already // checked for a uniform return value in tryUniformRetValOpt. - assert(UniqueBitSet); + assert(UniqueMember); // Replace each call with the comparison. for (auto &&Call : CallSites) { IRBuilder<> B(Call.CS.getInstruction()); - Value *OneAddr = B.CreateBitCast(UniqueBitSet->Bits->GV, Int8PtrTy); - OneAddr = B.CreateConstGEP1_64(OneAddr, UniqueBitSet->Offset); + Value *OneAddr = B.CreateBitCast(UniqueMember->Bits->GV, Int8PtrTy); + OneAddr = B.CreateConstGEP1_64(OneAddr, UniqueMember->Offset); Value *Cmp = B.CreateICmp(IsOne ? ICmpInst::ICMP_EQ : ICmpInst::ICMP_NE, Call.VTable, OneAddr); Call.replaceAndErase(Cmp); @@ -526,7 +523,8 @@ bool DevirtModule::tryVirtualConstProp( if (tryUniqueRetValOpt(BitWidth, TargetsForSlot, CSByConstantArg.second)) continue; - // Find an allocation offset in bits in all vtables in the bitset. + // Find an allocation offset in bits in all vtables associated with the + // type. uint64_t AllocBefore = findLowestOffset(TargetsForSlot, /*IsAfter=*/false, BitWidth); uint64_t AllocAfter = @@ -620,9 +618,9 @@ void DevirtModule::rebuildGlobal(VTableBits &B) { } bool DevirtModule::run() { - Function *BitSetTestFunc = - M.getFunction(Intrinsic::getName(Intrinsic::bitset_test)); - if (!BitSetTestFunc || BitSetTestFunc->use_empty()) + Function *TypeTestFunc = + M.getFunction(Intrinsic::getName(Intrinsic::type_test)); + if (!TypeTestFunc || TypeTestFunc->use_empty()) return false; Function *AssumeFunc = M.getFunction(Intrinsic::getName(Intrinsic::assume)); @@ -630,11 +628,12 @@ bool DevirtModule::run() { return false; // Find all virtual calls via a virtual table pointer %p under an assumption - // of the form llvm.assume(llvm.bitset.test(%p, %md)). This indicates that %p - // points to a vtable in the bitset %md. Group calls by (bitset, offset) pair - // (effectively the identity of the virtual function) and store to CallSlots. + // of the form llvm.assume(llvm.type.test(%p, %md)). This indicates that %p + // points to a member of the type identifier %md. Group calls by (type ID, + // offset) pair (effectively the identity of the virtual function) and store + // to CallSlots. DenseSet<Value *> SeenPtrs; - for (auto I = BitSetTestFunc->use_begin(), E = BitSetTestFunc->use_end(); + for (auto I = TypeTestFunc->use_begin(), E = TypeTestFunc->use_end(); I != E;) { auto CI = dyn_cast<CallInst>(I->getUser()); ++I; @@ -650,18 +649,18 @@ bool DevirtModule::run() { // the vtable pointer before, as it may have been CSE'd with pointers from // other call sites, and we don't want to process call sites multiple times. if (!Assumes.empty()) { - Metadata *BitSet = + Metadata *TypeId = cast<MetadataAsValue>(CI->getArgOperand(1))->getMetadata(); Value *Ptr = CI->getArgOperand(0)->stripPointerCasts(); if (SeenPtrs.insert(Ptr).second) { for (DevirtCallSite Call : DevirtCalls) { - CallSlots[{BitSet, Call.Offset}].push_back( + CallSlots[{TypeId, Call.Offset}].push_back( {CI->getArgOperand(0), Call.CS}); } } } - // We no longer need the assumes or the bitset test. + // We no longer need the assumes or the type test. for (auto Assume : Assumes) Assume->eraseFromParent(); // We can't use RecursivelyDeleteTriviallyDeadInstructions here because we @@ -670,20 +669,21 @@ bool DevirtModule::run() { CI->eraseFromParent(); } - // Rebuild llvm.bitsets metadata into a map for easy lookup. + // Rebuild type metadata into a map for easy lookup. std::vector<VTableBits> Bits; - DenseMap<Metadata *, std::set<BitSetInfo>> BitSets; - buildBitSets(Bits, BitSets); - if (BitSets.empty()) + DenseMap<Metadata *, std::set<TypeMemberInfo>> TypeIdMap; + buildTypeIdentifierMap(Bits, TypeIdMap); + if (TypeIdMap.empty()) return true; - // For each (bitset, offset) pair: + // For each (type, offset) pair: bool DidVirtualConstProp = false; for (auto &S : CallSlots) { - // Search each of the vtables in the bitset for the virtual function - // implementation at offset S.first.ByteOffset, and add to TargetsForSlot. + // Search each of the members of the type identifier for the virtual + // function implementation at offset S.first.ByteOffset, and add to + // TargetsForSlot. std::vector<VirtualCallTarget> TargetsForSlot; - if (!tryFindVirtualCallTargets(TargetsForSlot, BitSets[S.first.BitSetID], + if (!tryFindVirtualCallTargets(TargetsForSlot, TypeIdMap[S.first.TypeID], S.first.ByteOffset)) continue; diff --git a/llvm/test/Transforms/CrossDSOCFI/basic.ll b/llvm/test/Transforms/CrossDSOCFI/basic.ll index c408449d2d6..d54e60e0e26 100644 --- a/llvm/test/Transforms/CrossDSOCFI/basic.ll +++ b/llvm/test/Transforms/CrossDSOCFI/basic.ll @@ -16,52 +16,48 @@ ; CHECK-NEXT: br label %[[EXIT]] ; CHECK: [[L1]]: -; CHECK-NEXT: call i1 @llvm.bitset.test(i8* %[[ADDR]], metadata i64 111) +; CHECK-NEXT: call i1 @llvm.type.test(i8* %[[ADDR]], metadata i64 111) ; CHECK-NEXT: br {{.*}} label %[[EXIT]], label %[[FAIL]] ; CHECK: [[L2]]: -; CHECK-NEXT: call i1 @llvm.bitset.test(i8* %[[ADDR]], metadata i64 222) +; CHECK-NEXT: call i1 @llvm.type.test(i8* %[[ADDR]], metadata i64 222) ; CHECK-NEXT: br {{.*}} label %[[EXIT]], label %[[FAIL]] ; CHECK: [[L3]]: -; CHECK-NEXT: call i1 @llvm.bitset.test(i8* %[[ADDR]], metadata i64 333) +; CHECK-NEXT: call i1 @llvm.type.test(i8* %[[ADDR]], metadata i64 333) ; CHECK-NEXT: br {{.*}} label %[[EXIT]], label %[[FAIL]] ; CHECK: [[L4]]: -; CHECK-NEXT: call i1 @llvm.bitset.test(i8* %[[ADDR]], metadata i64 444) +; CHECK-NEXT: call i1 @llvm.type.test(i8* %[[ADDR]], metadata i64 444) ; CHECK-NEXT: br {{.*}} label %[[EXIT]], label %[[FAIL]] target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-unknown-linux-gnu" -@_ZTV1A = constant i8 0 -@_ZTI1A = constant i8 0 -@_ZTS1A = constant i8 0 -@_ZTV1B = constant i8 0 -@_ZTI1B = constant i8 0 -@_ZTS1B = constant i8 0 +@_ZTV1A = constant i8 0, !type !4, !type !5 +@_ZTV1B = constant i8 0, !type !4, !type !5, !type !6, !type !7 -define signext i8 @f11() { +define signext i8 @f11() !type !0 !type !1 { entry: ret i8 1 } -define signext i8 @f12() { +define signext i8 @f12() !type !0 !type !1 { entry: ret i8 2 } -define signext i8 @f13() { +define signext i8 @f13() !type !0 !type !1 { entry: ret i8 3 } -define i32 @f21() { +define i32 @f21() !type !2 !type !3 { entry: ret i32 4 } -define i32 @f22() { +define i32 @f22() !type !2 !type !3 { entry: ret i32 5 } @@ -71,23 +67,14 @@ entry: ret void } -!llvm.bitsets = !{!0, !1, !2, !3, !4, !7, !8, !9, !10, !11, !12, !13, !14, !15} -!llvm.module.flags = !{!17} - -!0 = !{!"_ZTSFcvE", i8 ()* @f11, i64 0} -!1 = !{i64 111, i8 ()* @f11, i64 0} -!2 = !{!"_ZTSFcvE", i8 ()* @f12, i64 0} -!3 = !{i64 111, i8 ()* @f12, i64 0} -!4 = !{!"_ZTSFcvE", i8 ()* @f13, i64 0} -!5 = !{i64 111, i8 ()* @f13, i64 0} -!6 = !{!"_ZTSFivE", i32 ()* @f21, i64 0} -!7 = !{i64 222, i32 ()* @f21, i64 0} -!8 = !{!"_ZTSFivE", i32 ()* @f22, i64 0} -!9 = !{i64 222, i32 ()* @f22, i64 0} -!10 = !{!"_ZTS1A", i8* @_ZTV1A, i64 16} -!11 = !{i64 333, i8* @_ZTV1A, i64 16} -!12 = !{!"_ZTS1A", i8* @_ZTV1B, i64 16} -!13 = !{i64 333, i8* @_ZTV1B, i64 16} -!14 = !{!"_ZTS1B", i8* @_ZTV1B, i64 16} -!15 = !{i64 444, i8* @_ZTV1B, i64 16} -!17= !{i32 4, !"Cross-DSO CFI", i32 1} +!llvm.module.flags = !{!8} + +!0 = !{i64 0, !"_ZTSFcvE"} +!1 = !{i64 0, i64 111} +!2 = !{i64 0, !"_ZTSFivE"} +!3 = !{i64 0, i64 222} +!4 = !{i64 16, !"_ZTS1A"} +!5 = !{i64 16, i64 333} +!6 = !{i64 16, !"_ZTS1B"} +!7 = !{i64 16, i64 444} +!8 = !{i32 4, !"Cross-DSO CFI", i32 1} diff --git a/llvm/test/Transforms/LowerBitSets/constant.ll b/llvm/test/Transforms/LowerBitSets/constant.ll deleted file mode 100644 index 99c925914f7..00000000000 --- a/llvm/test/Transforms/LowerBitSets/constant.ll +++ /dev/null @@ -1,34 +0,0 @@ -; RUN: opt -S -lowerbitsets < %s | FileCheck %s - -target datalayout = "e-p:32:32" - -@a = constant i32 1 -@b = constant [2 x i32] [i32 2, i32 3] - -!0 = !{!"bitset1", i32* @a, i32 0} -!1 = !{!"bitset1", [2 x i32]* @b, i32 4} - -!llvm.bitsets = !{ !0, !1 } - -declare i1 @llvm.bitset.test(i8* %ptr, metadata %bitset) nounwind readnone - -; CHECK: @foo( -define i1 @foo() { - ; CHECK: ret i1 true - %x = call i1 @llvm.bitset.test(i8* bitcast (i32* @a to i8*), metadata !"bitset1") - ret i1 %x -} - -; CHECK: @bar( -define i1 @bar() { - ; CHECK: ret i1 true - %x = call i1 @llvm.bitset.test(i8* bitcast (i32* getelementptr ([2 x i32], [2 x i32]* @b, i32 0, i32 1) to i8*), metadata !"bitset1") - ret i1 %x -} - -; CHECK: @baz( -define i1 @baz() { - ; CHECK-NOT: ret i1 true - %x = call i1 @llvm.bitset.test(i8* bitcast (i32* getelementptr ([2 x i32], [2 x i32]* @b, i32 0, i32 0) to i8*), metadata !"bitset1") - ret i1 %x -} diff --git a/llvm/test/Transforms/LowerBitSets/layout.ll b/llvm/test/Transforms/LowerBitSets/layout.ll deleted file mode 100644 index a0c6e77a57f..00000000000 --- a/llvm/test/Transforms/LowerBitSets/layout.ll +++ /dev/null @@ -1,35 +0,0 @@ -; RUN: opt -S -lowerbitsets < %s | FileCheck %s - -target datalayout = "e-p:32:32" - -; Tests that this set of globals is laid out according to our layout algorithm -; (see GlobalLayoutBuilder in include/llvm/Transforms/IPO/LowerBitSets.h). -; The chosen layout in this case is a, e, b, d, c. - -; CHECK: private constant { i32, [0 x i8], i32, [0 x i8], i32, [0 x i8], i32, [0 x i8], i32 } { i32 1, [0 x i8] zeroinitializer, i32 5, [0 x i8] zeroinitializer, i32 2, [0 x i8] zeroinitializer, i32 4, [0 x i8] zeroinitializer, i32 3 } -@a = constant i32 1 -@b = constant i32 2 -@c = constant i32 3 -@d = constant i32 4 -@e = constant i32 5 - -!0 = !{!"bitset1", i32* @a, i32 0} -!1 = !{!"bitset1", i32* @b, i32 0} -!2 = !{!"bitset1", i32* @c, i32 0} - -!3 = !{!"bitset2", i32* @b, i32 0} -!4 = !{!"bitset2", i32* @d, i32 0} - -!5 = !{!"bitset3", i32* @a, i32 0} -!6 = !{!"bitset3", i32* @e, i32 0} - -!llvm.bitsets = !{ !0, !1, !2, !3, !4, !5, !6 } - -declare i1 @llvm.bitset.test(i8* %ptr, metadata %bitset) nounwind readnone - -define void @foo() { - %x = call i1 @llvm.bitset.test(i8* undef, metadata !"bitset1") - %y = call i1 @llvm.bitset.test(i8* undef, metadata !"bitset2") - %z = call i1 @llvm.bitset.test(i8* undef, metadata !"bitset3") - ret void -} diff --git a/llvm/test/Transforms/LowerBitSets/nonglobal.ll b/llvm/test/Transforms/LowerBitSets/nonglobal.ll deleted file mode 100644 index 7591e31e352..00000000000 --- a/llvm/test/Transforms/LowerBitSets/nonglobal.ll +++ /dev/null @@ -1,19 +0,0 @@ -; RUN: opt -S -lowerbitsets < %s | FileCheck %s - -target datalayout = "e-p:32:32" - -; CHECK-NOT: @b = alias -@a = constant i32 1 -@b = constant [2 x i32] [i32 2, i32 3] - -!0 = !{!"bitset1", i32* @a, i32 0} -!1 = !{!"bitset1", i32* bitcast ([2 x i32]* @b to i32*), i32 0} - -!llvm.bitsets = !{ !0, !1 } - -declare i1 @llvm.bitset.test(i8* %ptr, metadata %bitset) nounwind readnone - -define i1 @foo(i8* %p) { - %x = call i1 @llvm.bitset.test(i8* %p, metadata !"bitset1") - ret i1 %x -} diff --git a/llvm/test/Transforms/LowerBitSets/pr25902.ll b/llvm/test/Transforms/LowerBitSets/pr25902.ll deleted file mode 100644 index b9a1203ec0e..00000000000 --- a/llvm/test/Transforms/LowerBitSets/pr25902.ll +++ /dev/null @@ -1,21 +0,0 @@ -; PR25902: gold plugin crash. -; RUN: opt -mtriple=i686-pc -S -lowerbitsets < %s - -define void @f(void ()* %p) { -entry: - %a = bitcast void ()* %p to i8*, !nosanitize !1 - %b = call i1 @llvm.bitset.test(i8* %a, metadata !"_ZTSFvvE"), !nosanitize !1 - ret void -} - -define void @g() { -entry: - ret void -} - -declare i1 @llvm.bitset.test(i8*, metadata) - -!llvm.bitsets = !{!0} - -!0 = !{!"_ZTSFvvE", void ()* @g, i64 0} -!1 = !{} diff --git a/llvm/test/Transforms/LowerBitSets/unnamed.ll b/llvm/test/Transforms/LowerBitSets/unnamed.ll deleted file mode 100644 index 6f108e22d02..00000000000 --- a/llvm/test/Transforms/LowerBitSets/unnamed.ll +++ /dev/null @@ -1,20 +0,0 @@ -; RUN: opt -S -lowerbitsets < %s | FileCheck %s - -target datalayout = "e-p:32:32" - -; CHECK: @{{[0-9]+}} = alias -; CHECK: @{{[0-9]+}} = alias -@0 = constant i32 1 -@1 = constant [2 x i32] [i32 2, i32 3] - -!0 = !{!"bitset1", i32* @0, i32 0} -!1 = !{!"bitset1", [2 x i32]* @1, i32 4} - -!llvm.bitsets = !{ !0, !1 } - -declare i1 @llvm.bitset.test(i8* %ptr, metadata %bitset) nounwind readnone - -define i1 @foo(i8* %p) { - %x = call i1 @llvm.bitset.test(i8* %p, metadata !"bitset1") - ret i1 %x -} diff --git a/llvm/test/Transforms/LowerTypeTests/constant.ll b/llvm/test/Transforms/LowerTypeTests/constant.ll new file mode 100644 index 00000000000..4ddf14916ba --- /dev/null +++ b/llvm/test/Transforms/LowerTypeTests/constant.ll @@ -0,0 +1,32 @@ +; RUN: opt -S -lowertypetests < %s | FileCheck %s + +target datalayout = "e-p:32:32" + +@a = constant i32 1, !type !0 +@b = constant [2 x i32] [i32 2, i32 3], !type !1 + +!0 = !{i32 0, !"typeid1"} +!1 = !{i32 4, !"typeid1"} + +declare i1 @llvm.type.test(i8* %ptr, metadata %bitset) nounwind readnone + +; CHECK: @foo( +define i1 @foo() { + ; CHECK: ret i1 true + %x = call i1 @llvm.type.test(i8* bitcast (i32* @a to i8*), metadata !"typeid1") + ret i1 %x +} + +; CHECK: @bar( +define i1 @bar() { + ; CHECK: ret i1 true + %x = call i1 @llvm.type.test(i8* bitcast (i32* getelementptr ([2 x i32], [2 x i32]* @b, i32 0, i32 1) to i8*), metadata !"typeid1") + ret i1 %x +} + +; CHECK: @baz( +define i1 @baz() { + ; CHECK-NOT: ret i1 true + %x = call i1 @llvm.type.test(i8* bitcast (i32* getelementptr ([2 x i32], [2 x i32]* @b, i32 0, i32 0) to i8*), metadata !"typeid1") + ret i1 %x +} diff --git a/llvm/test/Transforms/LowerBitSets/function-ext.ll b/llvm/test/Transforms/LowerTypeTests/function-ext.ll index 2a83bef2f07..45dcc5e6de3 100644 --- a/llvm/test/Transforms/LowerBitSets/function-ext.ll +++ b/llvm/test/Transforms/LowerTypeTests/function-ext.ll @@ -1,22 +1,20 @@ -; RUN: opt -S -lowerbitsets < %s | FileCheck %s +; RUN: opt -S -lowertypetests < %s | FileCheck %s ; Tests that we correctly handle external references, including the case where ; all functions in a bitset are external references. target triple = "x86_64-unknown-linux-gnu" -declare void @foo() +declare !type !0 void @foo() ; CHECK: @[[JT:.*]] = private constant [1 x <{ i8, i32, i8, i8, i8 }>] [<{ i8, i32, i8, i8, i8 }> <{ i8 -23, i32 trunc (i64 sub (i64 sub (i64 ptrtoint (void ()* @foo to i64), i64 ptrtoint ([1 x <{ i8, i32, i8, i8, i8 }>]* @[[JT]] to i64)), i64 5) to i32), i8 -52, i8 -52, i8 -52 }>], section ".text" define i1 @bar(i8* %ptr) { ; CHECK: icmp eq i64 {{.*}}, ptrtoint ([1 x <{ i8, i32, i8, i8, i8 }>]* @[[JT]] to i64) - %p = call i1 @llvm.bitset.test(i8* %ptr, metadata !"void") + %p = call i1 @llvm.type.test(i8* %ptr, metadata !"void") ret i1 %p } -declare i1 @llvm.bitset.test(i8* %ptr, metadata %bitset) nounwind readnone +declare i1 @llvm.type.test(i8* %ptr, metadata %bitset) nounwind readnone -!0 = !{!"void", void ()* @foo, i64 0} - -!llvm.bitsets = !{!0} +!0 = !{i64 0, !"void"} diff --git a/llvm/test/Transforms/LowerBitSets/function.ll b/llvm/test/Transforms/LowerTypeTests/function.ll index bf4043d61c4..662d1e2a197 100644 --- a/llvm/test/Transforms/LowerBitSets/function.ll +++ b/llvm/test/Transforms/LowerTypeTests/function.ll @@ -1,4 +1,4 @@ -; RUN: opt -S -lowerbitsets < %s | FileCheck %s +; RUN: opt -S -lowertypetests < %s | FileCheck %s ; Tests that we correctly create a jump table for bitsets containing 2 or more ; functions. @@ -11,25 +11,22 @@ target datalayout = "e-p:64:64" ; CHECK: @f = alias void (), bitcast ([2 x <{ i8, i32, i8, i8, i8 }>]* @[[JT]] to void ()*) ; CHECK: @g = alias void (), bitcast (<{ i8, i32, i8, i8, i8 }>* getelementptr inbounds ([2 x <{ i8, i32, i8, i8, i8 }>], [2 x <{ i8, i32, i8, i8, i8 }>]* @[[JT]], i64 0, i64 1) to void ()*) -; CHECK: define private void @[[FNAME]]() { -define void @f() { +; CHECK: define private void @[[FNAME]]() +define void @f() !type !0 { ret void } -; CHECK: define private void @[[GNAME]]() { -define void @g() { +; CHECK: define private void @[[GNAME]]() +define void @g() !type !0 { ret void } -!0 = !{!"bitset1", void ()* @f, i32 0} -!1 = !{!"bitset1", void ()* @g, i32 0} +!0 = !{i32 0, !"typeid1"} -!llvm.bitsets = !{ !0, !1 } - -declare i1 @llvm.bitset.test(i8* %ptr, metadata %bitset) nounwind readnone +declare i1 @llvm.type.test(i8* %ptr, metadata %bitset) nounwind readnone define i1 @foo(i8* %p) { ; CHECK: sub i64 {{.*}}, ptrtoint ([2 x <{ i8, i32, i8, i8, i8 }>]* @[[JT]] to i64) - %x = call i1 @llvm.bitset.test(i8* %p, metadata !"bitset1") + %x = call i1 @llvm.type.test(i8* %p, metadata !"typeid1") ret i1 %x } diff --git a/llvm/test/Transforms/LowerTypeTests/layout.ll b/llvm/test/Transforms/LowerTypeTests/layout.ll new file mode 100644 index 00000000000..7075955790d --- /dev/null +++ b/llvm/test/Transforms/LowerTypeTests/layout.ll @@ -0,0 +1,27 @@ +; RUN: opt -S -lowertypetests < %s | FileCheck %s + +target datalayout = "e-p:32:32" + +; Tests that this set of globals is laid out according to our layout algorithm +; (see GlobalLayoutBuilder in include/llvm/Transforms/IPO/LowerTypeTests.h). +; The chosen layout in this case is a, e, b, d, c. + +; CHECK: private constant { i32, [0 x i8], i32, [0 x i8], i32, [0 x i8], i32, [0 x i8], i32 } { i32 1, [0 x i8] zeroinitializer, i32 5, [0 x i8] zeroinitializer, i32 2, [0 x i8] zeroinitializer, i32 4, [0 x i8] zeroinitializer, i32 3 } +@a = constant i32 1, !type !0, !type !2 +@b = constant i32 2, !type !0, !type !1 +@c = constant i32 3, !type !0 +@d = constant i32 4, !type !1 +@e = constant i32 5, !type !2 + +!0 = !{i32 0, !"typeid1"} +!1 = !{i32 0, !"typeid2"} +!2 = !{i32 0, !"typeid3"} + +declare i1 @llvm.type.test(i8* %ptr, metadata %bitset) nounwind readnone + +define void @foo() { + %x = call i1 @llvm.type.test(i8* undef, metadata !"typeid1") + %y = call i1 @llvm.type.test(i8* undef, metadata !"typeid2") + %z = call i1 @llvm.type.test(i8* undef, metadata !"typeid3") + ret void +} diff --git a/llvm/test/Transforms/LowerBitSets/nonstring.ll b/llvm/test/Transforms/LowerTypeTests/nonstring.ll index e61c9123e08..306dd1f3db1 100644 --- a/llvm/test/Transforms/LowerBitSets/nonstring.ll +++ b/llvm/test/Transforms/LowerTypeTests/nonstring.ll @@ -1,4 +1,4 @@ -; RUN: opt -S -lowerbitsets < %s | FileCheck %s +; RUN: opt -S -lowertypetests < %s | FileCheck %s ; Tests that non-string metadata nodes may be used as bitset identifiers. @@ -7,28 +7,26 @@ target datalayout = "e-p:32:32" ; CHECK: @[[ANAME:.*]] = private constant { i32 } ; CHECK: @[[BNAME:.*]] = private constant { [2 x i32] } -@a = constant i32 1 -@b = constant [2 x i32] [i32 2, i32 3] +@a = constant i32 1, !type !0 +@b = constant [2 x i32] [i32 2, i32 3], !type !1 -!0 = !{!2, i32* @a, i32 0} -!1 = !{!3, [2 x i32]* @b, i32 0} +!0 = !{i32 0, !2} +!1 = !{i32 0, !3} !2 = distinct !{} !3 = distinct !{} -!llvm.bitsets = !{ !0, !1 } - -declare i1 @llvm.bitset.test(i8* %ptr, metadata %bitset) nounwind readnone +declare i1 @llvm.type.test(i8* %ptr, metadata %bitset) nounwind readnone ; CHECK-LABEL: @foo define i1 @foo(i8* %p) { ; CHECK: icmp eq i32 {{.*}}, ptrtoint ({ i32 }* @[[ANAME]] to i32) - %x = call i1 @llvm.bitset.test(i8* %p, metadata !2) + %x = call i1 @llvm.type.test(i8* %p, metadata !2) ret i1 %x } ; CHECK-LABEL: @bar define i1 @bar(i8* %p) { ; CHECK: icmp eq i32 {{.*}}, ptrtoint ({ [2 x i32] }* @[[BNAME]] to i32) - %x = call i1 @llvm.bitset.test(i8* %p, metadata !3) + %x = call i1 @llvm.type.test(i8* %p, metadata !3) ret i1 %x } diff --git a/llvm/test/Transforms/LowerTypeTests/pr25902.ll b/llvm/test/Transforms/LowerTypeTests/pr25902.ll new file mode 100644 index 00000000000..dda283ca668 --- /dev/null +++ b/llvm/test/Transforms/LowerTypeTests/pr25902.ll @@ -0,0 +1,19 @@ +; PR25902: gold plugin crash. +; RUN: opt -mtriple=i686-pc -S -lowertypetests < %s + +define void @f(void ()* %p) { +entry: + %a = bitcast void ()* %p to i8*, !nosanitize !1 + %b = call i1 @llvm.type.test(i8* %a, metadata !"_ZTSFvvE"), !nosanitize !1 + ret void +} + +define void @g() !type !0 { +entry: + ret void +} + +declare i1 @llvm.type.test(i8*, metadata) + +!0 = !{i64 0, !"_ZTSFvvE"} +!1 = !{} diff --git a/llvm/test/Transforms/LowerBitSets/section.ll b/llvm/test/Transforms/LowerTypeTests/section.ll index d5f94148676..7884acfaec3 100644 --- a/llvm/test/Transforms/LowerBitSets/section.ll +++ b/llvm/test/Transforms/LowerTypeTests/section.ll @@ -1,7 +1,7 @@ ; Test that functions with "section" attribute are accepted, and jumptables are ; emitted in ".text". -; RUN: opt -S -lowerbitsets < %s | FileCheck %s +; RUN: opt -S -lowertypetests < %s | FileCheck %s target triple = "x86_64-unknown-linux-gnu" @@ -9,18 +9,17 @@ target triple = "x86_64-unknown-linux-gnu" ; CHECK: @f = alias void (), bitcast ({{.*}}* @[[A]] to void ()*) ; CHECK: define private void {{.*}} section "xxx" -define void @f() section "xxx" { +define void @f() section "xxx" !type !0 { entry: ret void } define i1 @g() { entry: - %0 = call i1 @llvm.bitset.test(i8* bitcast (void ()* @f to i8*), metadata !"_ZTSFvE") + %0 = call i1 @llvm.type.test(i8* bitcast (void ()* @f to i8*), metadata !"_ZTSFvE") ret i1 %0 } -declare i1 @llvm.bitset.test(i8*, metadata) nounwind readnone +declare i1 @llvm.type.test(i8*, metadata) nounwind readnone -!llvm.bitsets = !{!0} -!0 = !{!"_ZTSFvE", void ()* @f, i64 0} +!0 = !{i64 0, !"_ZTSFvE"} diff --git a/llvm/test/Transforms/LowerBitSets/simple.ll b/llvm/test/Transforms/LowerTypeTests/simple.ll index a22d998e200..0628951868c 100644 --- a/llvm/test/Transforms/LowerBitSets/simple.ll +++ b/llvm/test/Transforms/LowerTypeTests/simple.ll @@ -1,42 +1,34 @@ -; RUN: opt -S -lowerbitsets < %s | FileCheck %s -; RUN: opt -S -lowerbitsets -mtriple=x86_64-apple-macosx10.8.0 < %s | FileCheck -check-prefix=CHECK-DARWIN %s +; RUN: opt -S -lowertypetests < %s | FileCheck %s +; RUN: opt -S -lowertypetests -mtriple=x86_64-apple-macosx10.8.0 < %s | FileCheck -check-prefix=CHECK-DARWIN %s ; RUN: opt -S -O3 < %s | FileCheck -check-prefix=CHECK-NODISCARD %s target datalayout = "e-p:32:32" ; CHECK: [[G:@[^ ]*]] = private constant { i32, [0 x i8], [63 x i32], [4 x i8], i32, [0 x i8], [2 x i32] } { i32 1, [0 x i8] zeroinitializer, [63 x i32] zeroinitializer, [4 x i8] zeroinitializer, i32 3, [0 x i8] zeroinitializer, [2 x i32] [i32 4, i32 5] } -@a = constant i32 1 -@b = hidden constant [63 x i32] zeroinitializer -@c = protected constant i32 3 -@d = constant [2 x i32] [i32 4, i32 5] +@a = constant i32 1, !type !0, !type !2 +@b = hidden constant [63 x i32] zeroinitializer, !type !0, !type !1 +@c = protected constant i32 3, !type !1, !type !2 +@d = constant [2 x i32] [i32 4, i32 5], !type !3 + +; CHECK-NODISCARD: !type +; CHECK-NODISCARD: !type +; CHECK-NODISCARD: !type +; CHECK-NODISCARD: !type +; CHECK-NODISCARD: !type +; CHECK-NODISCARD: !type +; CHECK-NODISCARD: !type ; CHECK: [[BA:@[^ ]*]] = private constant [68 x i8] c"\03\01\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\02\00\01" ; Offset 0, 4 byte alignment -!0 = !{!"bitset1", i32* @a, i32 0} -; CHECK-NODISCARD-DAG: !{!"bitset1", i32* @a, i32 0} -!1 = !{!"bitset1", [63 x i32]* @b, i32 0} -; CHECK-NODISCARD-DAG: !{!"bitset1", [63 x i32]* @b, i32 0} -!2 = !{!"bitset1", [2 x i32]* @d, i32 4} -; CHECK-NODISCARD-DAG: !{!"bitset1", [2 x i32]* @d, i32 4} +!0 = !{i32 0, !"typeid1"} +!3 = !{i32 4, !"typeid1"} ; Offset 4, 256 byte alignment -!3 = !{!"bitset2", [63 x i32]* @b, i32 0} -; CHECK-NODISCARD-DAG: !{!"bitset2", [63 x i32]* @b, i32 0} -!4 = !{!"bitset2", i32* @c, i32 0} -; CHECK-NODISCARD-DAG: !{!"bitset2", i32* @c, i32 0} - -; Entries whose second operand is null (the result of a global being DCE'd) -; should be ignored. -!5 = !{!"bitset2", null, i32 0} +!1 = !{i32 0, !"typeid2"} ; Offset 0, 4 byte alignment -!6 = !{!"bitset3", i32* @a, i32 0} -; CHECK-NODISCARD-DAG: !{!"bitset3", i32* @a, i32 0} -!7 = !{!"bitset3", i32* @c, i32 0} -; CHECK-NODISCARD-DAG: !{!"bitset3", i32* @c, i32 0} - -!llvm.bitsets = !{ !0, !1, !2, !3, !4, !5, !6, !7 } +!2 = !{i32 0, !"typeid3"} ; CHECK: @bits_use{{[0-9]*}} = private alias i8, i8* @bits{{[0-9]*}} ; CHECK: @bits_use.{{[0-9]*}} = private alias i8, i8* @bits{{[0-9]*}} @@ -64,11 +56,11 @@ target datalayout = "e-p:32:32" ; CHECK: @bits{{[0-9]*}} = private alias i8, getelementptr inbounds ([68 x i8], [68 x i8]* [[BA]], i32 0, i32 0) ; CHECK: @bits.{{[0-9]*}} = private alias i8, getelementptr inbounds ([68 x i8], [68 x i8]* [[BA]], i32 0, i32 0) -declare i1 @llvm.bitset.test(i8* %ptr, metadata %bitset) nounwind readnone +declare i1 @llvm.type.test(i8* %ptr, metadata %bitset) nounwind readnone ; CHECK: @foo(i32* [[A0:%[^ ]*]]) define i1 @foo(i32* %p) { - ; CHECK-NOT: llvm.bitset.test + ; CHECK-NOT: llvm.type.test ; CHECK: [[R0:%[^ ]*]] = bitcast i32* [[A0]] to i8* %pi8 = bitcast i32* %p to i8* @@ -86,10 +78,10 @@ define i1 @foo(i32* %p) { ; CHECK: [[R11:%[^ ]*]] = icmp ne i8 [[R10]], 0 ; CHECK: [[R16:%[^ ]*]] = phi i1 [ false, {{%[^ ]*}} ], [ [[R11]], {{%[^ ]*}} ] - %x = call i1 @llvm.bitset.test(i8* %pi8, metadata !"bitset1") + %x = call i1 @llvm.type.test(i8* %pi8, metadata !"typeid1") - ; CHECK-NOT: llvm.bitset.test - %y = call i1 @llvm.bitset.test(i8* %pi8, metadata !"bitset1") + ; CHECK-NOT: llvm.type.test + %y = call i1 @llvm.type.test(i8* %pi8, metadata !"typeid1") ; CHECK: ret i1 [[R16]] ret i1 %x @@ -105,7 +97,7 @@ define i1 @bar(i32* %p) { ; CHECK: [[S4:%[^ ]*]] = shl i32 [[S2]], 24 ; CHECK: [[S5:%[^ ]*]] = or i32 [[S3]], [[S4]] ; CHECK: [[S6:%[^ ]*]] = icmp ult i32 [[S5]], 2 - %x = call i1 @llvm.bitset.test(i8* %pi8, metadata !"bitset2") + %x = call i1 @llvm.type.test(i8* %pi8, metadata !"typeid2") ; CHECK: ret i1 [[S6]] ret i1 %x @@ -123,15 +115,13 @@ define i1 @baz(i32* %p) { ; CHECK: [[T6:%[^ ]*]] = icmp ult i32 [[T5]], 66 ; CHECK: br i1 [[T6]] - ; CHECK: [[T8:%[^ ]*]] = getelementptr i8, i8* @bits_use.{{[0-9]*}}, i32 [[T5]] + ; CHECK: [[T8:%[^ ]*]] = getelementptr i8, i8* @bits_use{{(\.[0-9]*)?}}, i32 [[T5]] ; CHECK: [[T9:%[^ ]*]] = load i8, i8* [[T8]] ; CHECK: [[T10:%[^ ]*]] = and i8 [[T9]], 2 ; CHECK: [[T11:%[^ ]*]] = icmp ne i8 [[T10]], 0 ; CHECK: [[T16:%[^ ]*]] = phi i1 [ false, {{%[^ ]*}} ], [ [[T11]], {{%[^ ]*}} ] - %x = call i1 @llvm.bitset.test(i8* %pi8, metadata !"bitset3") + %x = call i1 @llvm.type.test(i8* %pi8, metadata !"typeid3") ; CHECK: ret i1 [[T16]] ret i1 %x } - -; CHECK-NOT: !llvm.bitsets diff --git a/llvm/test/Transforms/LowerBitSets/single-offset.ll b/llvm/test/Transforms/LowerTypeTests/single-offset.ll index 57194f42e09..6dd37984df9 100644 --- a/llvm/test/Transforms/LowerBitSets/single-offset.ll +++ b/llvm/test/Transforms/LowerTypeTests/single-offset.ll @@ -1,25 +1,22 @@ -; RUN: opt -S -lowerbitsets < %s | FileCheck %s +; RUN: opt -S -lowertypetests < %s | FileCheck %s target datalayout = "e-p:32:32" ; CHECK: [[G:@[^ ]*]] = private constant { i32, [0 x i8], i32 } -@a = constant i32 1 -@b = constant i32 2 +@a = constant i32 1, !type !0, !type !1 +@b = constant i32 2, !type !0, !type !2 -!0 = !{!"bitset1", i32* @a, i32 0} -!1 = !{!"bitset1", i32* @b, i32 0} -!2 = !{!"bitset2", i32* @a, i32 0} -!3 = !{!"bitset3", i32* @b, i32 0} +!0 = !{i32 0, !"typeid1"} +!1 = !{i32 0, !"typeid2"} +!2 = !{i32 0, !"typeid3"} -!llvm.bitsets = !{ !0, !1, !2, !3 } - -declare i1 @llvm.bitset.test(i8* %ptr, metadata %bitset) nounwind readnone +declare i1 @llvm.type.test(i8* %ptr, metadata %bitset) nounwind readnone ; CHECK: @foo(i8* [[A0:%[^ ]*]]) define i1 @foo(i8* %p) { ; CHECK: [[R0:%[^ ]*]] = ptrtoint i8* [[A0]] to i32 ; CHECK: [[R1:%[^ ]*]] = icmp eq i32 [[R0]], ptrtoint ({ i32, [0 x i8], i32 }* [[G]] to i32) - %x = call i1 @llvm.bitset.test(i8* %p, metadata !"bitset2") + %x = call i1 @llvm.type.test(i8* %p, metadata !"typeid2") ; CHECK: ret i1 [[R1]] ret i1 %x } @@ -28,13 +25,13 @@ define i1 @foo(i8* %p) { define i1 @bar(i8* %p) { ; CHECK: [[S0:%[^ ]*]] = ptrtoint i8* [[B0]] to i32 ; CHECK: [[S1:%[^ ]*]] = icmp eq i32 [[S0]], add (i32 ptrtoint ({ i32, [0 x i8], i32 }* [[G]] to i32), i32 4) - %x = call i1 @llvm.bitset.test(i8* %p, metadata !"bitset3") + %x = call i1 @llvm.type.test(i8* %p, metadata !"typeid3") ; CHECK: ret i1 [[S1]] ret i1 %x } ; CHECK: @x( define i1 @x(i8* %p) { - %x = call i1 @llvm.bitset.test(i8* %p, metadata !"bitset1") + %x = call i1 @llvm.type.test(i8* %p, metadata !"typeid1") ret i1 %x } diff --git a/llvm/test/Transforms/LowerTypeTests/unnamed.ll b/llvm/test/Transforms/LowerTypeTests/unnamed.ll new file mode 100644 index 00000000000..4bb2fd97208 --- /dev/null +++ b/llvm/test/Transforms/LowerTypeTests/unnamed.ll @@ -0,0 +1,18 @@ +; RUN: opt -S -lowertypetests < %s | FileCheck %s + +target datalayout = "e-p:32:32" + +; CHECK: @{{[0-9]+}} = alias +; CHECK: @{{[0-9]+}} = alias +@0 = constant i32 1, !type !0 +@1 = constant [2 x i32] [i32 2, i32 3], !type !1 + +!0 = !{i32 0, !"typeid1"} +!1 = !{i32 4, !"typeid1"} + +declare i1 @llvm.type.test(i8* %ptr, metadata %bitset) nounwind readnone + +define i1 @foo(i8* %p) { + %x = call i1 @llvm.type.test(i8* %p, metadata !"typeid1") + ret i1 %x +} diff --git a/llvm/test/Transforms/WholeProgramDevirt/bad-read-from-vtable.ll b/llvm/test/Transforms/WholeProgramDevirt/bad-read-from-vtable.ll index 9402076adf0..97445efb101 100644 --- a/llvm/test/Transforms/WholeProgramDevirt/bad-read-from-vtable.ll +++ b/llvm/test/Transforms/WholeProgramDevirt/bad-read-from-vtable.ll @@ -3,7 +3,7 @@ target datalayout = "e-p:64:64" target triple = "x86_64-unknown-linux-gnu" -@vt = global [2 x i8*] [i8* zeroinitializer, i8* bitcast (void (i8*)* @vf to i8*)] +@vt = global [2 x i8*] [i8* zeroinitializer, i8* bitcast (void (i8*)* @vf to i8*)], !type !0 define void @vf(i8* %this) { ret void @@ -14,7 +14,7 @@ define void @unaligned(i8* %obj) { %vtableptr = bitcast i8* %obj to [1 x i8*]** %vtable = load [1 x i8*]*, [1 x i8*]** %vtableptr %vtablei8 = bitcast [1 x i8*]* %vtable to i8* - %p = call i1 @llvm.bitset.test(i8* %vtablei8, metadata !"bitset") + %p = call i1 @llvm.type.test(i8* %vtablei8, metadata !"typeid") call void @llvm.assume(i1 %p) %fptrptr = getelementptr i8, i8* %vtablei8, i32 1 %fptrptr_casted = bitcast i8* %fptrptr to i8** @@ -30,7 +30,7 @@ define void @outofbounds(i8* %obj) { %vtableptr = bitcast i8* %obj to [1 x i8*]** %vtable = load [1 x i8*]*, [1 x i8*]** %vtableptr %vtablei8 = bitcast [1 x i8*]* %vtable to i8* - %p = call i1 @llvm.bitset.test(i8* %vtablei8, metadata !"bitset") + %p = call i1 @llvm.type.test(i8* %vtablei8, metadata !"typeid") call void @llvm.assume(i1 %p) %fptrptr = getelementptr i8, i8* %vtablei8, i32 16 %fptrptr_casted = bitcast i8* %fptrptr to i8** @@ -46,7 +46,7 @@ define void @nonfunction(i8* %obj) { %vtableptr = bitcast i8* %obj to [1 x i8*]** %vtable = load [1 x i8*]*, [1 x i8*]** %vtableptr %vtablei8 = bitcast [1 x i8*]* %vtable to i8* - %p = call i1 @llvm.bitset.test(i8* %vtablei8, metadata !"bitset") + %p = call i1 @llvm.type.test(i8* %vtablei8, metadata !"typeid") call void @llvm.assume(i1 %p) %fptrptr = getelementptr i8, i8* %vtablei8, i32 0 %fptrptr_casted = bitcast i8* %fptrptr to i8** @@ -57,8 +57,7 @@ define void @nonfunction(i8* %obj) { ret void } -declare i1 @llvm.bitset.test(i8*, metadata) +declare i1 @llvm.type.test(i8*, metadata) declare void @llvm.assume(i1) -!0 = !{!"bitset", [2 x i8*]* @vt, i32 0} -!llvm.bitsets = !{!0} +!0 = !{i32 0, !"typeid"} diff --git a/llvm/test/Transforms/WholeProgramDevirt/constant-arg.ll b/llvm/test/Transforms/WholeProgramDevirt/constant-arg.ll index e26759faedc..08047033aef 100644 --- a/llvm/test/Transforms/WholeProgramDevirt/constant-arg.ll +++ b/llvm/test/Transforms/WholeProgramDevirt/constant-arg.ll @@ -9,10 +9,10 @@ target triple = "x86_64-unknown-linux-gnu" ; CHECK: private constant { [8 x i8], [1 x i8*], [0 x i8] } { [8 x i8] c"\00\00\00\00\00\00\00\01", [1 x i8*] [i8* bitcast (i1 (i8*, i32)* @vf4 to i8*)], [0 x i8] zeroinitializer } ; CHECK: private constant { [8 x i8], [1 x i8*], [0 x i8] } { [8 x i8] c"\00\00\00\00\00\00\00\02", [1 x i8*] [i8* bitcast (i1 (i8*, i32)* @vf8 to i8*)], [0 x i8] zeroinitializer } -@vt1 = constant [1 x i8*] [i8* bitcast (i1 (i8*, i32)* @vf1 to i8*)] -@vt2 = constant [1 x i8*] [i8* bitcast (i1 (i8*, i32)* @vf2 to i8*)] -@vt4 = constant [1 x i8*] [i8* bitcast (i1 (i8*, i32)* @vf4 to i8*)] -@vt8 = constant [1 x i8*] [i8* bitcast (i1 (i8*, i32)* @vf8 to i8*)] +@vt1 = constant [1 x i8*] [i8* bitcast (i1 (i8*, i32)* @vf1 to i8*)], !type !0 +@vt2 = constant [1 x i8*] [i8* bitcast (i1 (i8*, i32)* @vf2 to i8*)], !type !0 +@vt4 = constant [1 x i8*] [i8* bitcast (i1 (i8*, i32)* @vf4 to i8*)], !type !0 +@vt8 = constant [1 x i8*] [i8* bitcast (i1 (i8*, i32)* @vf8 to i8*)], !type !0 define i1 @vf1(i8* %this, i32 %arg) readnone { %and = and i32 %arg, 1 @@ -43,7 +43,7 @@ define i1 @call1(i8* %obj) { %vtableptr = bitcast i8* %obj to [1 x i8*]** %vtable = load [1 x i8*]*, [1 x i8*]** %vtableptr %vtablei8 = bitcast [1 x i8*]* %vtable to i8* - %p = call i1 @llvm.bitset.test(i8* %vtablei8, metadata !"bitset") + %p = call i1 @llvm.type.test(i8* %vtablei8, metadata !"typeid") call void @llvm.assume(i1 %p) %fptrptr = getelementptr [1 x i8*], [1 x i8*]* %vtable, i32 0, i32 0 %fptr = load i8*, i8** %fptrptr @@ -59,7 +59,7 @@ define i1 @call2(i8* %obj) { %vtableptr = bitcast i8* %obj to [1 x i8*]** %vtable = load [1 x i8*]*, [1 x i8*]** %vtableptr %vtablei8 = bitcast [1 x i8*]* %vtable to i8* - %p = call i1 @llvm.bitset.test(i8* %vtablei8, metadata !"bitset") + %p = call i1 @llvm.type.test(i8* %vtablei8, metadata !"typeid") call void @llvm.assume(i1 %p) %fptrptr = getelementptr [1 x i8*], [1 x i8*]* %vtable, i32 0, i32 0 %fptr = load i8*, i8** %fptrptr @@ -70,11 +70,7 @@ define i1 @call2(i8* %obj) { ret i1 %result } -declare i1 @llvm.bitset.test(i8*, metadata) +declare i1 @llvm.type.test(i8*, metadata) declare void @llvm.assume(i1) -!0 = !{!"bitset", [1 x i8*]* @vt1, i32 0} -!1 = !{!"bitset", [1 x i8*]* @vt2, i32 0} -!2 = !{!"bitset", [1 x i8*]* @vt4, i32 0} -!3 = !{!"bitset", [1 x i8*]* @vt8, i32 0} -!llvm.bitsets = !{!0, !1, !2, !3} +!0 = !{i32 0, !"typeid"} diff --git a/llvm/test/Transforms/WholeProgramDevirt/devirt-single-impl.ll b/llvm/test/Transforms/WholeProgramDevirt/devirt-single-impl.ll index 85041551f67..7d665f534a5 100644 --- a/llvm/test/Transforms/WholeProgramDevirt/devirt-single-impl.ll +++ b/llvm/test/Transforms/WholeProgramDevirt/devirt-single-impl.ll @@ -3,8 +3,8 @@ target datalayout = "e-p:64:64" target triple = "x86_64-unknown-linux-gnu" -@vt1 = constant [1 x i8*] [i8* bitcast (void (i8*)* @vf to i8*)] -@vt2 = constant [1 x i8*] [i8* bitcast (void (i8*)* @vf to i8*)] +@vt1 = constant [1 x i8*] [i8* bitcast (void (i8*)* @vf to i8*)], !type !0 +@vt2 = constant [1 x i8*] [i8* bitcast (void (i8*)* @vf to i8*)], !type !0 define void @vf(i8* %this) { ret void @@ -15,7 +15,7 @@ define void @call(i8* %obj) { %vtableptr = bitcast i8* %obj to [1 x i8*]** %vtable = load [1 x i8*]*, [1 x i8*]** %vtableptr %vtablei8 = bitcast [1 x i8*]* %vtable to i8* - %p = call i1 @llvm.bitset.test(i8* %vtablei8, metadata !"bitset") + %p = call i1 @llvm.type.test(i8* %vtablei8, metadata !"typeid") call void @llvm.assume(i1 %p) %fptrptr = getelementptr [1 x i8*], [1 x i8*]* %vtable, i32 0, i32 0 %fptr = load i8*, i8** %fptrptr @@ -25,9 +25,7 @@ define void @call(i8* %obj) { ret void } -declare i1 @llvm.bitset.test(i8*, metadata) +declare i1 @llvm.type.test(i8*, metadata) declare void @llvm.assume(i1) -!0 = !{!"bitset", [1 x i8*]* @vt1, i32 0} -!1 = !{!"bitset", [1 x i8*]* @vt2, i32 0} -!llvm.bitsets = !{!0, !1} +!0 = !{i32 0, !"typeid"} diff --git a/llvm/test/Transforms/WholeProgramDevirt/non-array-vtable.ll b/llvm/test/Transforms/WholeProgramDevirt/non-array-vtable.ll index d6befd591e9..e9c2db79fcb 100644 --- a/llvm/test/Transforms/WholeProgramDevirt/non-array-vtable.ll +++ b/llvm/test/Transforms/WholeProgramDevirt/non-array-vtable.ll @@ -3,7 +3,7 @@ target datalayout = "e-p:64:64" target triple = "x86_64-unknown-linux-gnu" -@vt = constant i8* bitcast (void (i8*)* @vf to i8*) +@vt = constant i8* bitcast (void (i8*)* @vf to i8*), !type !0 define void @vf(i8* %this) { ret void @@ -14,7 +14,7 @@ define void @call(i8* %obj) { %vtableptr = bitcast i8* %obj to [1 x i8*]** %vtable = load [1 x i8*]*, [1 x i8*]** %vtableptr %vtablei8 = bitcast [1 x i8*]* %vtable to i8* - %p = call i1 @llvm.bitset.test(i8* %vtablei8, metadata !"bitset") + %p = call i1 @llvm.type.test(i8* %vtablei8, metadata !"typeid") call void @llvm.assume(i1 %p) %fptrptr = getelementptr [1 x i8*], [1 x i8*]* %vtable, i32 0, i32 0 %fptr = load i8*, i8** %fptrptr @@ -24,8 +24,7 @@ define void @call(i8* %obj) { ret void } -declare i1 @llvm.bitset.test(i8*, metadata) +declare i1 @llvm.type.test(i8*, metadata) declare void @llvm.assume(i1) -!0 = !{!"bitset", i8** @vt, i32 0} -!llvm.bitsets = !{!0} +!0 = !{i32 0, !"typeid"} diff --git a/llvm/test/Transforms/WholeProgramDevirt/non-constant-vtable.ll b/llvm/test/Transforms/WholeProgramDevirt/non-constant-vtable.ll index 394f5e6c37a..f66409093c4 100644 --- a/llvm/test/Transforms/WholeProgramDevirt/non-constant-vtable.ll +++ b/llvm/test/Transforms/WholeProgramDevirt/non-constant-vtable.ll @@ -3,7 +3,7 @@ target datalayout = "e-p:64:64" target triple = "x86_64-unknown-linux-gnu" -@vt = global [1 x i8*] [i8* bitcast (void (i8*)* @vf to i8*)] +@vt = global [1 x i8*] [i8* bitcast (void (i8*)* @vf to i8*)], !type !0 define void @vf(i8* %this) { ret void @@ -14,7 +14,7 @@ define void @call(i8* %obj) { %vtableptr = bitcast i8* %obj to [1 x i8*]** %vtable = load [1 x i8*]*, [1 x i8*]** %vtableptr %vtablei8 = bitcast [1 x i8*]* %vtable to i8* - %p = call i1 @llvm.bitset.test(i8* %vtablei8, metadata !"bitset") + %p = call i1 @llvm.type.test(i8* %vtablei8, metadata !"typeid") call void @llvm.assume(i1 %p) %fptrptr = getelementptr [1 x i8*], [1 x i8*]* %vtable, i32 0, i32 0 %fptr = load i8*, i8** %fptrptr @@ -24,8 +24,7 @@ define void @call(i8* %obj) { ret void } -declare i1 @llvm.bitset.test(i8*, metadata) +declare i1 @llvm.type.test(i8*, metadata) declare void @llvm.assume(i1) -!0 = !{!"bitset", [1 x i8*]* @vt, i32 0} -!llvm.bitsets = !{!0} +!0 = !{i32 0, !"typeid"} diff --git a/llvm/test/Transforms/WholeProgramDevirt/uniform-retval-invoke.ll b/llvm/test/Transforms/WholeProgramDevirt/uniform-retval-invoke.ll index d34a529daa4..8fea9bc7b24 100644 --- a/llvm/test/Transforms/WholeProgramDevirt/uniform-retval-invoke.ll +++ b/llvm/test/Transforms/WholeProgramDevirt/uniform-retval-invoke.ll @@ -3,8 +3,8 @@ target datalayout = "e-p:64:64" target triple = "x86_64-unknown-linux-gnu" -@vt1 = constant [1 x i8*] [i8* bitcast (i32 (i8*)* @vf1 to i8*)] -@vt2 = constant [1 x i8*] [i8* bitcast (i32 (i8*)* @vf2 to i8*)] +@vt1 = constant [1 x i8*] [i8* bitcast (i32 (i8*)* @vf1 to i8*)], !type !0 +@vt2 = constant [1 x i8*] [i8* bitcast (i32 (i8*)* @vf2 to i8*)], !type !0 define i32 @vf1(i8* %this) readnone { ret i32 123 @@ -19,7 +19,7 @@ define i32 @call(i8* %obj) personality i8* undef { %vtableptr = bitcast i8* %obj to [1 x i8*]** %vtable = load [1 x i8*]*, [1 x i8*]** %vtableptr %vtablei8 = bitcast [1 x i8*]* %vtable to i8* - %p = call i1 @llvm.bitset.test(i8* %vtablei8, metadata !"bitset") + %p = call i1 @llvm.type.test(i8* %vtablei8, metadata !"typeid") call void @llvm.assume(i1 %p) %fptrptr = getelementptr [1 x i8*], [1 x i8*]* %vtable, i32 0, i32 0 %fptr = load i8*, i8** %fptrptr @@ -37,9 +37,7 @@ ret: ret i32 %result } -declare i1 @llvm.bitset.test(i8*, metadata) +declare i1 @llvm.type.test(i8*, metadata) declare void @llvm.assume(i1) -!0 = !{!"bitset", [1 x i8*]* @vt1, i32 0} -!1 = !{!"bitset", [1 x i8*]* @vt2, i32 0} -!llvm.bitsets = !{!0, !1} +!0 = !{i32 0, !"typeid"} diff --git a/llvm/test/Transforms/WholeProgramDevirt/uniform-retval.ll b/llvm/test/Transforms/WholeProgramDevirt/uniform-retval.ll index f6433c32aba..ef3a7e49b52 100644 --- a/llvm/test/Transforms/WholeProgramDevirt/uniform-retval.ll +++ b/llvm/test/Transforms/WholeProgramDevirt/uniform-retval.ll @@ -3,8 +3,8 @@ target datalayout = "e-p:64:64" target triple = "x86_64-unknown-linux-gnu" -@vt1 = constant [1 x i8*] [i8* bitcast (i32 (i8*)* @vf1 to i8*)] -@vt2 = constant [1 x i8*] [i8* bitcast (i32 (i8*)* @vf2 to i8*)] +@vt1 = constant [1 x i8*] [i8* bitcast (i32 (i8*)* @vf1 to i8*)], !type !0 +@vt2 = constant [1 x i8*] [i8* bitcast (i32 (i8*)* @vf2 to i8*)], !type !0 define i32 @vf1(i8* %this) readnone { ret i32 123 @@ -19,7 +19,7 @@ define i32 @call(i8* %obj) { %vtableptr = bitcast i8* %obj to [1 x i8*]** %vtable = load [1 x i8*]*, [1 x i8*]** %vtableptr %vtablei8 = bitcast [1 x i8*]* %vtable to i8* - %p = call i1 @llvm.bitset.test(i8* %vtablei8, metadata !"bitset") + %p = call i1 @llvm.type.test(i8* %vtablei8, metadata !"typeid") call void @llvm.assume(i1 %p) %fptrptr = getelementptr [1 x i8*], [1 x i8*]* %vtable, i32 0, i32 0 %fptr = load i8*, i8** %fptrptr @@ -30,9 +30,7 @@ define i32 @call(i8* %obj) { ret i32 %result } -declare i1 @llvm.bitset.test(i8*, metadata) +declare i1 @llvm.type.test(i8*, metadata) declare void @llvm.assume(i1) -!0 = !{!"bitset", [1 x i8*]* @vt1, i32 0} -!1 = !{!"bitset", [1 x i8*]* @vt2, i32 0} -!llvm.bitsets = !{!0, !1} +!0 = !{i32 0, !"typeid"} diff --git a/llvm/test/Transforms/WholeProgramDevirt/unique-retval.ll b/llvm/test/Transforms/WholeProgramDevirt/unique-retval.ll index 41aa3e59e8a..50b938c43e4 100644 --- a/llvm/test/Transforms/WholeProgramDevirt/unique-retval.ll +++ b/llvm/test/Transforms/WholeProgramDevirt/unique-retval.ll @@ -3,10 +3,10 @@ target datalayout = "e-p:64:64" target triple = "x86_64-unknown-linux-gnu" -@vt1 = constant [1 x i8*] [i8* bitcast (i1 (i8*)* @vf0 to i8*)] -@vt2 = constant [1 x i8*] [i8* bitcast (i1 (i8*)* @vf0 to i8*)] -@vt3 = constant [1 x i8*] [i8* bitcast (i1 (i8*)* @vf1 to i8*)] -@vt4 = constant [1 x i8*] [i8* bitcast (i1 (i8*)* @vf1 to i8*)] +@vt1 = constant [1 x i8*] [i8* bitcast (i1 (i8*)* @vf0 to i8*)], !type !0 +@vt2 = constant [1 x i8*] [i8* bitcast (i1 (i8*)* @vf0 to i8*)], !type !0, !type !1 +@vt3 = constant [1 x i8*] [i8* bitcast (i1 (i8*)* @vf1 to i8*)], !type !0, !type !1 +@vt4 = constant [1 x i8*] [i8* bitcast (i1 (i8*)* @vf1 to i8*)], !type !1 define i1 @vf0(i8* %this) readnone { ret i1 0 @@ -22,7 +22,7 @@ define i1 @call1(i8* %obj) { %vtable = load [1 x i8*]*, [1 x i8*]** %vtableptr ; CHECK: [[VT1:%[^ ]*]] = bitcast [1 x i8*]* {{.*}} to i8* %vtablei8 = bitcast [1 x i8*]* %vtable to i8* - %p = call i1 @llvm.bitset.test(i8* %vtablei8, metadata !"bitset1") + %p = call i1 @llvm.type.test(i8* %vtablei8, metadata !"typeid1") call void @llvm.assume(i1 %p) %fptrptr = getelementptr [1 x i8*], [1 x i8*]* %vtable, i32 0, i32 0 %fptr = load i8*, i8** %fptrptr @@ -39,7 +39,7 @@ define i1 @call2(i8* %obj) { %vtable = load [1 x i8*]*, [1 x i8*]** %vtableptr ; CHECK: [[VT2:%[^ ]*]] = bitcast [1 x i8*]* {{.*}} to i8* %vtablei8 = bitcast [1 x i8*]* %vtable to i8* - %p = call i1 @llvm.bitset.test(i8* %vtablei8, metadata !"bitset2") + %p = call i1 @llvm.type.test(i8* %vtablei8, metadata !"typeid2") call void @llvm.assume(i1 %p) %fptrptr = getelementptr [1 x i8*], [1 x i8*]* %vtable, i32 0, i32 0 %fptr = load i8*, i8** %fptrptr @@ -49,13 +49,8 @@ define i1 @call2(i8* %obj) { ret i1 %result } -declare i1 @llvm.bitset.test(i8*, metadata) +declare i1 @llvm.type.test(i8*, metadata) declare void @llvm.assume(i1) -!0 = !{!"bitset1", [1 x i8*]* @vt1, i32 0} -!1 = !{!"bitset1", [1 x i8*]* @vt2, i32 0} -!2 = !{!"bitset1", [1 x i8*]* @vt3, i32 0} -!3 = !{!"bitset2", [1 x i8*]* @vt2, i32 0} -!4 = !{!"bitset2", [1 x i8*]* @vt3, i32 0} -!5 = !{!"bitset2", [1 x i8*]* @vt4, i32 0} -!llvm.bitsets = !{!0, !1, !2, !3, !4, !5} +!0 = !{i32 0, !"typeid1"} +!1 = !{i32 0, !"typeid2"} diff --git a/llvm/test/Transforms/WholeProgramDevirt/vcp-accesses-memory.ll b/llvm/test/Transforms/WholeProgramDevirt/vcp-accesses-memory.ll index f963d18e164..b5d51f2d463 100644 --- a/llvm/test/Transforms/WholeProgramDevirt/vcp-accesses-memory.ll +++ b/llvm/test/Transforms/WholeProgramDevirt/vcp-accesses-memory.ll @@ -3,8 +3,8 @@ target datalayout = "e-p:64:64" target triple = "x86_64-unknown-linux-gnu" -@vt1 = global [1 x i8*] [i8* bitcast (i32 (i8*, i32)* @vf1 to i8*)] -@vt2 = global [1 x i8*] [i8* bitcast (i32 (i8*, i32)* @vf2 to i8*)] +@vt1 = global [1 x i8*] [i8* bitcast (i32 (i8*, i32)* @vf1 to i8*)], !type !0 +@vt2 = global [1 x i8*] [i8* bitcast (i32 (i8*, i32)* @vf2 to i8*)], !type !0 define i32 @vf1(i8* %this, i32 %arg) { ret i32 %arg @@ -19,7 +19,7 @@ define i32 @call(i8* %obj) { %vtableptr = bitcast i8* %obj to [1 x i8*]** %vtable = load [1 x i8*]*, [1 x i8*]** %vtableptr %vtablei8 = bitcast [1 x i8*]* %vtable to i8* - %p = call i1 @llvm.bitset.test(i8* %vtablei8, metadata !"bitset") + %p = call i1 @llvm.type.test(i8* %vtablei8, metadata !"typeid") call void @llvm.assume(i1 %p) %fptrptr = getelementptr [1 x i8*], [1 x i8*]* %vtable, i32 0, i32 0 %fptr = load i8*, i8** %fptrptr @@ -29,9 +29,7 @@ define i32 @call(i8* %obj) { ret i32 %result } -declare i1 @llvm.bitset.test(i8*, metadata) +declare i1 @llvm.type.test(i8*, metadata) declare void @llvm.assume(i1) -!0 = !{!"bitset", [1 x i8*]* @vt1, i32 0} -!1 = !{!"bitset", [1 x i8*]* @vt2, i32 0} -!llvm.bitsets = !{!0} +!0 = !{i32 0, !"typeid"} diff --git a/llvm/test/Transforms/WholeProgramDevirt/vcp-no-this.ll b/llvm/test/Transforms/WholeProgramDevirt/vcp-no-this.ll index 28d39e169e8..c564665471c 100644 --- a/llvm/test/Transforms/WholeProgramDevirt/vcp-no-this.ll +++ b/llvm/test/Transforms/WholeProgramDevirt/vcp-no-this.ll @@ -3,8 +3,8 @@ target datalayout = "e-p:64:64" target triple = "x86_64-unknown-linux-gnu" -@vt1 = global [1 x i8*] [i8* bitcast (i32 ()* @vf1 to i8*)] -@vt2 = global [1 x i8*] [i8* bitcast (i32 ()* @vf2 to i8*)] +@vt1 = global [1 x i8*] [i8* bitcast (i32 ()* @vf1 to i8*)], !type !0 +@vt2 = global [1 x i8*] [i8* bitcast (i32 ()* @vf2 to i8*)], !type !0 define i32 @vf1() readnone { ret i32 1 @@ -19,7 +19,7 @@ define i32 @call(i8* %obj) { %vtableptr = bitcast i8* %obj to [1 x i8*]** %vtable = load [1 x i8*]*, [1 x i8*]** %vtableptr %vtablei8 = bitcast [1 x i8*]* %vtable to i8* - %p = call i1 @llvm.bitset.test(i8* %vtablei8, metadata !"bitset") + %p = call i1 @llvm.type.test(i8* %vtablei8, metadata !"typeid") call void @llvm.assume(i1 %p) %fptrptr = getelementptr [1 x i8*], [1 x i8*]* %vtable, i32 0, i32 0 %fptr = load i8*, i8** %fptrptr @@ -29,9 +29,7 @@ define i32 @call(i8* %obj) { ret i32 %result } -declare i1 @llvm.bitset.test(i8*, metadata) +declare i1 @llvm.type.test(i8*, metadata) declare void @llvm.assume(i1) -!0 = !{!"bitset", [1 x i8*]* @vt1, i32 0} -!1 = !{!"bitset", [1 x i8*]* @vt2, i32 0} -!llvm.bitsets = !{!0} +!0 = !{i32 0, !"typeid"} diff --git a/llvm/test/Transforms/WholeProgramDevirt/vcp-non-constant-arg.ll b/llvm/test/Transforms/WholeProgramDevirt/vcp-non-constant-arg.ll index c056832de6d..197c923c3a1 100644 --- a/llvm/test/Transforms/WholeProgramDevirt/vcp-non-constant-arg.ll +++ b/llvm/test/Transforms/WholeProgramDevirt/vcp-non-constant-arg.ll @@ -3,8 +3,8 @@ target datalayout = "e-p:64:64" target triple = "x86_64-unknown-linux-gnu" -@vt1 = global [1 x i8*] [i8* bitcast (i32 (i8*, i32)* @vf1 to i8*)] -@vt2 = global [1 x i8*] [i8* bitcast (i32 (i8*, i32)* @vf2 to i8*)] +@vt1 = global [1 x i8*] [i8* bitcast (i32 (i8*, i32)* @vf1 to i8*)], !type !0 +@vt2 = global [1 x i8*] [i8* bitcast (i32 (i8*, i32)* @vf2 to i8*)], !type !0 define i32 @vf1(i8* %this, i32 %arg) readnone { ret i32 %arg @@ -19,7 +19,7 @@ define void @call(i8* %obj, i32 %arg) { %vtableptr = bitcast i8* %obj to [1 x i8*]** %vtable = load [1 x i8*]*, [1 x i8*]** %vtableptr %vtablei8 = bitcast [1 x i8*]* %vtable to i8* - %p = call i1 @llvm.bitset.test(i8* %vtablei8, metadata !"bitset") + %p = call i1 @llvm.type.test(i8* %vtablei8, metadata !"typeid") call void @llvm.assume(i1 %p) %fptrptr = getelementptr [1 x i8*], [1 x i8*]* %vtable, i32 0, i32 0 %fptr = load i8*, i8** %fptrptr @@ -29,9 +29,7 @@ define void @call(i8* %obj, i32 %arg) { ret void } -declare i1 @llvm.bitset.test(i8*, metadata) +declare i1 @llvm.type.test(i8*, metadata) declare void @llvm.assume(i1) -!0 = !{!"bitset", [1 x i8*]* @vt1, i32 0} -!1 = !{!"bitset", [1 x i8*]* @vt2, i32 0} -!llvm.bitsets = !{!0} +!0 = !{i32 0, !"typeid"} diff --git a/llvm/test/Transforms/WholeProgramDevirt/vcp-too-wide-ints.ll b/llvm/test/Transforms/WholeProgramDevirt/vcp-too-wide-ints.ll index 4dbbc1b458b..93936d5e1d2 100644 --- a/llvm/test/Transforms/WholeProgramDevirt/vcp-too-wide-ints.ll +++ b/llvm/test/Transforms/WholeProgramDevirt/vcp-too-wide-ints.ll @@ -3,8 +3,8 @@ target datalayout = "e-p:64:64" target triple = "x86_64-unknown-linux-gnu" -@vt1 = global [1 x i8*] [i8* bitcast (i128 (i8*, i128)* @vf1 to i8*)] -@vt2 = global [1 x i8*] [i8* bitcast (i128 (i8*, i128)* @vf2 to i8*)] +@vt1 = global [1 x i8*] [i8* bitcast (i128 (i8*, i128)* @vf1 to i8*)], !type !0 +@vt2 = global [1 x i8*] [i8* bitcast (i128 (i8*, i128)* @vf2 to i8*)], !type !0 define i128 @vf1(i8* %this, i128 %arg) readnone { ret i128 %arg @@ -19,7 +19,7 @@ define i128 @call(i8* %obj) { %vtableptr = bitcast i8* %obj to [1 x i8*]** %vtable = load [1 x i8*]*, [1 x i8*]** %vtableptr %vtablei8 = bitcast [1 x i8*]* %vtable to i8* - %p = call i1 @llvm.bitset.test(i8* %vtablei8, metadata !"bitset") + %p = call i1 @llvm.type.test(i8* %vtablei8, metadata !"typeid") call void @llvm.assume(i1 %p) %fptrptr = getelementptr [1 x i8*], [1 x i8*]* %vtable, i32 0, i32 0 %fptr = load i8*, i8** %fptrptr @@ -29,9 +29,7 @@ define i128 @call(i8* %obj) { ret i128 %result } -declare i1 @llvm.bitset.test(i8*, metadata) +declare i1 @llvm.type.test(i8*, metadata) declare void @llvm.assume(i1) -!0 = !{!"bitset", [1 x i8*]* @vt1, i32 0} -!1 = !{!"bitset", [1 x i8*]* @vt2, i32 0} -!llvm.bitsets = !{!0} +!0 = !{i32 0, !"typeid"} diff --git a/llvm/test/Transforms/WholeProgramDevirt/vcp-type-mismatch.ll b/llvm/test/Transforms/WholeProgramDevirt/vcp-type-mismatch.ll index 6dff4d17a2b..3124889a707 100644 --- a/llvm/test/Transforms/WholeProgramDevirt/vcp-type-mismatch.ll +++ b/llvm/test/Transforms/WholeProgramDevirt/vcp-type-mismatch.ll @@ -3,8 +3,8 @@ target datalayout = "e-p:64:64" target triple = "x86_64-unknown-linux-gnu" -@vt1 = global [1 x i8*] [i8* bitcast (i32 (i8*, i32)* @vf1 to i8*)] -@vt2 = global [1 x i8*] [i8* bitcast (i32 (i8*, i32)* @vf2 to i8*)] +@vt1 = global [1 x i8*] [i8* bitcast (i32 (i8*, i32)* @vf1 to i8*)], !type !0 +@vt2 = global [1 x i8*] [i8* bitcast (i32 (i8*, i32)* @vf2 to i8*)], !type !0 define i32 @vf1(i8* %this, i32 %arg) readnone { ret i32 %arg @@ -19,7 +19,7 @@ define i32 @bad_arg_type(i8* %obj) { %vtableptr = bitcast i8* %obj to [1 x i8*]** %vtable = load [1 x i8*]*, [1 x i8*]** %vtableptr %vtablei8 = bitcast [1 x i8*]* %vtable to i8* - %p = call i1 @llvm.bitset.test(i8* %vtablei8, metadata !"bitset") + %p = call i1 @llvm.type.test(i8* %vtablei8, metadata !"typeid") call void @llvm.assume(i1 %p) %fptrptr = getelementptr [1 x i8*], [1 x i8*]* %vtable, i32 0, i32 0 %fptr = load i8*, i8** %fptrptr @@ -34,7 +34,7 @@ define i32 @bad_arg_count(i8* %obj) { %vtableptr = bitcast i8* %obj to [1 x i8*]** %vtable = load [1 x i8*]*, [1 x i8*]** %vtableptr %vtablei8 = bitcast [1 x i8*]* %vtable to i8* - %p = call i1 @llvm.bitset.test(i8* %vtablei8, metadata !"bitset") + %p = call i1 @llvm.type.test(i8* %vtablei8, metadata !"typeid") call void @llvm.assume(i1 %p) %fptrptr = getelementptr [1 x i8*], [1 x i8*]* %vtable, i32 0, i32 0 %fptr = load i8*, i8** %fptrptr @@ -49,7 +49,7 @@ define i64 @bad_return_type(i8* %obj) { %vtableptr = bitcast i8* %obj to [1 x i8*]** %vtable = load [1 x i8*]*, [1 x i8*]** %vtableptr %vtablei8 = bitcast [1 x i8*]* %vtable to i8* - %p = call i1 @llvm.bitset.test(i8* %vtablei8, metadata !"bitset") + %p = call i1 @llvm.type.test(i8* %vtablei8, metadata !"typeid") call void @llvm.assume(i1 %p) %fptrptr = getelementptr [1 x i8*], [1 x i8*]* %vtable, i32 0, i32 0 %fptr = load i8*, i8** %fptrptr @@ -59,9 +59,7 @@ define i64 @bad_return_type(i8* %obj) { ret i64 %result } -declare i1 @llvm.bitset.test(i8*, metadata) +declare i1 @llvm.type.test(i8*, metadata) declare void @llvm.assume(i1) -!0 = !{!"bitset", [1 x i8*]* @vt1, i32 0} -!1 = !{!"bitset", [1 x i8*]* @vt2, i32 0} -!llvm.bitsets = !{!0} +!0 = !{i32 0, !"typeid"} diff --git a/llvm/test/Transforms/WholeProgramDevirt/vcp-uses-this.ll b/llvm/test/Transforms/WholeProgramDevirt/vcp-uses-this.ll index 39a63c62f44..fc4dee37dba 100644 --- a/llvm/test/Transforms/WholeProgramDevirt/vcp-uses-this.ll +++ b/llvm/test/Transforms/WholeProgramDevirt/vcp-uses-this.ll @@ -3,8 +3,8 @@ target datalayout = "e-p:64:64" target triple = "x86_64-unknown-linux-gnu" -@vt1 = global [1 x i8*] [i8* bitcast (i32 (i8*)* @vf1 to i8*)] -@vt2 = global [1 x i8*] [i8* bitcast (i32 (i8*)* @vf2 to i8*)] +@vt1 = global [1 x i8*] [i8* bitcast (i32 (i8*)* @vf1 to i8*)], !type !0 +@vt2 = global [1 x i8*] [i8* bitcast (i32 (i8*)* @vf2 to i8*)], !type !0 define i32 @vf1(i8* %this) readnone { %this_int = ptrtoint i8* %this to i32 @@ -21,7 +21,7 @@ define i32 @call(i8* %obj) { %vtableptr = bitcast i8* %obj to [1 x i8*]** %vtable = load [1 x i8*]*, [1 x i8*]** %vtableptr %vtablei8 = bitcast [1 x i8*]* %vtable to i8* - %p = call i1 @llvm.bitset.test(i8* %vtablei8, metadata !"bitset") + %p = call i1 @llvm.type.test(i8* %vtablei8, metadata !"typeid") call void @llvm.assume(i1 %p) %fptrptr = getelementptr [1 x i8*], [1 x i8*]* %vtable, i32 0, i32 0 %fptr = load i8*, i8** %fptrptr @@ -31,9 +31,7 @@ define i32 @call(i8* %obj) { ret i32 %result } -declare i1 @llvm.bitset.test(i8*, metadata) +declare i1 @llvm.type.test(i8*, metadata) declare void @llvm.assume(i1) -!0 = !{!"bitset", [1 x i8*]* @vt1, i32 0} -!1 = !{!"bitset", [1 x i8*]* @vt2, i32 0} -!llvm.bitsets = !{!0} +!0 = !{i32 0, !"typeid"} diff --git a/llvm/test/Transforms/WholeProgramDevirt/virtual-const-prop-begin.ll b/llvm/test/Transforms/WholeProgramDevirt/virtual-const-prop-begin.ll index 3686f8aca3e..f65b8a28288 100644 --- a/llvm/test/Transforms/WholeProgramDevirt/virtual-const-prop-begin.ll +++ b/llvm/test/Transforms/WholeProgramDevirt/virtual-const-prop-begin.ll @@ -8,34 +8,34 @@ target triple = "x86_64-unknown-linux-gnu" i8* bitcast (i1 (i8*)* @vf0i1 to i8*), i8* bitcast (i1 (i8*)* @vf1i1 to i8*), i8* bitcast (i32 (i8*)* @vf1i32 to i8*) -], section "vt1sec" +], section "vt1sec", !type !0 ; CHECK: [[VT2DATA:@[^ ]*]] = private constant { [8 x i8], [3 x i8*], [0 x i8] } { [8 x i8] c"\00\00\00\02\02\00\00\00", [3 x i8*] [i8* bitcast (i1 (i8*)* @vf1i1 to i8*), i8* bitcast (i1 (i8*)* @vf0i1 to i8*), i8* bitcast (i32 (i8*)* @vf2i32 to i8*)], [0 x i8] zeroinitializer }{{$}} @vt2 = constant [3 x i8*] [ i8* bitcast (i1 (i8*)* @vf1i1 to i8*), i8* bitcast (i1 (i8*)* @vf0i1 to i8*), i8* bitcast (i32 (i8*)* @vf2i32 to i8*) -] +], !type !0 ; CHECK: [[VT3DATA:@[^ ]*]] = private constant { [8 x i8], [3 x i8*], [0 x i8] } { [8 x i8] c"\00\00\00\01\03\00\00\00", [3 x i8*] [i8* bitcast (i1 (i8*)* @vf0i1 to i8*), i8* bitcast (i1 (i8*)* @vf1i1 to i8*), i8* bitcast (i32 (i8*)* @vf3i32 to i8*)], [0 x i8] zeroinitializer }{{$}} @vt3 = constant [3 x i8*] [ i8* bitcast (i1 (i8*)* @vf0i1 to i8*), i8* bitcast (i1 (i8*)* @vf1i1 to i8*), i8* bitcast (i32 (i8*)* @vf3i32 to i8*) -] +], !type !0 ; CHECK: [[VT4DATA:@[^ ]*]] = private constant { [8 x i8], [3 x i8*], [0 x i8] } { [8 x i8] c"\00\00\00\02\04\00\00\00", [3 x i8*] [i8* bitcast (i1 (i8*)* @vf1i1 to i8*), i8* bitcast (i1 (i8*)* @vf0i1 to i8*), i8* bitcast (i32 (i8*)* @vf4i32 to i8*)], [0 x i8] zeroinitializer }{{$}} @vt4 = constant [3 x i8*] [ i8* bitcast (i1 (i8*)* @vf1i1 to i8*), i8* bitcast (i1 (i8*)* @vf0i1 to i8*), i8* bitcast (i32 (i8*)* @vf4i32 to i8*) -] +], !type !0 @vt5 = constant [3 x i8*] [ i8* bitcast (void ()* @__cxa_pure_virtual to i8*), i8* bitcast (void ()* @__cxa_pure_virtual to i8*), i8* bitcast (void ()* @__cxa_pure_virtual to i8*) -] +], !type !0 ; CHECK: @vt1 = alias [3 x i8*], getelementptr inbounds ({ [8 x i8], [3 x i8*], [0 x i8] }, { [8 x i8], [3 x i8*], [0 x i8] }* [[VT1DATA]], i32 0, i32 1) ; CHECK: @vt2 = alias [3 x i8*], getelementptr inbounds ({ [8 x i8], [3 x i8*], [0 x i8] }, { [8 x i8], [3 x i8*], [0 x i8] }* [[VT2DATA]], i32 0, i32 1) @@ -72,7 +72,7 @@ define i1 @call1(i8* %obj) { %vtable = load [3 x i8*]*, [3 x i8*]** %vtableptr ; CHECK: [[VT1:%[^ ]*]] = bitcast [3 x i8*]* {{.*}} to i8* %vtablei8 = bitcast [3 x i8*]* %vtable to i8* - %p = call i1 @llvm.bitset.test(i8* %vtablei8, metadata !"bitset") + %p = call i1 @llvm.type.test(i8* %vtablei8, metadata !"typeid") call void @llvm.assume(i1 %p) %fptrptr = getelementptr [3 x i8*], [3 x i8*]* %vtable, i32 0, i32 0 %fptr = load i8*, i8** %fptrptr @@ -92,7 +92,7 @@ define i1 @call2(i8* %obj) { %vtable = load [3 x i8*]*, [3 x i8*]** %vtableptr ; CHECK: [[VT2:%[^ ]*]] = bitcast [3 x i8*]* {{.*}} to i8* %vtablei8 = bitcast [3 x i8*]* %vtable to i8* - %p = call i1 @llvm.bitset.test(i8* %vtablei8, metadata !"bitset") + %p = call i1 @llvm.type.test(i8* %vtablei8, metadata !"typeid") call void @llvm.assume(i1 %p) %fptrptr = getelementptr [3 x i8*], [3 x i8*]* %vtable, i32 0, i32 1 %fptr = load i8*, i8** %fptrptr @@ -112,7 +112,7 @@ define i32 @call3(i8* %obj) { %vtable = load [3 x i8*]*, [3 x i8*]** %vtableptr ; CHECK: [[VT3:%[^ ]*]] = bitcast [3 x i8*]* {{.*}} to i8* %vtablei8 = bitcast [3 x i8*]* %vtable to i8* - %p = call i1 @llvm.bitset.test(i8* %vtablei8, metadata !"bitset") + %p = call i1 @llvm.type.test(i8* %vtablei8, metadata !"typeid") call void @llvm.assume(i1 %p) %fptrptr = getelementptr [3 x i8*], [3 x i8*]* %vtable, i32 0, i32 2 %fptr = load i8*, i8** %fptrptr @@ -125,13 +125,8 @@ define i32 @call3(i8* %obj) { ret i32 %result } -declare i1 @llvm.bitset.test(i8*, metadata) +declare i1 @llvm.type.test(i8*, metadata) declare void @llvm.assume(i1) declare void @__cxa_pure_virtual() -!0 = !{!"bitset", [3 x i8*]* @vt1, i32 0} -!1 = !{!"bitset", [3 x i8*]* @vt2, i32 0} -!2 = !{!"bitset", [3 x i8*]* @vt3, i32 0} -!3 = !{!"bitset", [3 x i8*]* @vt4, i32 0} -!4 = !{!"bitset", [3 x i8*]* @vt5, i32 0} -!llvm.bitsets = !{!0, !1, !2, !3, !4} +!0 = !{i32 0, !"typeid"} diff --git a/llvm/test/Transforms/WholeProgramDevirt/virtual-const-prop-end.ll b/llvm/test/Transforms/WholeProgramDevirt/virtual-const-prop-end.ll index 44608cf67a3..04c89ddb026 100644 --- a/llvm/test/Transforms/WholeProgramDevirt/virtual-const-prop-end.ll +++ b/llvm/test/Transforms/WholeProgramDevirt/virtual-const-prop-end.ll @@ -9,14 +9,14 @@ i8* null, i8* bitcast (i1 (i8*)* @vf0i1 to i8*), i8* bitcast (i1 (i8*)* @vf1i1 to i8*), i8* bitcast (i32 (i8*)* @vf1i32 to i8*) -] +], !type !1 ; CHECK: [[VT2DATA:@[^ ]*]] = private constant { [0 x i8], [3 x i8*], [8 x i8] } { [0 x i8] zeroinitializer, [3 x i8*] [i8* bitcast (i1 (i8*)* @vf1i1 to i8*), i8* bitcast (i1 (i8*)* @vf0i1 to i8*), i8* bitcast (i32 (i8*)* @vf2i32 to i8*)], [8 x i8] c"\02\00\00\00\02\00\00\00" } @vt2 = constant [3 x i8*] [ i8* bitcast (i1 (i8*)* @vf1i1 to i8*), i8* bitcast (i1 (i8*)* @vf0i1 to i8*), i8* bitcast (i32 (i8*)* @vf2i32 to i8*) -] +], !type !0 ; CHECK: [[VT3DATA:@[^ ]*]] = private constant { [0 x i8], [4 x i8*], [8 x i8] } { [0 x i8] zeroinitializer, [4 x i8*] [i8* null, i8* bitcast (i1 (i8*)* @vf0i1 to i8*), i8* bitcast (i1 (i8*)* @vf1i1 to i8*), i8* bitcast (i32 (i8*)* @vf3i32 to i8*)], [8 x i8] c"\03\00\00\00\01\00\00\00" } @vt3 = constant [4 x i8*] [ @@ -24,14 +24,14 @@ i8* null, i8* bitcast (i1 (i8*)* @vf0i1 to i8*), i8* bitcast (i1 (i8*)* @vf1i1 to i8*), i8* bitcast (i32 (i8*)* @vf3i32 to i8*) -] +], !type !1 ; CHECK: [[VT4DATA:@[^ ]*]] = private constant { [0 x i8], [3 x i8*], [8 x i8] } { [0 x i8] zeroinitializer, [3 x i8*] [i8* bitcast (i1 (i8*)* @vf1i1 to i8*), i8* bitcast (i1 (i8*)* @vf0i1 to i8*), i8* bitcast (i32 (i8*)* @vf4i32 to i8*)], [8 x i8] c"\04\00\00\00\02\00\00\00" } @vt4 = constant [3 x i8*] [ i8* bitcast (i1 (i8*)* @vf1i1 to i8*), i8* bitcast (i1 (i8*)* @vf0i1 to i8*), i8* bitcast (i32 (i8*)* @vf4i32 to i8*) -] +], !type !0 ; CHECK: @vt1 = alias [4 x i8*], getelementptr inbounds ({ [0 x i8], [4 x i8*], [8 x i8] }, { [0 x i8], [4 x i8*], [8 x i8] }* [[VT1DATA]], i32 0, i32 1) ; CHECK: @vt2 = alias [3 x i8*], getelementptr inbounds ({ [0 x i8], [3 x i8*], [8 x i8] }, { [0 x i8], [3 x i8*], [8 x i8] }* [[VT2DATA]], i32 0, i32 1) @@ -68,7 +68,7 @@ define i1 @call1(i8* %obj) { %vtable = load [3 x i8*]*, [3 x i8*]** %vtableptr ; CHECK: [[VT1:%[^ ]*]] = bitcast [3 x i8*]* {{.*}} to i8* %vtablei8 = bitcast [3 x i8*]* %vtable to i8* - %p = call i1 @llvm.bitset.test(i8* %vtablei8, metadata !"bitset") + %p = call i1 @llvm.type.test(i8* %vtablei8, metadata !"typeid") call void @llvm.assume(i1 %p) %fptrptr = getelementptr [3 x i8*], [3 x i8*]* %vtable, i32 0, i32 0 %fptr = load i8*, i8** %fptrptr @@ -88,7 +88,7 @@ define i1 @call2(i8* %obj) { %vtable = load [3 x i8*]*, [3 x i8*]** %vtableptr ; CHECK: [[VT2:%[^ ]*]] = bitcast [3 x i8*]* {{.*}} to i8* %vtablei8 = bitcast [3 x i8*]* %vtable to i8* - %p = call i1 @llvm.bitset.test(i8* %vtablei8, metadata !"bitset") + %p = call i1 @llvm.type.test(i8* %vtablei8, metadata !"typeid") call void @llvm.assume(i1 %p) %fptrptr = getelementptr [3 x i8*], [3 x i8*]* %vtable, i32 0, i32 1 %fptr = load i8*, i8** %fptrptr @@ -108,7 +108,7 @@ define i32 @call3(i8* %obj) { %vtable = load [3 x i8*]*, [3 x i8*]** %vtableptr ; CHECK: [[VT3:%[^ ]*]] = bitcast [3 x i8*]* {{.*}} to i8* %vtablei8 = bitcast [3 x i8*]* %vtable to i8* - %p = call i1 @llvm.bitset.test(i8* %vtablei8, metadata !"bitset") + %p = call i1 @llvm.type.test(i8* %vtablei8, metadata !"typeid") call void @llvm.assume(i1 %p) %fptrptr = getelementptr [3 x i8*], [3 x i8*]* %vtable, i32 0, i32 2 %fptr = load i8*, i8** %fptrptr @@ -121,11 +121,8 @@ define i32 @call3(i8* %obj) { ret i32 %result } -declare i1 @llvm.bitset.test(i8*, metadata) +declare i1 @llvm.type.test(i8*, metadata) declare void @llvm.assume(i1) -!0 = !{!"bitset", [4 x i8*]* @vt1, i32 8} -!1 = !{!"bitset", [3 x i8*]* @vt2, i32 0} -!2 = !{!"bitset", [4 x i8*]* @vt3, i32 8} -!3 = !{!"bitset", [3 x i8*]* @vt4, i32 0} -!llvm.bitsets = !{!0, !1, !2, !3} +!0 = !{i32 0, !"typeid"} +!1 = !{i32 8, !"typeid"} diff --git a/llvm/test/tools/gold/X86/opt-level.ll b/llvm/test/tools/gold/X86/opt-level.ll index 3deb0af37a7..a3cd844a142 100644 --- a/llvm/test/tools/gold/X86/opt-level.ll +++ b/llvm/test/tools/gold/X86/opt-level.ll @@ -34,17 +34,18 @@ end: ret i32 %r } -define void @baz() { +define i1 @baz() { call void @foo() %c = call i32 @bar(i1 true) - ret void + %p = call i1 @llvm.type.test(i8* undef, metadata !"typeid1") + ret i1 %p } -@a = constant i32 1 +; CHECK-O0-NOT: !type +; CHECK-O1-NOT: !type +; CHECK-O2-NOT: !type +@a = constant i32 1, !type !0 -!0 = !{!"bitset1", i32* @a, i32 0} +!0 = !{i32 0, !"typeid1"} -; CHECK-O0-NOT: llvm.bitsets -; CHECK-O1-NOT: llvm.bitsets -; CHECK-O2-NOT: llvm.bitsets -!llvm.bitsets = !{ !0 } +declare i1 @llvm.type.test(i8* %ptr, metadata %bitset) nounwind readnone diff --git a/llvm/unittests/Transforms/IPO/CMakeLists.txt b/llvm/unittests/Transforms/IPO/CMakeLists.txt index 445f70354e7..ee33a5fcd1b 100644 --- a/llvm/unittests/Transforms/IPO/CMakeLists.txt +++ b/llvm/unittests/Transforms/IPO/CMakeLists.txt @@ -5,6 +5,6 @@ set(LLVM_LINK_COMPONENTS ) add_llvm_unittest(IPOTests - LowerBitSets.cpp + LowerTypeTests.cpp WholeProgramDevirt.cpp ) diff --git a/llvm/unittests/Transforms/IPO/LowerBitSets.cpp b/llvm/unittests/Transforms/IPO/LowerTypeTests.cpp index d3ee27d7e94..66c9de6bd66 100644 --- a/llvm/unittests/Transforms/IPO/LowerBitSets.cpp +++ b/llvm/unittests/Transforms/IPO/LowerTypeTests.cpp @@ -1,4 +1,4 @@ -//===- LowerBitSets.cpp - Unit tests for bitset lowering ------------------===// +//===- LowerTypeTests.cpp - Unit tests for type test lowering -------------===// // // The LLVM Compiler Infrastructure // @@ -7,13 +7,13 @@ // //===----------------------------------------------------------------------===// -#include "llvm/Transforms/IPO/LowerBitSets.h" +#include "llvm/Transforms/IPO/LowerTypeTests.h" #include "gtest/gtest.h" using namespace llvm; -using namespace lowerbitsets; +using namespace lowertypetests; -TEST(LowerBitSets, BitSetBuilder) { +TEST(LowerTypeTests, BitSetBuilder) { struct { std::vector<uint64_t> Offsets; std::set<uint64_t> Bits; @@ -80,7 +80,7 @@ TEST(LowerBitSets, BitSetBuilder) { } } -TEST(LowerBitSets, GlobalLayoutBuilder) { +TEST(LowerTypeTests, GlobalLayoutBuilder) { struct { uint64_t NumObjects; std::vector<std::set<uint64_t>> Fragments; @@ -107,7 +107,7 @@ TEST(LowerBitSets, GlobalLayoutBuilder) { } } -TEST(LowerBitSets, ByteArrayBuilder) { +TEST(LowerTypeTests, ByteArrayBuilder) { struct BABAlloc { std::set<uint64_t> Bits; uint64_t BitSize; diff --git a/llvm/unittests/Transforms/IPO/WholeProgramDevirt.cpp b/llvm/unittests/Transforms/IPO/WholeProgramDevirt.cpp index 794863b0a91..7e7a6bf4596 100644 --- a/llvm/unittests/Transforms/IPO/WholeProgramDevirt.cpp +++ b/llvm/unittests/Transforms/IPO/WholeProgramDevirt.cpp @@ -25,11 +25,11 @@ TEST(WholeProgramDevirt, findLowestOffset) { VT2.Before.BytesUsed = {1 << 1}; VT2.After.BytesUsed = {1 << 0}; - BitSetInfo BS1{&VT1, 0}; - BitSetInfo BS2{&VT2, 0}; + TypeMemberInfo TM1{&VT1, 0}; + TypeMemberInfo TM2{&VT2, 0}; VirtualCallTarget Targets[] = { - {&BS1, /*IsBigEndian=*/false}, - {&BS2, /*IsBigEndian=*/false}, + {&TM1, /*IsBigEndian=*/false}, + {&TM2, /*IsBigEndian=*/false}, }; EXPECT_EQ(2ull, findLowestOffset(Targets, /*IsAfter=*/false, 1)); @@ -38,15 +38,15 @@ TEST(WholeProgramDevirt, findLowestOffset) { EXPECT_EQ(8ull, findLowestOffset(Targets, /*IsAfter=*/false, 8)); EXPECT_EQ(72ull, findLowestOffset(Targets, /*IsAfter=*/true, 8)); - BS1.Offset = 4; + TM1.Offset = 4; EXPECT_EQ(33ull, findLowestOffset(Targets, /*IsAfter=*/false, 1)); EXPECT_EQ(65ull, findLowestOffset(Targets, /*IsAfter=*/true, 1)); EXPECT_EQ(40ull, findLowestOffset(Targets, /*IsAfter=*/false, 8)); EXPECT_EQ(72ull, findLowestOffset(Targets, /*IsAfter=*/true, 8)); - BS1.Offset = 8; - BS2.Offset = 8; + TM1.Offset = 8; + TM2.Offset = 8; EXPECT_EQ(66ull, findLowestOffset(Targets, /*IsAfter=*/false, 1)); EXPECT_EQ(2ull, findLowestOffset(Targets, /*IsAfter=*/true, 1)); @@ -66,15 +66,15 @@ TEST(WholeProgramDevirt, setReturnValues) { VTableBits VT2; VT2.ObjectSize = 8; - BitSetInfo BS1{&VT1, 0}; - BitSetInfo BS2{&VT2, 0}; + TypeMemberInfo TM1{&VT1, 0}; + TypeMemberInfo TM2{&VT2, 0}; VirtualCallTarget Targets[] = { - {&BS1, /*IsBigEndian=*/false}, - {&BS2, /*IsBigEndian=*/false}, + {&TM1, /*IsBigEndian=*/false}, + {&TM2, /*IsBigEndian=*/false}, }; - BS1.Offset = 4; - BS2.Offset = 4; + TM1.Offset = 4; + TM2.Offset = 4; int64_t OffsetByte; uint64_t OffsetBit; |