+++ /dev/null
-=======
-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
!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
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
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:
::
- 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
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
--- /dev/null
+=============
+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
CoverageMappingFormat
Statepoints
MergeFunctions
- BitSets
+ TypeMetadata
FaultMaps
MIRLangRef
-//===- BitSetUtils.h - Utilities related to pointer bitsets ------*- C++ -*-==//
+//===- TypeMetadataUtils.h - Utilities related to type metadata --*- C++ -*-==//
//
// The LLVM Compiler Infrastructure
//
//
//===----------------------------------------------------------------------===//
//
-// 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"
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,
namespace llvm {
class Comdat;
class MDNode;
+class Metadata;
class Module;
class GlobalObject : public GlobalValue {
/// 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;
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]>;
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
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&);
/// 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();
-//===- LowerBitSets.h - Bitset lowering pass --------------------*- C++ -*-===//
+//===- LowerTypeTests.h - type metadata lowering pass -----------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
//
//===----------------------------------------------------------------------===//
//
-// 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"
class Value;
class raw_ostream;
-namespace lowerbitsets {
+namespace lowertypetests {
struct BitSetInfo {
// The indices of the set bits in the bitset.
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
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.
// 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.
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);
}
};
Analysis.cpp
AssumptionCache.cpp
BasicAliasAnalysis.cpp
- BitSetUtils.cpp
BlockFrequencyInfo.cpp
BlockFrequencyInfoImpl.cpp
BranchProbabilityInfo.cpp
TargetTransformInfo.cpp
Trace.cpp
TypeBasedAliasAnalysis.cpp
+ TypeMetadataUtils.cpp
ScopedNoAliasAA.cpp
ValueTracking.cpp
VectorUtils.cpp
-//===- BitSetUtils.cpp - Utilities related to pointer bitsets -------------===//
+//===- TypeMetadataUtils.cpp - Utilities related to type metadata ---------===//
//
// The LLVM Compiler Infrastructure
//
//
//===----------------------------------------------------------------------===//
//
-// 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"
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) {
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!");
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) {
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
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);
Inliner.cpp
Internalize.cpp
LoopExtractor.cpp
- LowerBitSets.cpp
+ LowerTypeTests.cpp
MergeFunctions.cpp
PartialInlining.cpp
PassManagerBuilder.cpp
#define DEBUG_TYPE "cross-dso-cfi"
-STATISTIC(TypeIds, "Number of unique type identifiers");
+STATISTIC(NumTypeIds, "Number of unique type identifiers");
namespace {
Module *M;
MDNode *VeryLikelyWeights;
- ConstantInt *extractBitSetTypeId(MDNode *MD);
+ ConstantInt *extractNumericTypeId(MDNode *MD);
void buildCFICheck();
bool doInitialization(Module &M) override;
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());
// 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(
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(
BI->setMetadata(LLVMContext::MD_prof, VeryLikelyWeights);
SI->addCase(CaseTypeId, TestBB);
- ++TypeIds;
+ ++NumTypeIds;
}
}
initializeLoopExtractorPass(Registry);
initializeBlockExtractorPassPass(Registry);
initializeSingleLoopExtractorPass(Registry);
- initializeLowerBitSetsPass(Registry);
+ initializeLowerTypeTestsPass(Registry);
initializeMergeFunctionsPass(Registry);
initializePartialInlinerPass(Registry);
initializePostOrderFunctionAttrsLegacyPassPass(Registry);
-//===-- LowerBitSets.cpp - Bitset lowering pass ---------------------------===//
+//===-- LowerTypeTests.cpp - type metadata lowering pass ------------------===//
//
// The LLVM Compiler Infrastructure
//
//
//===----------------------------------------------------------------------===//
//
-// 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"
#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));
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;
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;
} // 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();
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);
}
}
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.
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;
/// 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.
}
}
-/// 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) {
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
// 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
}
}
-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());
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);
}
}
-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");
// 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");
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");
/*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
// 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
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.
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();
});
// 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.
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());
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);
}
// 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();
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();
}
// 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);
//===----------------------------------------------------------------------===//
//
// 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.
#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"
// 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();
}
}
-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;
};
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;
}
};
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(
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;
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.
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);
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 =
}
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));
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;
// 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
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;
; 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
}
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}
+++ /dev/null
-; 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
-}
+++ /dev/null
-; 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
-}
+++ /dev/null
-; 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
-}
+++ /dev/null
-; 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 = !{}
+++ /dev/null
-; 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
-}
--- /dev/null
+; 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
+}
-; 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"}
-; 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.
; 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
}
--- /dev/null
+; 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
+}
-; 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.
; 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
}
--- /dev/null
+; 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 = !{}
; 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"
; 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"}
-; 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]*}}
; 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*
; 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
; 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
; 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
-; 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
}
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
}
--- /dev/null
+; 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
+}
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
%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**
%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**
%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**
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"}
; 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
%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
%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
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"}
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
%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
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"}
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
%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
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"}
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
%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
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"}
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
%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
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"}
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
%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
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"}
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
%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
%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
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"}
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
%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
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"}
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
%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
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"}
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
%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
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"}
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
%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
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"}
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
%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
%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
%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
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"}
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
%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
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"}
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)
%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
%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
%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
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"}
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*] [
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)
%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
%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
%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
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"}
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
)
add_llvm_unittest(IPOTests
- LowerBitSets.cpp
+ LowerTypeTests.cpp
WholeProgramDevirt.cpp
)
-//===- LowerBitSets.cpp - Unit tests for bitset lowering ------------------===//
+//===- LowerTypeTests.cpp - Unit tests for type test lowering -------------===//
//
// The LLVM Compiler Infrastructure
//
//
//===----------------------------------------------------------------------===//
-#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;
}
}
-TEST(LowerBitSets, GlobalLayoutBuilder) {
+TEST(LowerTypeTests, GlobalLayoutBuilder) {
struct {
uint64_t NumObjects;
std::vector<std::set<uint64_t>> Fragments;
}
}
-TEST(LowerBitSets, ByteArrayBuilder) {
+TEST(LowerTypeTests, ByteArrayBuilder) {
struct BABAlloc {
std::set<uint64_t> Bits;
uint64_t BitSize;
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));
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));
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;