226 changes: 226 additions & 0 deletions llvm/docs/TypeMetadata.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,226 @@
=============
Type Metadata
=============

Type metadata is a mechanism that allows IR modules to co-operatively build
pointer sets corresponding to addresses within a given set of globals. LLVM's
`control flow integrity`_ implementation uses this metadata to efficiently
check (at each call site) that a given address corresponds to either a
valid vtable or function pointer for a given class or function type, and its
whole-program devirtualization pass uses the metadata to identify potential
callees for a given virtual call.

To use the mechanism, a client creates metadata nodes with two elements:

1. a byte offset into the global (generally zero for functions)
2. a metadata object representing an identifier for the type

These metadata nodes are associated with globals by using global object
metadata attachments with the ``!type`` metadata kind.

Each type identifier must exclusively identify either global variables
or functions.

.. admonition:: Limitation

The current implementation only supports attaching metadata to functions on
the x86-32 and x86-64 architectures.

An intrinsic, :ref:`llvm.type.test <type.test>`, is used to test whether a
given pointer is associated with a type identifier.

.. _control flow integrity: http://clang.llvm.org/docs/ControlFlowIntegrity.html

Representing Type Information using Type Metadata
=================================================

This section describes how Clang represents C++ type information associated with
virtual tables using type metadata.

Consider the following inheritance hierarchy:

.. code-block:: c++

struct A {
virtual void f();
};

struct B : A {
virtual void f();
virtual void g();
};

struct C {
virtual void h();
};

struct D : A, C {
virtual void f();
virtual void h();
};

The virtual table objects for A, B, C and D look like this (under the Itanium ABI):

.. csv-table:: Virtual Table Layout for A, B, C, D
:header: Class, 0, 1, 2, 3, 4, 5, 6

A, A::offset-to-top, &A::rtti, &A::f
B, B::offset-to-top, &B::rtti, &B::f, &B::g
C, C::offset-to-top, &C::rtti, &C::h
D, D::offset-to-top, &D::rtti, &D::f, &D::h, D::offset-to-top, &D::rtti, thunk for &D::h

When an object of type A is constructed, the address of ``&A::f`` in A's
virtual table object is stored in the object's vtable pointer. In ABI parlance
this address is known as an `address point`_. Similarly, when an object of type
B is constructed, the address of ``&B::f`` is stored in the vtable pointer. In
this way, the vtable in B's virtual table object is compatible with A's vtable.

D is a little more complicated, due to the use of multiple inheritance. Its
virtual table object contains two vtables, one compatible with A's vtable and
the other compatible with C's vtable. Objects of type D contain two virtual
pointers, one belonging to the A subobject and containing the address of
the vtable compatible with A's vtable, and the other belonging to the C
subobject and containing the address of the vtable compatible with C's vtable.

The full set of compatibility information for the above class hierarchy is
shown below. The following table shows the name of a class, the offset of an
address point within that class's vtable and the name of one of the classes
with which that address point is compatible.

.. csv-table:: Type Offsets for A, B, C, D
:header: VTable for, Offset, Compatible Class

A, 16, A
B, 16, A
, , B
C, 16, C
D, 16, A
, , D
, 48, C

The next step is to encode this compatibility information into the IR. The way
this is done is to create type metadata named after each of the compatible
classes, with which we associate each of the compatible address points in
each vtable. For example, these type metadata entries encode the compatibility
information for the above hierarchy:

::

@_ZTV1A = constant [...], !type !0
@_ZTV1B = constant [...], !type !0, !type !1
@_ZTV1C = constant [...], !type !2
@_ZTV1D = constant [...], !type !0, !type !3, !type !4

!0 = !{i64 16, !"_ZTS1A"}
!1 = !{i64 16, !"_ZTS1B"}
!2 = !{i64 16, !"_ZTS1C"}
!3 = !{i64 16, !"_ZTS1D"}
!4 = !{i64 48, !"_ZTS1C"}

With this type metadata, we can now use the ``llvm.type.test`` intrinsic to
test whether a given pointer is compatible with a type identifier. Working
backwards, if ``llvm.type.test`` returns true for a particular pointer,
we can also statically determine the identities of the virtual functions
that a particular virtual call may call. For example, if a program assumes
a pointer to be a member of ``!"_ZST1A"``, we know that the address can
be only be one of ``_ZTV1A+16``, ``_ZTV1B+16`` or ``_ZTV1D+16`` (i.e. the
address points of the vtables of A, B and D respectively). If we then load
an address from that pointer, we know that the address can only be one of
``&A::f``, ``&B::f`` or ``&D::f``.

.. _address point: https://mentorembedded.github.io/cxx-abi/abi.html#vtable-general

Testing Addresses For Type Membership
=====================================

If a program tests an address using ``llvm.type.test``, this will cause
a link-time optimization pass, ``LowerTypeTests``, to replace calls to this
intrinsic with efficient code to perform type member tests. At a high level,
the pass will lay out referenced globals in a consecutive memory region in
the object file, construct bit vectors that map onto that memory region,
and generate code at each of the ``llvm.type.test`` call sites to test
pointers against those bit vectors. Because of the layout manipulation, the
globals' definitions must be available at LTO time. For more information,
see the `control flow integrity design document`_.

A type identifier that identifies functions is transformed into a jump table,
which is a block of code consisting of one branch instruction for each
of the functions associated with the type identifier that branches to the
target function. The pass will redirect any taken function addresses to the
corresponding jump table entry. In the object file's symbol table, the jump
table entries take the identities of the original functions, so that addresses
taken outside the module will pass any verification done inside the module.

Jump tables may call external functions, so their definitions need not
be available at LTO time. Note that if an externally defined function is
associated with a type identifier, there is no guarantee that its identity
within the module will be the same as its identity outside of the module,
as the former will be the jump table entry if a jump table is necessary.

The `GlobalLayoutBuilder`_ class is responsible for laying out the globals
efficiently to minimize the sizes of the underlying bitsets.

.. _control flow integrity design document: http://clang.llvm.org/docs/ControlFlowIntegrityDesign.html

:Example:

::

target datalayout = "e-p:32:32"

@a = internal global i32 0, !type !0
@b = internal global i32 0, !type !0, !type !1
@c = internal global i32 0, !type !1
@d = internal global [2 x i32] [i32 0, i32 0], !type !2

define void @e() !type !3 {
ret void
}

define void @f() {
ret void
}

declare void @g() !type !3

!0 = !{i32 0, !"typeid1"}
!1 = !{i32 0, !"typeid2"}
!2 = !{i32 4, !"typeid2"}
!3 = !{i32 0, !"typeid3"}

declare i1 @llvm.type.test(i8* %ptr, metadata %typeid) nounwind readnone

define i1 @foo(i32* %p) {
%pi8 = bitcast i32* %p to i8*
%x = call i1 @llvm.type.test(i8* %pi8, metadata !"typeid1")
ret i1 %x
}

define i1 @bar(i32* %p) {
%pi8 = bitcast i32* %p to i8*
%x = call i1 @llvm.type.test(i8* %pi8, metadata !"typeid2")
ret i1 %x
}

define i1 @baz(void ()* %p) {
%pi8 = bitcast void ()* %p to i8*
%x = call i1 @llvm.type.test(i8* %pi8, metadata !"typeid3")
ret i1 %x
}

define void @main() {
%a1 = call i1 @foo(i32* @a) ; returns 1
%b1 = call i1 @foo(i32* @b) ; returns 1
%c1 = call i1 @foo(i32* @c) ; returns 0
%a2 = call i1 @bar(i32* @a) ; returns 0
%b2 = call i1 @bar(i32* @b) ; returns 1
%c2 = call i1 @bar(i32* @c) ; returns 1
%d02 = call i1 @bar(i32* getelementptr ([2 x i32]* @d, i32 0, i32 0)) ; returns 0
%d12 = call i1 @bar(i32* getelementptr ([2 x i32]* @d, i32 0, i32 1)) ; returns 1
%e = call i1 @baz(void ()* @e) ; returns 1
%f = call i1 @baz(void ()* @f) ; returns 0
%g = call i1 @baz(void ()* @g) ; returns 1
ret void
}

.. _GlobalLayoutBuilder: http://llvm.org/klaus/llvm/blob/master/include/llvm/Transforms/IPO/LowerTypeTests.h
2 changes: 1 addition & 1 deletion llvm/docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,7 @@ For API clients and LLVM developers.
CoverageMappingFormat
Statepoints
MergeFunctions
BitSets
TypeMetadata
FaultMaps
MIRLangRef

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//===- BitSetUtils.h - Utilities related to pointer bitsets ------*- C++ -*-==//
//===- TypeMetadataUtils.h - Utilities related to type metadata --*- C++ -*-==//
//
// The LLVM Compiler Infrastructure
//
Expand All @@ -7,13 +7,13 @@
//
//===----------------------------------------------------------------------===//
//
// This file contains functions that make it easier to manipulate bitsets for
// devirtualization.
// This file contains functions that make it easier to manipulate type metadata
// for devirtualization.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_ANALYSIS_BITSETUTILS_H
#define LLVM_ANALYSIS_BITSETUTILS_H
#ifndef LLVM_ANALYSIS_TYPEMETADATAUTILS_H
#define LLVM_ANALYSIS_TYPEMETADATAUTILS_H

#include "llvm/ADT/SmallVector.h"
#include "llvm/IR/CallSite.h"
Expand All @@ -28,7 +28,7 @@ struct DevirtCallSite {
CallSite CS;
};

/// Given a call to the intrinsic @llvm.bitset.test, find all devirtualizable
/// Given a call to the intrinsic @llvm.type.test, find all devirtualizable
/// call sites based on the call and return them in DevirtCalls.
void findDevirtualizableCalls(SmallVectorImpl<DevirtCallSite> &DevirtCalls,
SmallVectorImpl<CallInst *> &Assumes,
Expand Down
7 changes: 5 additions & 2 deletions llvm/include/llvm/IR/GlobalObject.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
namespace llvm {
class Comdat;
class MDNode;
class Metadata;
class Module;

class GlobalObject : public GlobalValue {
Expand Down Expand Up @@ -114,8 +115,10 @@ 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;

Expand Down
6 changes: 3 additions & 3 deletions llvm/include/llvm/IR/Intrinsics.td
Original file line number Diff line number Diff line change
Expand Up @@ -663,9 +663,9 @@ def int_masked_scatter: Intrinsic<[],
LLVMVectorSameWidth<0, llvm_i1_ty>],
[IntrArgMemOnly]>;

// Intrinsics to support bit sets.
def int_bitset_test : Intrinsic<[llvm_i1_ty], [llvm_ptr_ty, llvm_metadata_ty],
[IntrNoMem]>;
// Test whether a pointer is associated with a type metadata identifier.
def int_type_test : Intrinsic<[llvm_i1_ty], [llvm_ptr_ty, llvm_metadata_ty],
[IntrNoMem]>;

def int_load_relative: Intrinsic<[llvm_ptr_ty], [llvm_ptr_ty, llvm_anyint_ty],
[IntrReadMem, IntrArgMemOnly]>;
Expand Down
1 change: 1 addition & 0 deletions llvm/include/llvm/IR/LLVMContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ class LLVMContext {
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
Expand Down
2 changes: 1 addition & 1 deletion llvm/include/llvm/InitializePasses.h
Original file line number Diff line number Diff line change
Expand Up @@ -192,13 +192,13 @@ void initializeLoopVectorizePass(PassRegistry&);
void initializeLoopVersioningLICMPass(PassRegistry&);
void initializeLoopVersioningPassPass(PassRegistry &);
void initializeLowerAtomicLegacyPassPass(PassRegistry &);
void initializeLowerBitSetsPass(PassRegistry&);
void initializeLowerEmuTLSPass(PassRegistry&);
void initializeLowerExpectIntrinsicPass(PassRegistry&);
void initializeLowerGuardIntrinsicPass(PassRegistry&);
void initializeLowerIntrinsicsPass(PassRegistry&);
void initializeLowerInvokePass(PassRegistry&);
void initializeLowerSwitchPass(PassRegistry&);
void initializeLowerTypeTestsPass(PassRegistry&);
void initializeMIRPrintingPassPass(PassRegistry&);
void initializeMachineBlockFrequencyInfoPass(PassRegistry&);
void initializeMachineBlockPlacementPass(PassRegistry&);
Expand Down
8 changes: 4 additions & 4 deletions llvm/include/llvm/Transforms/IPO.h
Original file line number Diff line number Diff line change
Expand Up @@ -214,14 +214,14 @@ ModulePass *createMetaRenamerPass();
/// manager.
ModulePass *createBarrierNoopPass();

/// \brief This pass lowers bitset metadata and the llvm.bitset.test intrinsic
/// to bitsets.
ModulePass *createLowerBitSetsPass();
/// \brief This pass lowers type metadata and the llvm.type.test intrinsic to
/// bitsets.
ModulePass *createLowerTypeTestsPass();

/// \brief This pass export CFI checks for use by external modules.
ModulePass *createCrossDSOCFIPass();

/// \brief This pass implements whole-program devirtualization using bitset
/// \brief This pass implements whole-program devirtualization using type
/// metadata.
ModulePass *createWholeProgramDevirtPass();

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//===- LowerBitSets.h - Bitset lowering pass --------------------*- C++ -*-===//
//===- LowerTypeTests.h - type metadata lowering pass -----------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
Expand All @@ -7,13 +7,13 @@
//
//===----------------------------------------------------------------------===//
//
// This file defines parts of the bitset lowering pass implementation that may
// be usefully unit tested.
// This file defines parts of the type test lowering pass implementation that
// may be usefully unit tested.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_TRANSFORMS_IPO_LOWERBITSETS_H
#define LLVM_TRANSFORMS_IPO_LOWERBITSETS_H
#ifndef LLVM_TRANSFORMS_IPO_LOWERTYPETESTS_H
#define LLVM_TRANSFORMS_IPO_LOWERTYPETESTS_H

#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallVector.h"
Expand All @@ -31,7 +31,7 @@ class GlobalObject;
class Value;
class raw_ostream;

namespace lowerbitsets {
namespace lowertypetests {

struct BitSetInfo {
// The indices of the set bits in the bitset.
Expand Down Expand Up @@ -199,7 +199,7 @@ struct ByteArrayBuilder {
uint64_t &AllocByteOffset, uint8_t &AllocMask);
};

} // end namespace lowerbitsets
} // end namespace lowertypetests
} // end namespace llvm

#endif // LLVM_TRANSFORMS_IPO_LOWERBITSETS_H
#endif // LLVM_TRANSFORMS_IPO_LOWERTYPETESTS_H
37 changes: 19 additions & 18 deletions llvm/include/llvm/Transforms/IPO/WholeProgramDevirt.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,32 +99,33 @@ struct VTableBits {
AccumBitVector After;
};

// Information about an entry in a particular bitset.
struct BitSetInfo {
// Information about a member of a particular type identifier.
struct TypeMemberInfo {
// The VTableBits for the vtable.
VTableBits *Bits;

// The offset in bytes from the start of the vtable (i.e. the address point).
uint64_t Offset;

bool operator<(const BitSetInfo &other) const {
bool operator<(const TypeMemberInfo &other) const {
return Bits < other.Bits || (Bits == other.Bits && Offset < other.Offset);
}
};

// A virtual call target, i.e. an entry in a particular vtable.
struct VirtualCallTarget {
VirtualCallTarget(Function *Fn, const BitSetInfo *BS);
VirtualCallTarget(Function *Fn, const TypeMemberInfo *TM);

// For testing only.
VirtualCallTarget(const BitSetInfo *BS, bool IsBigEndian)
: Fn(nullptr), BS(BS), IsBigEndian(IsBigEndian) {}
VirtualCallTarget(const TypeMemberInfo *TM, bool IsBigEndian)
: Fn(nullptr), TM(TM), IsBigEndian(IsBigEndian) {}

// The function stored in the vtable.
Function *Fn;

// A pointer to the bitset through which the pointer to Fn is accessed.
const BitSetInfo *BS;
// A pointer to the type identifier member through which the pointer to Fn is
// accessed.
const TypeMemberInfo *TM;

// When doing virtual constant propagation, this stores the return value for
// the function when passed the currently considered argument list.
Expand All @@ -137,37 +138,37 @@ struct VirtualCallTarget {
// the vtable object before the address point (e.g. RTTI, access-to-top,
// vtables for other base classes) and is equal to the offset from the start
// of the vtable object to the address point.
uint64_t minBeforeBytes() const { return BS->Offset; }
uint64_t minBeforeBytes() const { return TM->Offset; }

// The minimum byte offset after the address point. This covers the bytes in
// the vtable object after the address point (e.g. the vtable for the current
// class and any later base classes) and is equal to the size of the vtable
// object minus the offset from the start of the vtable object to the address
// point.
uint64_t minAfterBytes() const { return BS->Bits->ObjectSize - BS->Offset; }
uint64_t minAfterBytes() const { return TM->Bits->ObjectSize - TM->Offset; }

// The number of bytes allocated (for the vtable plus the byte array) before
// the address point.
uint64_t allocatedBeforeBytes() const {
return minBeforeBytes() + BS->Bits->Before.Bytes.size();
return minBeforeBytes() + TM->Bits->Before.Bytes.size();
}

// The number of bytes allocated (for the vtable plus the byte array) after
// the address point.
uint64_t allocatedAfterBytes() const {
return minAfterBytes() + BS->Bits->After.Bytes.size();
return minAfterBytes() + TM->Bits->After.Bytes.size();
}

// Set the bit at position Pos before the address point to RetVal.
void setBeforeBit(uint64_t Pos) {
assert(Pos >= 8 * minBeforeBytes());
BS->Bits->Before.setBit(Pos - 8 * minBeforeBytes(), RetVal);
TM->Bits->Before.setBit(Pos - 8 * minBeforeBytes(), RetVal);
}

// Set the bit at position Pos after the address point to RetVal.
void setAfterBit(uint64_t Pos) {
assert(Pos >= 8 * minAfterBytes());
BS->Bits->After.setBit(Pos - 8 * minAfterBytes(), RetVal);
TM->Bits->After.setBit(Pos - 8 * minAfterBytes(), RetVal);
}

// Set the bytes at position Pos before the address point to RetVal.
Expand All @@ -176,18 +177,18 @@ struct VirtualCallTarget {
void setBeforeBytes(uint64_t Pos, uint8_t Size) {
assert(Pos >= 8 * minBeforeBytes());
if (IsBigEndian)
BS->Bits->Before.setLE(Pos - 8 * minBeforeBytes(), RetVal, Size);
TM->Bits->Before.setLE(Pos - 8 * minBeforeBytes(), RetVal, Size);
else
BS->Bits->Before.setBE(Pos - 8 * minBeforeBytes(), RetVal, Size);
TM->Bits->Before.setBE(Pos - 8 * minBeforeBytes(), RetVal, Size);
}

// Set the bytes at position Pos after the address point to RetVal.
void setAfterBytes(uint64_t Pos, uint8_t Size) {
assert(Pos >= 8 * minAfterBytes());
if (IsBigEndian)
BS->Bits->After.setBE(Pos - 8 * minAfterBytes(), RetVal, Size);
TM->Bits->After.setBE(Pos - 8 * minAfterBytes(), RetVal, Size);
else
BS->Bits->After.setLE(Pos - 8 * minAfterBytes(), RetVal, Size);
TM->Bits->After.setLE(Pos - 8 * minAfterBytes(), RetVal, Size);
}
};

Expand Down
2 changes: 1 addition & 1 deletion llvm/lib/Analysis/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ add_llvm_library(LLVMAnalysis
Analysis.cpp
AssumptionCache.cpp
BasicAliasAnalysis.cpp
BitSetUtils.cpp
BlockFrequencyInfo.cpp
BlockFrequencyInfoImpl.cpp
BranchProbabilityInfo.cpp
Expand Down Expand Up @@ -71,6 +70,7 @@ add_llvm_library(LLVMAnalysis
TargetTransformInfo.cpp
Trace.cpp
TypeBasedAliasAnalysis.cpp
TypeMetadataUtils.cpp
ScopedNoAliasAA.cpp
ValueTracking.cpp
VectorUtils.cpp
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//===- BitSetUtils.cpp - Utilities related to pointer bitsets -------------===//
//===- TypeMetadataUtils.cpp - Utilities related to type metadata ---------===//
//
// The LLVM Compiler Infrastructure
//
Expand All @@ -7,12 +7,12 @@
//
//===----------------------------------------------------------------------===//
//
// This file contains functions that make it easier to manipulate bitsets for
// devirtualization.
// This file contains functions that make it easier to manipulate type metadata
// for devirtualization.
//
//===----------------------------------------------------------------------===//

#include "llvm/Analysis/BitSetUtils.h"
#include "llvm/Analysis/TypeMetadataUtils.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/Module.h"

Expand Down Expand Up @@ -60,11 +60,11 @@ findLoadCallsAtConstantOffset(Module *M,
void llvm::findDevirtualizableCalls(
SmallVectorImpl<DevirtCallSite> &DevirtCalls,
SmallVectorImpl<CallInst *> &Assumes, CallInst *CI) {
assert(CI->getCalledFunction()->getIntrinsicID() == Intrinsic::bitset_test);
assert(CI->getCalledFunction()->getIntrinsicID() == Intrinsic::type_test);

Module *M = CI->getParent()->getParent()->getParent();

// Find llvm.assume intrinsics for this llvm.bitset.test call.
// Find llvm.assume intrinsics for this llvm.type.test call.
for (const Use &CIU : CI->uses()) {
auto AssumeCI = dyn_cast<CallInst>(CIU.getUser());
if (AssumeCI) {
Expand Down
4 changes: 4 additions & 0 deletions llvm/lib/IR/LLVMContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,10 @@ LLVMContext::LLVMContext() : pImpl(new LLVMContextImpl(*this)) {
assert(LoopID == MD_loop && "llvm.loop kind id drifted");
(void)LoopID;

unsigned TypeID = getMDKindID("type");
assert(TypeID == MD_type && "type kind id drifted");
(void)TypeID;

auto *DeoptEntry = pImpl->getOrInsertBundleTag("deopt");
assert(DeoptEntry->second == LLVMContext::OB_deopt &&
"deopt operand bundle id drifted!");
Expand Down
25 changes: 23 additions & 2 deletions llvm/lib/IR/Metadata.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1393,11 +1393,32 @@ MDNode *GlobalObject::getMetadata(StringRef Kind) const {
return getMetadata(getContext().getMDKindID(Kind));
}

void GlobalObject::copyMetadata(const GlobalObject *Other) {
void GlobalObject::copyMetadata(const GlobalObject *Other, unsigned Offset) {
SmallVector<std::pair<unsigned, MDNode *>, 8> MDs;
Other->getAllMetadata(MDs);
for (auto &MD : MDs)
for (auto &MD : MDs) {
// We need to adjust the type metadata offset.
if (Offset != 0 && MD.first == LLVMContext::MD_type) {
auto *OffsetConst = cast<ConstantInt>(
cast<ConstantAsMetadata>(MD.second->getOperand(0))->getValue());
Metadata *TypeId = MD.second->getOperand(1);
auto *NewOffsetMD = ConstantAsMetadata::get(ConstantInt::get(
OffsetConst->getType(), OffsetConst->getValue() + Offset));
addMetadata(LLVMContext::MD_type,
*MDNode::get(getContext(), {NewOffsetMD, TypeId}));
continue;
}
addMetadata(MD.first, *MD.second);
}
}

void GlobalObject::addTypeMetadata(unsigned Offset, Metadata *TypeID) {
addMetadata(
LLVMContext::MD_type,
*MDTuple::get(getContext(),
{llvm::ConstantAsMetadata::get(llvm::ConstantInt::get(
Type::getInt64Ty(getContext()), Offset)),
TypeID}));
}

void Function::setSubprogram(DISubprogram *SP) {
Expand Down
4 changes: 2 additions & 2 deletions llvm/lib/Linker/IRMover.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -641,7 +641,7 @@ GlobalValue *IRLinker::copyGlobalValueProto(const GlobalValue *SGV,
if (auto *NewGO = dyn_cast<GlobalObject>(NewGV)) {
// Metadata for global variables and function declarations is copied eagerly.
if (isa<GlobalVariable>(SGV) || SGV->isDeclaration())
NewGO->copyMetadata(cast<GlobalObject>(SGV));
NewGO->copyMetadata(cast<GlobalObject>(SGV), 0);
}

// Remove these copied constants in case this stays a declaration, since
Expand Down Expand Up @@ -967,7 +967,7 @@ Error IRLinker::linkFunctionBody(Function &Dst, Function &Src) {
Dst.setPersonalityFn(Src.getPersonalityFn());

// Copy over the metadata attachments without remapping.
Dst.copyMetadata(&Src);
Dst.copyMetadata(&Src, 0);

// Steal arguments and splice the body of Src into Dst.
Dst.stealArgumentListFrom(Src);
Expand Down
2 changes: 1 addition & 1 deletion llvm/lib/Transforms/IPO/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ add_llvm_library(LLVMipo
Inliner.cpp
Internalize.cpp
LoopExtractor.cpp
LowerBitSets.cpp
LowerTypeTests.cpp
MergeFunctions.cpp
PartialInlining.cpp
PassManagerBuilder.cpp
Expand Down
51 changes: 24 additions & 27 deletions llvm/lib/Transforms/IPO/CrossDSOCFI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ using namespace llvm;

#define DEBUG_TYPE "cross-dso-cfi"

STATISTIC(TypeIds, "Number of unique type identifiers");
STATISTIC(NumTypeIds, "Number of unique type identifiers");

namespace {

Expand All @@ -49,7 +49,7 @@ struct CrossDSOCFI : public ModulePass {
Module *M;
MDNode *VeryLikelyWeights;

ConstantInt *extractBitSetTypeId(MDNode *MD);
ConstantInt *extractNumericTypeId(MDNode *MD);
void buildCFICheck();

bool doInitialization(Module &M) override;
Expand All @@ -73,40 +73,38 @@ bool CrossDSOCFI::doInitialization(Module &Mod) {
return false;
}

/// extractBitSetTypeId - Extracts TypeId from a hash-based bitset MDNode.
ConstantInt *CrossDSOCFI::extractBitSetTypeId(MDNode *MD) {
/// Extracts a numeric type identifier from an MDNode containing type metadata.
ConstantInt *CrossDSOCFI::extractNumericTypeId(MDNode *MD) {
// This check excludes vtables for classes inside anonymous namespaces.
auto TM = dyn_cast<ValueAsMetadata>(MD->getOperand(0));
auto TM = dyn_cast<ValueAsMetadata>(MD->getOperand(1));
if (!TM)
return nullptr;
auto C = dyn_cast_or_null<ConstantInt>(TM->getValue());
if (!C) return nullptr;
// 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(
Expand Down Expand Up @@ -138,13 +136,12 @@ void CrossDSOCFI::buildCFICheck() {
IRBExit.CreateRetVoid();

IRBuilder<> IRB(BB);
SwitchInst *SI = IRB.CreateSwitch(&CallSiteTypeId, TrapBB, BitSetIds.size());
for (uint64_t TypeId : BitSetIds) {
SwitchInst *SI = IRB.CreateSwitch(&CallSiteTypeId, TrapBB, TypeIds.size());
for (uint64_t TypeId : TypeIds) {
ConstantInt *CaseTypeId = ConstantInt::get(Type::getInt64Ty(Ctx), TypeId);
BasicBlock *TestBB = BasicBlock::Create(Ctx, "test", F);
IRBuilder<> IRBTest(TestBB);
Function *BitsetTestFn =
Intrinsic::getDeclaration(M, Intrinsic::bitset_test);
Function *BitsetTestFn = Intrinsic::getDeclaration(M, Intrinsic::type_test);

Value *Test = IRBTest.CreateCall(
BitsetTestFn, {&Addr, MetadataAsValue::get(
Expand All @@ -153,7 +150,7 @@ void CrossDSOCFI::buildCFICheck() {
BI->setMetadata(LLVMContext::MD_prof, VeryLikelyWeights);

SI->addCase(CaseTypeId, TestBB);
++TypeIds;
++NumTypeIds;
}
}

Expand Down
2 changes: 1 addition & 1 deletion llvm/lib/Transforms/IPO/IPO.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ void llvm::initializeIPO(PassRegistry &Registry) {
initializeLoopExtractorPass(Registry);
initializeBlockExtractorPassPass(Registry);
initializeSingleLoopExtractorPass(Registry);
initializeLowerBitSetsPass(Registry);
initializeLowerTypeTestsPass(Registry);
initializeMergeFunctionsPass(Registry);
initializePartialInlinerPass(Registry);
initializePostOrderFunctionAttrsLegacyPassPass(Registry);
Expand Down

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions llvm/lib/Transforms/IPO/PassManagerBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -748,10 +748,10 @@ void PassManagerBuilder::populateLTOPassManager(legacy::PassManagerBase &PM) {
// in the current module.
PM.add(createCrossDSOCFIPass());

// Lower bit sets to globals. This pass supports Clang's control flow
// integrity mechanisms (-fsanitize=cfi*) and needs to run at link time if CFI
// is enabled. The pass does nothing if CFI is disabled.
PM.add(createLowerBitSetsPass());
// Lower type metadata and the type.test intrinsic. This pass supports Clang's
// control flow integrity mechanisms (-fsanitize=cfi*) and needs to run at
// link time if CFI is enabled. The pass does nothing if CFI is disabled.
PM.add(createLowerTypeTestsPass());

if (OptLevel != 0)
addLateLTOOptimizationPasses(PM);
Expand Down
150 changes: 75 additions & 75 deletions llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
//===----------------------------------------------------------------------===//
//
// This pass implements whole program optimization of virtual calls in cases
// where we know (via bitset information) that the list of callee is fixed. This
// where we know (via !type metadata) that the list of callees is fixed. This
// includes the following:
// - Single implementation devirtualization: if a virtual call has a single
// possible callee, replace all calls with a direct call to that callee.
Expand All @@ -31,7 +31,7 @@
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/MapVector.h"
#include "llvm/Analysis/BitSetUtils.h"
#include "llvm/Analysis/TypeMetadataUtils.h"
#include "llvm/IR/CallSite.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DataLayout.h"
Expand Down Expand Up @@ -89,8 +89,8 @@ wholeprogramdevirt::findLowestOffset(ArrayRef<VirtualCallTarget> Targets,
// at MinByte.
std::vector<ArrayRef<uint8_t>> Used;
for (const VirtualCallTarget &Target : Targets) {
ArrayRef<uint8_t> VTUsed = IsAfter ? Target.BS->Bits->After.BytesUsed
: Target.BS->Bits->Before.BytesUsed;
ArrayRef<uint8_t> VTUsed = IsAfter ? Target.TM->Bits->After.BytesUsed
: Target.TM->Bits->Before.BytesUsed;
uint64_t Offset = IsAfter ? MinByte - Target.minAfterBytes()
: MinByte - Target.minBeforeBytes();

Expand Down Expand Up @@ -163,17 +163,17 @@ void wholeprogramdevirt::setAfterReturnValues(
}
}

VirtualCallTarget::VirtualCallTarget(Function *Fn, const BitSetInfo *BS)
: Fn(Fn), BS(BS),
VirtualCallTarget::VirtualCallTarget(Function *Fn, const TypeMemberInfo *TM)
: Fn(Fn), TM(TM),
IsBigEndian(Fn->getParent()->getDataLayout().isBigEndian()) {}

namespace {

// A slot in a set of virtual tables. The BitSetID identifies the set of virtual
// A slot in a set of virtual tables. The TypeID identifies the set of virtual
// tables, and the ByteOffset is the offset in bytes from the address point to
// the virtual function pointer.
struct VTableSlot {
Metadata *BitSetID;
Metadata *TypeID;
uint64_t ByteOffset;
};

Expand All @@ -191,12 +191,12 @@ template <> struct DenseMapInfo<VTableSlot> {
DenseMapInfo<uint64_t>::getTombstoneKey()};
}
static unsigned getHashValue(const VTableSlot &I) {
return DenseMapInfo<Metadata *>::getHashValue(I.BitSetID) ^
return DenseMapInfo<Metadata *>::getHashValue(I.TypeID) ^
DenseMapInfo<uint64_t>::getHashValue(I.ByteOffset);
}
static bool isEqual(const VTableSlot &LHS,
const VTableSlot &RHS) {
return LHS.BitSetID == RHS.BitSetID && LHS.ByteOffset == RHS.ByteOffset;
return LHS.TypeID == RHS.TypeID && LHS.ByteOffset == RHS.ByteOffset;
}
};

Expand Down Expand Up @@ -233,11 +233,13 @@ struct DevirtModule {
Int8PtrTy(Type::getInt8PtrTy(M.getContext())),
Int32Ty(Type::getInt32Ty(M.getContext())) {}

void buildBitSets(std::vector<VTableBits> &Bits,
DenseMap<Metadata *, std::set<BitSetInfo>> &BitSets);
bool tryFindVirtualCallTargets(std::vector<VirtualCallTarget> &TargetsForSlot,
const std::set<BitSetInfo> &BitSetInfos,
uint64_t ByteOffset);
void buildTypeIdentifierMap(
std::vector<VTableBits> &Bits,
DenseMap<Metadata *, std::set<TypeMemberInfo>> &TypeIdMap);
bool
tryFindVirtualCallTargets(std::vector<VirtualCallTarget> &TargetsForSlot,
const std::set<TypeMemberInfo> &TypeMemberInfos,
uint64_t ByteOffset);
bool trySingleImplDevirt(ArrayRef<VirtualCallTarget> TargetsForSlot,
MutableArrayRef<VirtualCallSite> CallSites);
bool tryEvaluateFunctionsWithArgs(
Expand Down Expand Up @@ -287,60 +289,55 @@ PreservedAnalyses WholeProgramDevirtPass::run(Module &M,
return PreservedAnalyses::none();
}

void DevirtModule::buildBitSets(
void DevirtModule::buildTypeIdentifierMap(
std::vector<VTableBits> &Bits,
DenseMap<Metadata *, std::set<BitSetInfo>> &BitSets) {
NamedMDNode *BitSetNM = M.getNamedMetadata("llvm.bitsets");
if (!BitSetNM)
return;

DenseMap<Metadata *, std::set<TypeMemberInfo>> &TypeIdMap) {
DenseMap<GlobalVariable *, VTableBits *> GVToBits;
Bits.reserve(BitSetNM->getNumOperands());
for (auto Op : BitSetNM->operands()) {
auto OpConstMD = dyn_cast_or_null<ConstantAsMetadata>(Op->getOperand(1));
if (!OpConstMD)
Bits.reserve(M.getGlobalList().size());
SmallVector<MDNode *, 2> Types;
for (GlobalVariable &GV : M.globals()) {
Types.clear();
GV.getMetadata(LLVMContext::MD_type, Types);
if (Types.empty())
continue;
auto BitSetID = Op->getOperand(0).get();

Constant *OpConst = OpConstMD->getValue();
if (auto GA = dyn_cast<GlobalAlias>(OpConst))
OpConst = GA->getAliasee();
auto OpGlobal = dyn_cast<GlobalVariable>(OpConst);
if (!OpGlobal)
continue;

uint64_t Offset =
cast<ConstantInt>(
cast<ConstantAsMetadata>(Op->getOperand(2))->getValue())
->getZExtValue();

VTableBits *&BitsPtr = GVToBits[OpGlobal];
VTableBits *&BitsPtr = GVToBits[&GV];
if (!BitsPtr) {
Bits.emplace_back();
Bits.back().GV = OpGlobal;
Bits.back().ObjectSize = M.getDataLayout().getTypeAllocSize(
OpGlobal->getInitializer()->getType());
Bits.back().GV = &GV;
Bits.back().ObjectSize =
M.getDataLayout().getTypeAllocSize(GV.getInitializer()->getType());
BitsPtr = &Bits.back();
}
BitSets[BitSetID].insert({BitsPtr, Offset});

for (MDNode *Type : Types) {
auto TypeID = Type->getOperand(1).get();

uint64_t Offset =
cast<ConstantInt>(
cast<ConstantAsMetadata>(Type->getOperand(0))->getValue())
->getZExtValue();

TypeIdMap[TypeID].insert({BitsPtr, Offset});
}
}
}

bool DevirtModule::tryFindVirtualCallTargets(
std::vector<VirtualCallTarget> &TargetsForSlot,
const std::set<BitSetInfo> &BitSetInfos, uint64_t ByteOffset) {
for (const BitSetInfo &BS : BitSetInfos) {
if (!BS.Bits->GV->isConstant())
const std::set<TypeMemberInfo> &TypeMemberInfos, uint64_t ByteOffset) {
for (const TypeMemberInfo &TM : TypeMemberInfos) {
if (!TM.Bits->GV->isConstant())
return false;

auto Init = dyn_cast<ConstantArray>(BS.Bits->GV->getInitializer());
auto Init = dyn_cast<ConstantArray>(TM.Bits->GV->getInitializer());
if (!Init)
return false;
ArrayType *VTableTy = Init->getType();

uint64_t ElemSize =
M.getDataLayout().getTypeAllocSize(VTableTy->getElementType());
uint64_t GlobalSlotOffset = BS.Offset + ByteOffset;
uint64_t GlobalSlotOffset = TM.Offset + ByteOffset;
if (GlobalSlotOffset % ElemSize != 0)
return false;

Expand All @@ -357,7 +354,7 @@ bool DevirtModule::tryFindVirtualCallTargets(
if (Fn->getName() == "__cxa_pure_virtual")
continue;

TargetsForSlot.push_back({Fn, &BS});
TargetsForSlot.push_back({Fn, &TM});
}

// Give up if we couldn't find any targets.
Expand Down Expand Up @@ -430,24 +427,24 @@ bool DevirtModule::tryUniqueRetValOpt(
MutableArrayRef<VirtualCallSite> CallSites) {
// IsOne controls whether we look for a 0 or a 1.
auto tryUniqueRetValOptFor = [&](bool IsOne) {
const BitSetInfo *UniqueBitSet = 0;
const TypeMemberInfo *UniqueMember = 0;
for (const VirtualCallTarget &Target : TargetsForSlot) {
if (Target.RetVal == (IsOne ? 1 : 0)) {
if (UniqueBitSet)
if (UniqueMember)
return false;
UniqueBitSet = Target.BS;
UniqueMember = Target.TM;
}
}

// We should have found a unique bit set or bailed out by now. We already
// We should have found a unique member or bailed out by now. We already
// checked for a uniform return value in tryUniformRetValOpt.
assert(UniqueBitSet);
assert(UniqueMember);

// Replace each call with the comparison.
for (auto &&Call : CallSites) {
IRBuilder<> B(Call.CS.getInstruction());
Value *OneAddr = B.CreateBitCast(UniqueBitSet->Bits->GV, Int8PtrTy);
OneAddr = B.CreateConstGEP1_64(OneAddr, UniqueBitSet->Offset);
Value *OneAddr = B.CreateBitCast(UniqueMember->Bits->GV, Int8PtrTy);
OneAddr = B.CreateConstGEP1_64(OneAddr, UniqueMember->Offset);
Value *Cmp = B.CreateICmp(IsOne ? ICmpInst::ICMP_EQ : ICmpInst::ICMP_NE,
Call.VTable, OneAddr);
Call.replaceAndErase(Cmp);
Expand Down Expand Up @@ -526,7 +523,8 @@ bool DevirtModule::tryVirtualConstProp(
if (tryUniqueRetValOpt(BitWidth, TargetsForSlot, CSByConstantArg.second))
continue;

// Find an allocation offset in bits in all vtables in the bitset.
// Find an allocation offset in bits in all vtables associated with the
// type.
uint64_t AllocBefore =
findLowestOffset(TargetsForSlot, /*IsAfter=*/false, BitWidth);
uint64_t AllocAfter =
Expand Down Expand Up @@ -620,21 +618,22 @@ void DevirtModule::rebuildGlobal(VTableBits &B) {
}

bool DevirtModule::run() {
Function *BitSetTestFunc =
M.getFunction(Intrinsic::getName(Intrinsic::bitset_test));
if (!BitSetTestFunc || BitSetTestFunc->use_empty())
Function *TypeTestFunc =
M.getFunction(Intrinsic::getName(Intrinsic::type_test));
if (!TypeTestFunc || TypeTestFunc->use_empty())
return false;

Function *AssumeFunc = M.getFunction(Intrinsic::getName(Intrinsic::assume));
if (!AssumeFunc || AssumeFunc->use_empty())
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;
Expand All @@ -650,18 +649,18 @@ bool DevirtModule::run() {
// the vtable pointer before, as it may have been CSE'd with pointers from
// other call sites, and we don't want to process call sites multiple times.
if (!Assumes.empty()) {
Metadata *BitSet =
Metadata *TypeId =
cast<MetadataAsValue>(CI->getArgOperand(1))->getMetadata();
Value *Ptr = CI->getArgOperand(0)->stripPointerCasts();
if (SeenPtrs.insert(Ptr).second) {
for (DevirtCallSite Call : DevirtCalls) {
CallSlots[{BitSet, Call.Offset}].push_back(
CallSlots[{TypeId, Call.Offset}].push_back(
{CI->getArgOperand(0), Call.CS});
}
}
}

// We no longer need the assumes or the bitset test.
// We no longer need the assumes or the type test.
for (auto Assume : Assumes)
Assume->eraseFromParent();
// We can't use RecursivelyDeleteTriviallyDeadInstructions here because we
Expand All @@ -670,20 +669,21 @@ bool DevirtModule::run() {
CI->eraseFromParent();
}

// Rebuild llvm.bitsets metadata into a map for easy lookup.
// Rebuild type metadata into a map for easy lookup.
std::vector<VTableBits> Bits;
DenseMap<Metadata *, std::set<BitSetInfo>> BitSets;
buildBitSets(Bits, BitSets);
if (BitSets.empty())
DenseMap<Metadata *, std::set<TypeMemberInfo>> TypeIdMap;
buildTypeIdentifierMap(Bits, TypeIdMap);
if (TypeIdMap.empty())
return true;

// For each (bitset, offset) pair:
// For each (type, offset) pair:
bool DidVirtualConstProp = false;
for (auto &S : CallSlots) {
// Search each of the vtables in the bitset for the virtual function
// implementation at offset S.first.ByteOffset, and add to TargetsForSlot.
// Search each of the members of the type identifier for the virtual
// function implementation at offset S.first.ByteOffset, and add to
// TargetsForSlot.
std::vector<VirtualCallTarget> TargetsForSlot;
if (!tryFindVirtualCallTargets(TargetsForSlot, BitSets[S.first.BitSetID],
if (!tryFindVirtualCallTargets(TargetsForSlot, TypeIdMap[S.first.TypeID],
S.first.ByteOffset))
continue;

Expand Down
57 changes: 22 additions & 35 deletions llvm/test/Transforms/CrossDSOCFI/basic.ll
Original file line number Diff line number Diff line change
Expand Up @@ -16,52 +16,48 @@
; CHECK-NEXT: br label %[[EXIT]]

; CHECK: [[L1]]:
; CHECK-NEXT: call i1 @llvm.bitset.test(i8* %[[ADDR]], metadata i64 111)
; CHECK-NEXT: call i1 @llvm.type.test(i8* %[[ADDR]], metadata i64 111)
; CHECK-NEXT: br {{.*}} label %[[EXIT]], label %[[FAIL]]

; CHECK: [[L2]]:
; CHECK-NEXT: call i1 @llvm.bitset.test(i8* %[[ADDR]], metadata i64 222)
; CHECK-NEXT: call i1 @llvm.type.test(i8* %[[ADDR]], metadata i64 222)
; CHECK-NEXT: br {{.*}} label %[[EXIT]], label %[[FAIL]]

; CHECK: [[L3]]:
; CHECK-NEXT: call i1 @llvm.bitset.test(i8* %[[ADDR]], metadata i64 333)
; CHECK-NEXT: call i1 @llvm.type.test(i8* %[[ADDR]], metadata i64 333)
; CHECK-NEXT: br {{.*}} label %[[EXIT]], label %[[FAIL]]

; CHECK: [[L4]]:
; CHECK-NEXT: call i1 @llvm.bitset.test(i8* %[[ADDR]], metadata i64 444)
; CHECK-NEXT: call i1 @llvm.type.test(i8* %[[ADDR]], metadata i64 444)
; CHECK-NEXT: br {{.*}} label %[[EXIT]], label %[[FAIL]]

target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"

@_ZTV1A = constant i8 0
@_ZTI1A = constant i8 0
@_ZTS1A = constant i8 0
@_ZTV1B = constant i8 0
@_ZTI1B = constant i8 0
@_ZTS1B = constant i8 0
@_ZTV1A = constant i8 0, !type !4, !type !5
@_ZTV1B = constant i8 0, !type !4, !type !5, !type !6, !type !7

define signext i8 @f11() {
define signext i8 @f11() !type !0 !type !1 {
entry:
ret i8 1
}

define signext i8 @f12() {
define signext i8 @f12() !type !0 !type !1 {
entry:
ret i8 2
}

define signext i8 @f13() {
define signext i8 @f13() !type !0 !type !1 {
entry:
ret i8 3
}

define i32 @f21() {
define i32 @f21() !type !2 !type !3 {
entry:
ret i32 4
}

define i32 @f22() {
define i32 @f22() !type !2 !type !3 {
entry:
ret i32 5
}
Expand All @@ -71,23 +67,14 @@ entry:
ret void
}

!llvm.bitsets = !{!0, !1, !2, !3, !4, !7, !8, !9, !10, !11, !12, !13, !14, !15}
!llvm.module.flags = !{!17}

!0 = !{!"_ZTSFcvE", i8 ()* @f11, i64 0}
!1 = !{i64 111, i8 ()* @f11, i64 0}
!2 = !{!"_ZTSFcvE", i8 ()* @f12, i64 0}
!3 = !{i64 111, i8 ()* @f12, i64 0}
!4 = !{!"_ZTSFcvE", i8 ()* @f13, i64 0}
!5 = !{i64 111, i8 ()* @f13, i64 0}
!6 = !{!"_ZTSFivE", i32 ()* @f21, i64 0}
!7 = !{i64 222, i32 ()* @f21, i64 0}
!8 = !{!"_ZTSFivE", i32 ()* @f22, i64 0}
!9 = !{i64 222, i32 ()* @f22, i64 0}
!10 = !{!"_ZTS1A", i8* @_ZTV1A, i64 16}
!11 = !{i64 333, i8* @_ZTV1A, i64 16}
!12 = !{!"_ZTS1A", i8* @_ZTV1B, i64 16}
!13 = !{i64 333, i8* @_ZTV1B, i64 16}
!14 = !{!"_ZTS1B", i8* @_ZTV1B, i64 16}
!15 = !{i64 444, i8* @_ZTV1B, i64 16}
!17= !{i32 4, !"Cross-DSO CFI", i32 1}
!llvm.module.flags = !{!8}

!0 = !{i64 0, !"_ZTSFcvE"}
!1 = !{i64 0, i64 111}
!2 = !{i64 0, !"_ZTSFivE"}
!3 = !{i64 0, i64 222}
!4 = !{i64 16, !"_ZTS1A"}
!5 = !{i64 16, i64 333}
!6 = !{i64 16, !"_ZTS1B"}
!7 = !{i64 16, i64 444}
!8 = !{i32 4, !"Cross-DSO CFI", i32 1}
34 changes: 0 additions & 34 deletions llvm/test/Transforms/LowerBitSets/constant.ll

This file was deleted.

35 changes: 0 additions & 35 deletions llvm/test/Transforms/LowerBitSets/layout.ll

This file was deleted.

19 changes: 0 additions & 19 deletions llvm/test/Transforms/LowerBitSets/nonglobal.ll

This file was deleted.

21 changes: 0 additions & 21 deletions llvm/test/Transforms/LowerBitSets/pr25902.ll

This file was deleted.

20 changes: 0 additions & 20 deletions llvm/test/Transforms/LowerBitSets/unnamed.ll

This file was deleted.

32 changes: 32 additions & 0 deletions llvm/test/Transforms/LowerTypeTests/constant.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
; RUN: opt -S -lowertypetests < %s | FileCheck %s

target datalayout = "e-p:32:32"

@a = constant i32 1, !type !0
@b = constant [2 x i32] [i32 2, i32 3], !type !1

!0 = !{i32 0, !"typeid1"}
!1 = !{i32 4, !"typeid1"}

declare i1 @llvm.type.test(i8* %ptr, metadata %bitset) nounwind readnone

; CHECK: @foo(
define i1 @foo() {
; CHECK: ret i1 true
%x = call i1 @llvm.type.test(i8* bitcast (i32* @a to i8*), metadata !"typeid1")
ret i1 %x
}

; CHECK: @bar(
define i1 @bar() {
; CHECK: ret i1 true
%x = call i1 @llvm.type.test(i8* bitcast (i32* getelementptr ([2 x i32], [2 x i32]* @b, i32 0, i32 1) to i8*), metadata !"typeid1")
ret i1 %x
}

; CHECK: @baz(
define i1 @baz() {
; CHECK-NOT: ret i1 true
%x = call i1 @llvm.type.test(i8* bitcast (i32* getelementptr ([2 x i32], [2 x i32]* @b, i32 0, i32 0) to i8*), metadata !"typeid1")
ret i1 %x
}
Original file line number Diff line number Diff line change
@@ -1,22 +1,20 @@
; RUN: opt -S -lowerbitsets < %s | FileCheck %s
; RUN: opt -S -lowertypetests < %s | FileCheck %s

; Tests that we correctly handle external references, including the case where
; all functions in a bitset are external references.

target triple = "x86_64-unknown-linux-gnu"

declare void @foo()
declare !type !0 void @foo()

; CHECK: @[[JT:.*]] = private constant [1 x <{ i8, i32, i8, i8, i8 }>] [<{ i8, i32, i8, i8, i8 }> <{ i8 -23, i32 trunc (i64 sub (i64 sub (i64 ptrtoint (void ()* @foo to i64), i64 ptrtoint ([1 x <{ i8, i32, i8, i8, i8 }>]* @[[JT]] to i64)), i64 5) to i32), i8 -52, i8 -52, i8 -52 }>], section ".text"

define i1 @bar(i8* %ptr) {
; CHECK: icmp eq i64 {{.*}}, ptrtoint ([1 x <{ i8, i32, i8, i8, i8 }>]* @[[JT]] to i64)
%p = call i1 @llvm.bitset.test(i8* %ptr, metadata !"void")
%p = call i1 @llvm.type.test(i8* %ptr, metadata !"void")
ret i1 %p
}

declare i1 @llvm.bitset.test(i8* %ptr, metadata %bitset) nounwind readnone
declare i1 @llvm.type.test(i8* %ptr, metadata %bitset) nounwind readnone

!0 = !{!"void", void ()* @foo, i64 0}

!llvm.bitsets = !{!0}
!0 = !{i64 0, !"void"}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
; RUN: opt -S -lowerbitsets < %s | FileCheck %s
; RUN: opt -S -lowertypetests < %s | FileCheck %s

; Tests that we correctly create a jump table for bitsets containing 2 or more
; functions.
Expand All @@ -11,25 +11,22 @@ target datalayout = "e-p:64:64"
; CHECK: @f = alias void (), bitcast ([2 x <{ i8, i32, i8, i8, i8 }>]* @[[JT]] to void ()*)
; CHECK: @g = alias void (), bitcast (<{ i8, i32, i8, i8, i8 }>* getelementptr inbounds ([2 x <{ i8, i32, i8, i8, i8 }>], [2 x <{ i8, i32, i8, i8, i8 }>]* @[[JT]], i64 0, i64 1) to void ()*)

; CHECK: define private void @[[FNAME]]() {
define void @f() {
; CHECK: define private void @[[FNAME]]()
define void @f() !type !0 {
ret void
}

; CHECK: define private void @[[GNAME]]() {
define void @g() {
; CHECK: define private void @[[GNAME]]()
define void @g() !type !0 {
ret void
}

!0 = !{!"bitset1", void ()* @f, i32 0}
!1 = !{!"bitset1", void ()* @g, i32 0}
!0 = !{i32 0, !"typeid1"}

!llvm.bitsets = !{ !0, !1 }

declare i1 @llvm.bitset.test(i8* %ptr, metadata %bitset) nounwind readnone
declare i1 @llvm.type.test(i8* %ptr, metadata %bitset) nounwind readnone

define i1 @foo(i8* %p) {
; CHECK: sub i64 {{.*}}, ptrtoint ([2 x <{ i8, i32, i8, i8, i8 }>]* @[[JT]] to i64)
%x = call i1 @llvm.bitset.test(i8* %p, metadata !"bitset1")
%x = call i1 @llvm.type.test(i8* %p, metadata !"typeid1")
ret i1 %x
}
27 changes: 27 additions & 0 deletions llvm/test/Transforms/LowerTypeTests/layout.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
; RUN: opt -S -lowertypetests < %s | FileCheck %s

target datalayout = "e-p:32:32"

; Tests that this set of globals is laid out according to our layout algorithm
; (see GlobalLayoutBuilder in include/llvm/Transforms/IPO/LowerTypeTests.h).
; The chosen layout in this case is a, e, b, d, c.

; CHECK: private constant { i32, [0 x i8], i32, [0 x i8], i32, [0 x i8], i32, [0 x i8], i32 } { i32 1, [0 x i8] zeroinitializer, i32 5, [0 x i8] zeroinitializer, i32 2, [0 x i8] zeroinitializer, i32 4, [0 x i8] zeroinitializer, i32 3 }
@a = constant i32 1, !type !0, !type !2
@b = constant i32 2, !type !0, !type !1
@c = constant i32 3, !type !0
@d = constant i32 4, !type !1
@e = constant i32 5, !type !2

!0 = !{i32 0, !"typeid1"}
!1 = !{i32 0, !"typeid2"}
!2 = !{i32 0, !"typeid3"}

declare i1 @llvm.type.test(i8* %ptr, metadata %bitset) nounwind readnone

define void @foo() {
%x = call i1 @llvm.type.test(i8* undef, metadata !"typeid1")
%y = call i1 @llvm.type.test(i8* undef, metadata !"typeid2")
%z = call i1 @llvm.type.test(i8* undef, metadata !"typeid3")
ret void
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
; RUN: opt -S -lowerbitsets < %s | FileCheck %s
; RUN: opt -S -lowertypetests < %s | FileCheck %s

; Tests that non-string metadata nodes may be used as bitset identifiers.

Expand All @@ -7,28 +7,26 @@ target datalayout = "e-p:32:32"
; CHECK: @[[ANAME:.*]] = private constant { i32 }
; CHECK: @[[BNAME:.*]] = private constant { [2 x i32] }

@a = constant i32 1
@b = constant [2 x i32] [i32 2, i32 3]
@a = constant i32 1, !type !0
@b = constant [2 x i32] [i32 2, i32 3], !type !1

!0 = !{!2, i32* @a, i32 0}
!1 = !{!3, [2 x i32]* @b, i32 0}
!0 = !{i32 0, !2}
!1 = !{i32 0, !3}
!2 = distinct !{}
!3 = distinct !{}

!llvm.bitsets = !{ !0, !1 }

declare i1 @llvm.bitset.test(i8* %ptr, metadata %bitset) nounwind readnone
declare i1 @llvm.type.test(i8* %ptr, metadata %bitset) nounwind readnone

; CHECK-LABEL: @foo
define i1 @foo(i8* %p) {
; CHECK: icmp eq i32 {{.*}}, ptrtoint ({ i32 }* @[[ANAME]] to i32)
%x = call i1 @llvm.bitset.test(i8* %p, metadata !2)
%x = call i1 @llvm.type.test(i8* %p, metadata !2)
ret i1 %x
}

; CHECK-LABEL: @bar
define i1 @bar(i8* %p) {
; CHECK: icmp eq i32 {{.*}}, ptrtoint ({ [2 x i32] }* @[[BNAME]] to i32)
%x = call i1 @llvm.bitset.test(i8* %p, metadata !3)
%x = call i1 @llvm.type.test(i8* %p, metadata !3)
ret i1 %x
}
19 changes: 19 additions & 0 deletions llvm/test/Transforms/LowerTypeTests/pr25902.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
; PR25902: gold plugin crash.
; RUN: opt -mtriple=i686-pc -S -lowertypetests < %s

define void @f(void ()* %p) {
entry:
%a = bitcast void ()* %p to i8*, !nosanitize !1
%b = call i1 @llvm.type.test(i8* %a, metadata !"_ZTSFvvE"), !nosanitize !1
ret void
}

define void @g() !type !0 {
entry:
ret void
}

declare i1 @llvm.type.test(i8*, metadata)

!0 = !{i64 0, !"_ZTSFvvE"}
!1 = !{}
Original file line number Diff line number Diff line change
@@ -1,26 +1,25 @@
; 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: @[[A:.*]] = private constant {{.*}} section ".text"
; 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"}
Original file line number Diff line number Diff line change
@@ -1,42 +1,34 @@
; RUN: opt -S -lowerbitsets < %s | FileCheck %s
; RUN: opt -S -lowerbitsets -mtriple=x86_64-apple-macosx10.8.0 < %s | FileCheck -check-prefix=CHECK-DARWIN %s
; RUN: opt -S -lowertypetests < %s | FileCheck %s
; RUN: opt -S -lowertypetests -mtriple=x86_64-apple-macosx10.8.0 < %s | FileCheck -check-prefix=CHECK-DARWIN %s
; RUN: opt -S -O3 < %s | FileCheck -check-prefix=CHECK-NODISCARD %s

target datalayout = "e-p:32:32"

; CHECK: [[G:@[^ ]*]] = private constant { i32, [0 x i8], [63 x i32], [4 x i8], i32, [0 x i8], [2 x i32] } { i32 1, [0 x i8] zeroinitializer, [63 x i32] zeroinitializer, [4 x i8] zeroinitializer, i32 3, [0 x i8] zeroinitializer, [2 x i32] [i32 4, i32 5] }
@a = constant i32 1
@b = hidden constant [63 x i32] zeroinitializer
@c = protected constant i32 3
@d = constant [2 x i32] [i32 4, i32 5]
@a = constant i32 1, !type !0, !type !2
@b = hidden constant [63 x i32] zeroinitializer, !type !0, !type !1
@c = protected constant i32 3, !type !1, !type !2
@d = constant [2 x i32] [i32 4, i32 5], !type !3

; CHECK-NODISCARD: !type
; CHECK-NODISCARD: !type
; CHECK-NODISCARD: !type
; CHECK-NODISCARD: !type
; CHECK-NODISCARD: !type
; CHECK-NODISCARD: !type
; CHECK-NODISCARD: !type

; CHECK: [[BA:@[^ ]*]] = private constant [68 x i8] c"\03\01\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\02\00\01"

; Offset 0, 4 byte alignment
!0 = !{!"bitset1", i32* @a, i32 0}
; CHECK-NODISCARD-DAG: !{!"bitset1", i32* @a, i32 0}
!1 = !{!"bitset1", [63 x i32]* @b, i32 0}
; CHECK-NODISCARD-DAG: !{!"bitset1", [63 x i32]* @b, i32 0}
!2 = !{!"bitset1", [2 x i32]* @d, i32 4}
; CHECK-NODISCARD-DAG: !{!"bitset1", [2 x i32]* @d, i32 4}
!0 = !{i32 0, !"typeid1"}
!3 = !{i32 4, !"typeid1"}

; Offset 4, 256 byte alignment
!3 = !{!"bitset2", [63 x i32]* @b, i32 0}
; CHECK-NODISCARD-DAG: !{!"bitset2", [63 x i32]* @b, i32 0}
!4 = !{!"bitset2", i32* @c, i32 0}
; CHECK-NODISCARD-DAG: !{!"bitset2", i32* @c, i32 0}

; Entries whose second operand is null (the result of a global being DCE'd)
; should be ignored.
!5 = !{!"bitset2", null, i32 0}
!1 = !{i32 0, !"typeid2"}

; Offset 0, 4 byte alignment
!6 = !{!"bitset3", i32* @a, i32 0}
; CHECK-NODISCARD-DAG: !{!"bitset3", i32* @a, i32 0}
!7 = !{!"bitset3", i32* @c, i32 0}
; CHECK-NODISCARD-DAG: !{!"bitset3", i32* @c, i32 0}

!llvm.bitsets = !{ !0, !1, !2, !3, !4, !5, !6, !7 }
!2 = !{i32 0, !"typeid3"}

; CHECK: @bits_use{{[0-9]*}} = private alias i8, i8* @bits{{[0-9]*}}
; CHECK: @bits_use.{{[0-9]*}} = private alias i8, i8* @bits{{[0-9]*}}
Expand Down Expand Up @@ -64,11 +56,11 @@ target datalayout = "e-p:32:32"
; CHECK: @bits{{[0-9]*}} = private alias i8, getelementptr inbounds ([68 x i8], [68 x i8]* [[BA]], i32 0, i32 0)
; CHECK: @bits.{{[0-9]*}} = private alias i8, getelementptr inbounds ([68 x i8], [68 x i8]* [[BA]], i32 0, i32 0)

declare i1 @llvm.bitset.test(i8* %ptr, metadata %bitset) nounwind readnone
declare i1 @llvm.type.test(i8* %ptr, metadata %bitset) nounwind readnone

; CHECK: @foo(i32* [[A0:%[^ ]*]])
define i1 @foo(i32* %p) {
; CHECK-NOT: llvm.bitset.test
; CHECK-NOT: llvm.type.test

; CHECK: [[R0:%[^ ]*]] = bitcast i32* [[A0]] to i8*
%pi8 = bitcast i32* %p to i8*
Expand All @@ -86,10 +78,10 @@ define i1 @foo(i32* %p) {
; CHECK: [[R11:%[^ ]*]] = icmp ne i8 [[R10]], 0

; CHECK: [[R16:%[^ ]*]] = phi i1 [ false, {{%[^ ]*}} ], [ [[R11]], {{%[^ ]*}} ]
%x = call i1 @llvm.bitset.test(i8* %pi8, metadata !"bitset1")
%x = call i1 @llvm.type.test(i8* %pi8, metadata !"typeid1")

; CHECK-NOT: llvm.bitset.test
%y = call i1 @llvm.bitset.test(i8* %pi8, metadata !"bitset1")
; CHECK-NOT: llvm.type.test
%y = call i1 @llvm.type.test(i8* %pi8, metadata !"typeid1")

; CHECK: ret i1 [[R16]]
ret i1 %x
Expand All @@ -105,7 +97,7 @@ define i1 @bar(i32* %p) {
; CHECK: [[S4:%[^ ]*]] = shl i32 [[S2]], 24
; CHECK: [[S5:%[^ ]*]] = or i32 [[S3]], [[S4]]
; CHECK: [[S6:%[^ ]*]] = icmp ult i32 [[S5]], 2
%x = call i1 @llvm.bitset.test(i8* %pi8, metadata !"bitset2")
%x = call i1 @llvm.type.test(i8* %pi8, metadata !"typeid2")

; CHECK: ret i1 [[S6]]
ret i1 %x
Expand All @@ -123,15 +115,13 @@ define i1 @baz(i32* %p) {
; CHECK: [[T6:%[^ ]*]] = icmp ult i32 [[T5]], 66
; CHECK: br i1 [[T6]]

; CHECK: [[T8:%[^ ]*]] = getelementptr i8, i8* @bits_use.{{[0-9]*}}, i32 [[T5]]
; CHECK: [[T8:%[^ ]*]] = getelementptr i8, i8* @bits_use{{(\.[0-9]*)?}}, i32 [[T5]]
; CHECK: [[T9:%[^ ]*]] = load i8, i8* [[T8]]
; CHECK: [[T10:%[^ ]*]] = and i8 [[T9]], 2
; CHECK: [[T11:%[^ ]*]] = icmp ne i8 [[T10]], 0

; CHECK: [[T16:%[^ ]*]] = phi i1 [ false, {{%[^ ]*}} ], [ [[T11]], {{%[^ ]*}} ]
%x = call i1 @llvm.bitset.test(i8* %pi8, metadata !"bitset3")
%x = call i1 @llvm.type.test(i8* %pi8, metadata !"typeid3")
; CHECK: ret i1 [[T16]]
ret i1 %x
}

; CHECK-NOT: !llvm.bitsets
Original file line number Diff line number Diff line change
@@ -1,25 +1,22 @@
; RUN: opt -S -lowerbitsets < %s | FileCheck %s
; RUN: opt -S -lowertypetests < %s | FileCheck %s

target datalayout = "e-p:32:32"

; CHECK: [[G:@[^ ]*]] = private constant { i32, [0 x i8], i32 }
@a = constant i32 1
@b = constant i32 2
@a = constant i32 1, !type !0, !type !1
@b = constant i32 2, !type !0, !type !2

!0 = !{!"bitset1", i32* @a, i32 0}
!1 = !{!"bitset1", i32* @b, i32 0}
!2 = !{!"bitset2", i32* @a, i32 0}
!3 = !{!"bitset3", i32* @b, i32 0}
!0 = !{i32 0, !"typeid1"}
!1 = !{i32 0, !"typeid2"}
!2 = !{i32 0, !"typeid3"}

!llvm.bitsets = !{ !0, !1, !2, !3 }

declare i1 @llvm.bitset.test(i8* %ptr, metadata %bitset) nounwind readnone
declare i1 @llvm.type.test(i8* %ptr, metadata %bitset) nounwind readnone

; CHECK: @foo(i8* [[A0:%[^ ]*]])
define i1 @foo(i8* %p) {
; CHECK: [[R0:%[^ ]*]] = ptrtoint i8* [[A0]] to i32
; CHECK: [[R1:%[^ ]*]] = icmp eq i32 [[R0]], ptrtoint ({ i32, [0 x i8], i32 }* [[G]] to i32)
%x = call i1 @llvm.bitset.test(i8* %p, metadata !"bitset2")
%x = call i1 @llvm.type.test(i8* %p, metadata !"typeid2")
; CHECK: ret i1 [[R1]]
ret i1 %x
}
Expand All @@ -28,13 +25,13 @@ define i1 @foo(i8* %p) {
define i1 @bar(i8* %p) {
; CHECK: [[S0:%[^ ]*]] = ptrtoint i8* [[B0]] to i32
; CHECK: [[S1:%[^ ]*]] = icmp eq i32 [[S0]], add (i32 ptrtoint ({ i32, [0 x i8], i32 }* [[G]] to i32), i32 4)
%x = call i1 @llvm.bitset.test(i8* %p, metadata !"bitset3")
%x = call i1 @llvm.type.test(i8* %p, metadata !"typeid3")
; CHECK: ret i1 [[S1]]
ret i1 %x
}

; CHECK: @x(
define i1 @x(i8* %p) {
%x = call i1 @llvm.bitset.test(i8* %p, metadata !"bitset1")
%x = call i1 @llvm.type.test(i8* %p, metadata !"typeid1")
ret i1 %x
}
18 changes: 18 additions & 0 deletions llvm/test/Transforms/LowerTypeTests/unnamed.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
; RUN: opt -S -lowertypetests < %s | FileCheck %s

target datalayout = "e-p:32:32"

; CHECK: @{{[0-9]+}} = alias
; CHECK: @{{[0-9]+}} = alias
@0 = constant i32 1, !type !0
@1 = constant [2 x i32] [i32 2, i32 3], !type !1

!0 = !{i32 0, !"typeid1"}
!1 = !{i32 4, !"typeid1"}

declare i1 @llvm.type.test(i8* %ptr, metadata %bitset) nounwind readnone

define i1 @foo(i8* %p) {
%x = call i1 @llvm.type.test(i8* %p, metadata !"typeid1")
ret i1 %x
}
13 changes: 6 additions & 7 deletions llvm/test/Transforms/WholeProgramDevirt/bad-read-from-vtable.ll
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
target datalayout = "e-p:64:64"
target triple = "x86_64-unknown-linux-gnu"

@vt = global [2 x i8*] [i8* zeroinitializer, i8* bitcast (void (i8*)* @vf to i8*)]
@vt = global [2 x i8*] [i8* zeroinitializer, i8* bitcast (void (i8*)* @vf to i8*)], !type !0

define void @vf(i8* %this) {
ret void
Expand All @@ -14,7 +14,7 @@ define void @unaligned(i8* %obj) {
%vtableptr = bitcast i8* %obj to [1 x i8*]**
%vtable = load [1 x i8*]*, [1 x i8*]** %vtableptr
%vtablei8 = bitcast [1 x i8*]* %vtable to i8*
%p = call i1 @llvm.bitset.test(i8* %vtablei8, metadata !"bitset")
%p = call i1 @llvm.type.test(i8* %vtablei8, metadata !"typeid")
call void @llvm.assume(i1 %p)
%fptrptr = getelementptr i8, i8* %vtablei8, i32 1
%fptrptr_casted = bitcast i8* %fptrptr to i8**
Expand All @@ -30,7 +30,7 @@ define void @outofbounds(i8* %obj) {
%vtableptr = bitcast i8* %obj to [1 x i8*]**
%vtable = load [1 x i8*]*, [1 x i8*]** %vtableptr
%vtablei8 = bitcast [1 x i8*]* %vtable to i8*
%p = call i1 @llvm.bitset.test(i8* %vtablei8, metadata !"bitset")
%p = call i1 @llvm.type.test(i8* %vtablei8, metadata !"typeid")
call void @llvm.assume(i1 %p)
%fptrptr = getelementptr i8, i8* %vtablei8, i32 16
%fptrptr_casted = bitcast i8* %fptrptr to i8**
Expand All @@ -46,7 +46,7 @@ define void @nonfunction(i8* %obj) {
%vtableptr = bitcast i8* %obj to [1 x i8*]**
%vtable = load [1 x i8*]*, [1 x i8*]** %vtableptr
%vtablei8 = bitcast [1 x i8*]* %vtable to i8*
%p = call i1 @llvm.bitset.test(i8* %vtablei8, metadata !"bitset")
%p = call i1 @llvm.type.test(i8* %vtablei8, metadata !"typeid")
call void @llvm.assume(i1 %p)
%fptrptr = getelementptr i8, i8* %vtablei8, i32 0
%fptrptr_casted = bitcast i8* %fptrptr to i8**
Expand All @@ -57,8 +57,7 @@ define void @nonfunction(i8* %obj) {
ret void
}

declare i1 @llvm.bitset.test(i8*, metadata)
declare i1 @llvm.type.test(i8*, metadata)
declare void @llvm.assume(i1)

!0 = !{!"bitset", [2 x i8*]* @vt, i32 0}
!llvm.bitsets = !{!0}
!0 = !{i32 0, !"typeid"}
20 changes: 8 additions & 12 deletions llvm/test/Transforms/WholeProgramDevirt/constant-arg.ll
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ target triple = "x86_64-unknown-linux-gnu"
; CHECK: private constant { [8 x i8], [1 x i8*], [0 x i8] } { [8 x i8] c"\00\00\00\00\00\00\00\01", [1 x i8*] [i8* bitcast (i1 (i8*, i32)* @vf4 to i8*)], [0 x i8] zeroinitializer }
; CHECK: private constant { [8 x i8], [1 x i8*], [0 x i8] } { [8 x i8] c"\00\00\00\00\00\00\00\02", [1 x i8*] [i8* bitcast (i1 (i8*, i32)* @vf8 to i8*)], [0 x i8] zeroinitializer }

@vt1 = constant [1 x i8*] [i8* bitcast (i1 (i8*, i32)* @vf1 to i8*)]
@vt2 = constant [1 x i8*] [i8* bitcast (i1 (i8*, i32)* @vf2 to i8*)]
@vt4 = constant [1 x i8*] [i8* bitcast (i1 (i8*, i32)* @vf4 to i8*)]
@vt8 = constant [1 x i8*] [i8* bitcast (i1 (i8*, i32)* @vf8 to i8*)]
@vt1 = constant [1 x i8*] [i8* bitcast (i1 (i8*, i32)* @vf1 to i8*)], !type !0
@vt2 = constant [1 x i8*] [i8* bitcast (i1 (i8*, i32)* @vf2 to i8*)], !type !0
@vt4 = constant [1 x i8*] [i8* bitcast (i1 (i8*, i32)* @vf4 to i8*)], !type !0
@vt8 = constant [1 x i8*] [i8* bitcast (i1 (i8*, i32)* @vf8 to i8*)], !type !0

define i1 @vf1(i8* %this, i32 %arg) readnone {
%and = and i32 %arg, 1
Expand Down Expand Up @@ -43,7 +43,7 @@ define i1 @call1(i8* %obj) {
%vtableptr = bitcast i8* %obj to [1 x i8*]**
%vtable = load [1 x i8*]*, [1 x i8*]** %vtableptr
%vtablei8 = bitcast [1 x i8*]* %vtable to i8*
%p = call i1 @llvm.bitset.test(i8* %vtablei8, metadata !"bitset")
%p = call i1 @llvm.type.test(i8* %vtablei8, metadata !"typeid")
call void @llvm.assume(i1 %p)
%fptrptr = getelementptr [1 x i8*], [1 x i8*]* %vtable, i32 0, i32 0
%fptr = load i8*, i8** %fptrptr
Expand All @@ -59,7 +59,7 @@ define i1 @call2(i8* %obj) {
%vtableptr = bitcast i8* %obj to [1 x i8*]**
%vtable = load [1 x i8*]*, [1 x i8*]** %vtableptr
%vtablei8 = bitcast [1 x i8*]* %vtable to i8*
%p = call i1 @llvm.bitset.test(i8* %vtablei8, metadata !"bitset")
%p = call i1 @llvm.type.test(i8* %vtablei8, metadata !"typeid")
call void @llvm.assume(i1 %p)
%fptrptr = getelementptr [1 x i8*], [1 x i8*]* %vtable, i32 0, i32 0
%fptr = load i8*, i8** %fptrptr
Expand All @@ -70,11 +70,7 @@ define i1 @call2(i8* %obj) {
ret i1 %result
}

declare i1 @llvm.bitset.test(i8*, metadata)
declare i1 @llvm.type.test(i8*, metadata)
declare void @llvm.assume(i1)

!0 = !{!"bitset", [1 x i8*]* @vt1, i32 0}
!1 = !{!"bitset", [1 x i8*]* @vt2, i32 0}
!2 = !{!"bitset", [1 x i8*]* @vt4, i32 0}
!3 = !{!"bitset", [1 x i8*]* @vt8, i32 0}
!llvm.bitsets = !{!0, !1, !2, !3}
!0 = !{i32 0, !"typeid"}
12 changes: 5 additions & 7 deletions llvm/test/Transforms/WholeProgramDevirt/devirt-single-impl.ll
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
target datalayout = "e-p:64:64"
target triple = "x86_64-unknown-linux-gnu"

@vt1 = constant [1 x i8*] [i8* bitcast (void (i8*)* @vf to i8*)]
@vt2 = constant [1 x i8*] [i8* bitcast (void (i8*)* @vf to i8*)]
@vt1 = constant [1 x i8*] [i8* bitcast (void (i8*)* @vf to i8*)], !type !0
@vt2 = constant [1 x i8*] [i8* bitcast (void (i8*)* @vf to i8*)], !type !0

define void @vf(i8* %this) {
ret void
Expand All @@ -15,7 +15,7 @@ define void @call(i8* %obj) {
%vtableptr = bitcast i8* %obj to [1 x i8*]**
%vtable = load [1 x i8*]*, [1 x i8*]** %vtableptr
%vtablei8 = bitcast [1 x i8*]* %vtable to i8*
%p = call i1 @llvm.bitset.test(i8* %vtablei8, metadata !"bitset")
%p = call i1 @llvm.type.test(i8* %vtablei8, metadata !"typeid")
call void @llvm.assume(i1 %p)
%fptrptr = getelementptr [1 x i8*], [1 x i8*]* %vtable, i32 0, i32 0
%fptr = load i8*, i8** %fptrptr
Expand All @@ -25,9 +25,7 @@ define void @call(i8* %obj) {
ret void
}

declare i1 @llvm.bitset.test(i8*, metadata)
declare i1 @llvm.type.test(i8*, metadata)
declare void @llvm.assume(i1)

!0 = !{!"bitset", [1 x i8*]* @vt1, i32 0}
!1 = !{!"bitset", [1 x i8*]* @vt2, i32 0}
!llvm.bitsets = !{!0, !1}
!0 = !{i32 0, !"typeid"}
9 changes: 4 additions & 5 deletions llvm/test/Transforms/WholeProgramDevirt/non-array-vtable.ll
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
target datalayout = "e-p:64:64"
target triple = "x86_64-unknown-linux-gnu"

@vt = constant i8* bitcast (void (i8*)* @vf to i8*)
@vt = constant i8* bitcast (void (i8*)* @vf to i8*), !type !0

define void @vf(i8* %this) {
ret void
Expand All @@ -14,7 +14,7 @@ define void @call(i8* %obj) {
%vtableptr = bitcast i8* %obj to [1 x i8*]**
%vtable = load [1 x i8*]*, [1 x i8*]** %vtableptr
%vtablei8 = bitcast [1 x i8*]* %vtable to i8*
%p = call i1 @llvm.bitset.test(i8* %vtablei8, metadata !"bitset")
%p = call i1 @llvm.type.test(i8* %vtablei8, metadata !"typeid")
call void @llvm.assume(i1 %p)
%fptrptr = getelementptr [1 x i8*], [1 x i8*]* %vtable, i32 0, i32 0
%fptr = load i8*, i8** %fptrptr
Expand All @@ -24,8 +24,7 @@ define void @call(i8* %obj) {
ret void
}

declare i1 @llvm.bitset.test(i8*, metadata)
declare i1 @llvm.type.test(i8*, metadata)
declare void @llvm.assume(i1)

!0 = !{!"bitset", i8** @vt, i32 0}
!llvm.bitsets = !{!0}
!0 = !{i32 0, !"typeid"}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
target datalayout = "e-p:64:64"
target triple = "x86_64-unknown-linux-gnu"

@vt = global [1 x i8*] [i8* bitcast (void (i8*)* @vf to i8*)]
@vt = global [1 x i8*] [i8* bitcast (void (i8*)* @vf to i8*)], !type !0

define void @vf(i8* %this) {
ret void
Expand All @@ -14,7 +14,7 @@ define void @call(i8* %obj) {
%vtableptr = bitcast i8* %obj to [1 x i8*]**
%vtable = load [1 x i8*]*, [1 x i8*]** %vtableptr
%vtablei8 = bitcast [1 x i8*]* %vtable to i8*
%p = call i1 @llvm.bitset.test(i8* %vtablei8, metadata !"bitset")
%p = call i1 @llvm.type.test(i8* %vtablei8, metadata !"typeid")
call void @llvm.assume(i1 %p)
%fptrptr = getelementptr [1 x i8*], [1 x i8*]* %vtable, i32 0, i32 0
%fptr = load i8*, i8** %fptrptr
Expand All @@ -24,8 +24,7 @@ define void @call(i8* %obj) {
ret void
}

declare i1 @llvm.bitset.test(i8*, metadata)
declare i1 @llvm.type.test(i8*, metadata)
declare void @llvm.assume(i1)

!0 = !{!"bitset", [1 x i8*]* @vt, i32 0}
!llvm.bitsets = !{!0}
!0 = !{i32 0, !"typeid"}
12 changes: 5 additions & 7 deletions llvm/test/Transforms/WholeProgramDevirt/uniform-retval-invoke.ll
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
target datalayout = "e-p:64:64"
target triple = "x86_64-unknown-linux-gnu"

@vt1 = constant [1 x i8*] [i8* bitcast (i32 (i8*)* @vf1 to i8*)]
@vt2 = constant [1 x i8*] [i8* bitcast (i32 (i8*)* @vf2 to i8*)]
@vt1 = constant [1 x i8*] [i8* bitcast (i32 (i8*)* @vf1 to i8*)], !type !0
@vt2 = constant [1 x i8*] [i8* bitcast (i32 (i8*)* @vf2 to i8*)], !type !0

define i32 @vf1(i8* %this) readnone {
ret i32 123
Expand All @@ -19,7 +19,7 @@ define i32 @call(i8* %obj) personality i8* undef {
%vtableptr = bitcast i8* %obj to [1 x i8*]**
%vtable = load [1 x i8*]*, [1 x i8*]** %vtableptr
%vtablei8 = bitcast [1 x i8*]* %vtable to i8*
%p = call i1 @llvm.bitset.test(i8* %vtablei8, metadata !"bitset")
%p = call i1 @llvm.type.test(i8* %vtablei8, metadata !"typeid")
call void @llvm.assume(i1 %p)
%fptrptr = getelementptr [1 x i8*], [1 x i8*]* %vtable, i32 0, i32 0
%fptr = load i8*, i8** %fptrptr
Expand All @@ -37,9 +37,7 @@ ret:
ret i32 %result
}

declare i1 @llvm.bitset.test(i8*, metadata)
declare i1 @llvm.type.test(i8*, metadata)
declare void @llvm.assume(i1)

!0 = !{!"bitset", [1 x i8*]* @vt1, i32 0}
!1 = !{!"bitset", [1 x i8*]* @vt2, i32 0}
!llvm.bitsets = !{!0, !1}
!0 = !{i32 0, !"typeid"}
12 changes: 5 additions & 7 deletions llvm/test/Transforms/WholeProgramDevirt/uniform-retval.ll
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
target datalayout = "e-p:64:64"
target triple = "x86_64-unknown-linux-gnu"

@vt1 = constant [1 x i8*] [i8* bitcast (i32 (i8*)* @vf1 to i8*)]
@vt2 = constant [1 x i8*] [i8* bitcast (i32 (i8*)* @vf2 to i8*)]
@vt1 = constant [1 x i8*] [i8* bitcast (i32 (i8*)* @vf1 to i8*)], !type !0
@vt2 = constant [1 x i8*] [i8* bitcast (i32 (i8*)* @vf2 to i8*)], !type !0

define i32 @vf1(i8* %this) readnone {
ret i32 123
Expand All @@ -19,7 +19,7 @@ define i32 @call(i8* %obj) {
%vtableptr = bitcast i8* %obj to [1 x i8*]**
%vtable = load [1 x i8*]*, [1 x i8*]** %vtableptr
%vtablei8 = bitcast [1 x i8*]* %vtable to i8*
%p = call i1 @llvm.bitset.test(i8* %vtablei8, metadata !"bitset")
%p = call i1 @llvm.type.test(i8* %vtablei8, metadata !"typeid")
call void @llvm.assume(i1 %p)
%fptrptr = getelementptr [1 x i8*], [1 x i8*]* %vtable, i32 0, i32 0
%fptr = load i8*, i8** %fptrptr
Expand All @@ -30,9 +30,7 @@ define i32 @call(i8* %obj) {
ret i32 %result
}

declare i1 @llvm.bitset.test(i8*, metadata)
declare i1 @llvm.type.test(i8*, metadata)
declare void @llvm.assume(i1)

!0 = !{!"bitset", [1 x i8*]* @vt1, i32 0}
!1 = !{!"bitset", [1 x i8*]* @vt2, i32 0}
!llvm.bitsets = !{!0, !1}
!0 = !{i32 0, !"typeid"}
23 changes: 9 additions & 14 deletions llvm/test/Transforms/WholeProgramDevirt/unique-retval.ll
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
target datalayout = "e-p:64:64"
target triple = "x86_64-unknown-linux-gnu"

@vt1 = constant [1 x i8*] [i8* bitcast (i1 (i8*)* @vf0 to i8*)]
@vt2 = constant [1 x i8*] [i8* bitcast (i1 (i8*)* @vf0 to i8*)]
@vt3 = constant [1 x i8*] [i8* bitcast (i1 (i8*)* @vf1 to i8*)]
@vt4 = constant [1 x i8*] [i8* bitcast (i1 (i8*)* @vf1 to i8*)]
@vt1 = constant [1 x i8*] [i8* bitcast (i1 (i8*)* @vf0 to i8*)], !type !0
@vt2 = constant [1 x i8*] [i8* bitcast (i1 (i8*)* @vf0 to i8*)], !type !0, !type !1
@vt3 = constant [1 x i8*] [i8* bitcast (i1 (i8*)* @vf1 to i8*)], !type !0, !type !1
@vt4 = constant [1 x i8*] [i8* bitcast (i1 (i8*)* @vf1 to i8*)], !type !1

define i1 @vf0(i8* %this) readnone {
ret i1 0
Expand All @@ -22,7 +22,7 @@ define i1 @call1(i8* %obj) {
%vtable = load [1 x i8*]*, [1 x i8*]** %vtableptr
; CHECK: [[VT1:%[^ ]*]] = bitcast [1 x i8*]* {{.*}} to i8*
%vtablei8 = bitcast [1 x i8*]* %vtable to i8*
%p = call i1 @llvm.bitset.test(i8* %vtablei8, metadata !"bitset1")
%p = call i1 @llvm.type.test(i8* %vtablei8, metadata !"typeid1")
call void @llvm.assume(i1 %p)
%fptrptr = getelementptr [1 x i8*], [1 x i8*]* %vtable, i32 0, i32 0
%fptr = load i8*, i8** %fptrptr
Expand All @@ -39,7 +39,7 @@ define i1 @call2(i8* %obj) {
%vtable = load [1 x i8*]*, [1 x i8*]** %vtableptr
; CHECK: [[VT2:%[^ ]*]] = bitcast [1 x i8*]* {{.*}} to i8*
%vtablei8 = bitcast [1 x i8*]* %vtable to i8*
%p = call i1 @llvm.bitset.test(i8* %vtablei8, metadata !"bitset2")
%p = call i1 @llvm.type.test(i8* %vtablei8, metadata !"typeid2")
call void @llvm.assume(i1 %p)
%fptrptr = getelementptr [1 x i8*], [1 x i8*]* %vtable, i32 0, i32 0
%fptr = load i8*, i8** %fptrptr
Expand All @@ -49,13 +49,8 @@ define i1 @call2(i8* %obj) {
ret i1 %result
}

declare i1 @llvm.bitset.test(i8*, metadata)
declare i1 @llvm.type.test(i8*, metadata)
declare void @llvm.assume(i1)

!0 = !{!"bitset1", [1 x i8*]* @vt1, i32 0}
!1 = !{!"bitset1", [1 x i8*]* @vt2, i32 0}
!2 = !{!"bitset1", [1 x i8*]* @vt3, i32 0}
!3 = !{!"bitset2", [1 x i8*]* @vt2, i32 0}
!4 = !{!"bitset2", [1 x i8*]* @vt3, i32 0}
!5 = !{!"bitset2", [1 x i8*]* @vt4, i32 0}
!llvm.bitsets = !{!0, !1, !2, !3, !4, !5}
!0 = !{i32 0, !"typeid1"}
!1 = !{i32 0, !"typeid2"}
12 changes: 5 additions & 7 deletions llvm/test/Transforms/WholeProgramDevirt/vcp-accesses-memory.ll
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
target datalayout = "e-p:64:64"
target triple = "x86_64-unknown-linux-gnu"

@vt1 = global [1 x i8*] [i8* bitcast (i32 (i8*, i32)* @vf1 to i8*)]
@vt2 = global [1 x i8*] [i8* bitcast (i32 (i8*, i32)* @vf2 to i8*)]
@vt1 = global [1 x i8*] [i8* bitcast (i32 (i8*, i32)* @vf1 to i8*)], !type !0
@vt2 = global [1 x i8*] [i8* bitcast (i32 (i8*, i32)* @vf2 to i8*)], !type !0

define i32 @vf1(i8* %this, i32 %arg) {
ret i32 %arg
Expand All @@ -19,7 +19,7 @@ define i32 @call(i8* %obj) {
%vtableptr = bitcast i8* %obj to [1 x i8*]**
%vtable = load [1 x i8*]*, [1 x i8*]** %vtableptr
%vtablei8 = bitcast [1 x i8*]* %vtable to i8*
%p = call i1 @llvm.bitset.test(i8* %vtablei8, metadata !"bitset")
%p = call i1 @llvm.type.test(i8* %vtablei8, metadata !"typeid")
call void @llvm.assume(i1 %p)
%fptrptr = getelementptr [1 x i8*], [1 x i8*]* %vtable, i32 0, i32 0
%fptr = load i8*, i8** %fptrptr
Expand All @@ -29,9 +29,7 @@ define i32 @call(i8* %obj) {
ret i32 %result
}

declare i1 @llvm.bitset.test(i8*, metadata)
declare i1 @llvm.type.test(i8*, metadata)
declare void @llvm.assume(i1)

!0 = !{!"bitset", [1 x i8*]* @vt1, i32 0}
!1 = !{!"bitset", [1 x i8*]* @vt2, i32 0}
!llvm.bitsets = !{!0}
!0 = !{i32 0, !"typeid"}
12 changes: 5 additions & 7 deletions llvm/test/Transforms/WholeProgramDevirt/vcp-no-this.ll
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
target datalayout = "e-p:64:64"
target triple = "x86_64-unknown-linux-gnu"

@vt1 = global [1 x i8*] [i8* bitcast (i32 ()* @vf1 to i8*)]
@vt2 = global [1 x i8*] [i8* bitcast (i32 ()* @vf2 to i8*)]
@vt1 = global [1 x i8*] [i8* bitcast (i32 ()* @vf1 to i8*)], !type !0
@vt2 = global [1 x i8*] [i8* bitcast (i32 ()* @vf2 to i8*)], !type !0

define i32 @vf1() readnone {
ret i32 1
Expand All @@ -19,7 +19,7 @@ define i32 @call(i8* %obj) {
%vtableptr = bitcast i8* %obj to [1 x i8*]**
%vtable = load [1 x i8*]*, [1 x i8*]** %vtableptr
%vtablei8 = bitcast [1 x i8*]* %vtable to i8*
%p = call i1 @llvm.bitset.test(i8* %vtablei8, metadata !"bitset")
%p = call i1 @llvm.type.test(i8* %vtablei8, metadata !"typeid")
call void @llvm.assume(i1 %p)
%fptrptr = getelementptr [1 x i8*], [1 x i8*]* %vtable, i32 0, i32 0
%fptr = load i8*, i8** %fptrptr
Expand All @@ -29,9 +29,7 @@ define i32 @call(i8* %obj) {
ret i32 %result
}

declare i1 @llvm.bitset.test(i8*, metadata)
declare i1 @llvm.type.test(i8*, metadata)
declare void @llvm.assume(i1)

!0 = !{!"bitset", [1 x i8*]* @vt1, i32 0}
!1 = !{!"bitset", [1 x i8*]* @vt2, i32 0}
!llvm.bitsets = !{!0}
!0 = !{i32 0, !"typeid"}
12 changes: 5 additions & 7 deletions llvm/test/Transforms/WholeProgramDevirt/vcp-non-constant-arg.ll
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
target datalayout = "e-p:64:64"
target triple = "x86_64-unknown-linux-gnu"

@vt1 = global [1 x i8*] [i8* bitcast (i32 (i8*, i32)* @vf1 to i8*)]
@vt2 = global [1 x i8*] [i8* bitcast (i32 (i8*, i32)* @vf2 to i8*)]
@vt1 = global [1 x i8*] [i8* bitcast (i32 (i8*, i32)* @vf1 to i8*)], !type !0
@vt2 = global [1 x i8*] [i8* bitcast (i32 (i8*, i32)* @vf2 to i8*)], !type !0

define i32 @vf1(i8* %this, i32 %arg) readnone {
ret i32 %arg
Expand All @@ -19,7 +19,7 @@ define void @call(i8* %obj, i32 %arg) {
%vtableptr = bitcast i8* %obj to [1 x i8*]**
%vtable = load [1 x i8*]*, [1 x i8*]** %vtableptr
%vtablei8 = bitcast [1 x i8*]* %vtable to i8*
%p = call i1 @llvm.bitset.test(i8* %vtablei8, metadata !"bitset")
%p = call i1 @llvm.type.test(i8* %vtablei8, metadata !"typeid")
call void @llvm.assume(i1 %p)
%fptrptr = getelementptr [1 x i8*], [1 x i8*]* %vtable, i32 0, i32 0
%fptr = load i8*, i8** %fptrptr
Expand All @@ -29,9 +29,7 @@ define void @call(i8* %obj, i32 %arg) {
ret void
}

declare i1 @llvm.bitset.test(i8*, metadata)
declare i1 @llvm.type.test(i8*, metadata)
declare void @llvm.assume(i1)

!0 = !{!"bitset", [1 x i8*]* @vt1, i32 0}
!1 = !{!"bitset", [1 x i8*]* @vt2, i32 0}
!llvm.bitsets = !{!0}
!0 = !{i32 0, !"typeid"}
12 changes: 5 additions & 7 deletions llvm/test/Transforms/WholeProgramDevirt/vcp-too-wide-ints.ll
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
target datalayout = "e-p:64:64"
target triple = "x86_64-unknown-linux-gnu"

@vt1 = global [1 x i8*] [i8* bitcast (i128 (i8*, i128)* @vf1 to i8*)]
@vt2 = global [1 x i8*] [i8* bitcast (i128 (i8*, i128)* @vf2 to i8*)]
@vt1 = global [1 x i8*] [i8* bitcast (i128 (i8*, i128)* @vf1 to i8*)], !type !0
@vt2 = global [1 x i8*] [i8* bitcast (i128 (i8*, i128)* @vf2 to i8*)], !type !0

define i128 @vf1(i8* %this, i128 %arg) readnone {
ret i128 %arg
Expand All @@ -19,7 +19,7 @@ define i128 @call(i8* %obj) {
%vtableptr = bitcast i8* %obj to [1 x i8*]**
%vtable = load [1 x i8*]*, [1 x i8*]** %vtableptr
%vtablei8 = bitcast [1 x i8*]* %vtable to i8*
%p = call i1 @llvm.bitset.test(i8* %vtablei8, metadata !"bitset")
%p = call i1 @llvm.type.test(i8* %vtablei8, metadata !"typeid")
call void @llvm.assume(i1 %p)
%fptrptr = getelementptr [1 x i8*], [1 x i8*]* %vtable, i32 0, i32 0
%fptr = load i8*, i8** %fptrptr
Expand All @@ -29,9 +29,7 @@ define i128 @call(i8* %obj) {
ret i128 %result
}

declare i1 @llvm.bitset.test(i8*, metadata)
declare i1 @llvm.type.test(i8*, metadata)
declare void @llvm.assume(i1)

!0 = !{!"bitset", [1 x i8*]* @vt1, i32 0}
!1 = !{!"bitset", [1 x i8*]* @vt2, i32 0}
!llvm.bitsets = !{!0}
!0 = !{i32 0, !"typeid"}
16 changes: 7 additions & 9 deletions llvm/test/Transforms/WholeProgramDevirt/vcp-type-mismatch.ll
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
target datalayout = "e-p:64:64"
target triple = "x86_64-unknown-linux-gnu"

@vt1 = global [1 x i8*] [i8* bitcast (i32 (i8*, i32)* @vf1 to i8*)]
@vt2 = global [1 x i8*] [i8* bitcast (i32 (i8*, i32)* @vf2 to i8*)]
@vt1 = global [1 x i8*] [i8* bitcast (i32 (i8*, i32)* @vf1 to i8*)], !type !0
@vt2 = global [1 x i8*] [i8* bitcast (i32 (i8*, i32)* @vf2 to i8*)], !type !0

define i32 @vf1(i8* %this, i32 %arg) readnone {
ret i32 %arg
Expand All @@ -19,7 +19,7 @@ define i32 @bad_arg_type(i8* %obj) {
%vtableptr = bitcast i8* %obj to [1 x i8*]**
%vtable = load [1 x i8*]*, [1 x i8*]** %vtableptr
%vtablei8 = bitcast [1 x i8*]* %vtable to i8*
%p = call i1 @llvm.bitset.test(i8* %vtablei8, metadata !"bitset")
%p = call i1 @llvm.type.test(i8* %vtablei8, metadata !"typeid")
call void @llvm.assume(i1 %p)
%fptrptr = getelementptr [1 x i8*], [1 x i8*]* %vtable, i32 0, i32 0
%fptr = load i8*, i8** %fptrptr
Expand All @@ -34,7 +34,7 @@ define i32 @bad_arg_count(i8* %obj) {
%vtableptr = bitcast i8* %obj to [1 x i8*]**
%vtable = load [1 x i8*]*, [1 x i8*]** %vtableptr
%vtablei8 = bitcast [1 x i8*]* %vtable to i8*
%p = call i1 @llvm.bitset.test(i8* %vtablei8, metadata !"bitset")
%p = call i1 @llvm.type.test(i8* %vtablei8, metadata !"typeid")
call void @llvm.assume(i1 %p)
%fptrptr = getelementptr [1 x i8*], [1 x i8*]* %vtable, i32 0, i32 0
%fptr = load i8*, i8** %fptrptr
Expand All @@ -49,7 +49,7 @@ define i64 @bad_return_type(i8* %obj) {
%vtableptr = bitcast i8* %obj to [1 x i8*]**
%vtable = load [1 x i8*]*, [1 x i8*]** %vtableptr
%vtablei8 = bitcast [1 x i8*]* %vtable to i8*
%p = call i1 @llvm.bitset.test(i8* %vtablei8, metadata !"bitset")
%p = call i1 @llvm.type.test(i8* %vtablei8, metadata !"typeid")
call void @llvm.assume(i1 %p)
%fptrptr = getelementptr [1 x i8*], [1 x i8*]* %vtable, i32 0, i32 0
%fptr = load i8*, i8** %fptrptr
Expand All @@ -59,9 +59,7 @@ define i64 @bad_return_type(i8* %obj) {
ret i64 %result
}

declare i1 @llvm.bitset.test(i8*, metadata)
declare i1 @llvm.type.test(i8*, metadata)
declare void @llvm.assume(i1)

!0 = !{!"bitset", [1 x i8*]* @vt1, i32 0}
!1 = !{!"bitset", [1 x i8*]* @vt2, i32 0}
!llvm.bitsets = !{!0}
!0 = !{i32 0, !"typeid"}
12 changes: 5 additions & 7 deletions llvm/test/Transforms/WholeProgramDevirt/vcp-uses-this.ll
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
target datalayout = "e-p:64:64"
target triple = "x86_64-unknown-linux-gnu"

@vt1 = global [1 x i8*] [i8* bitcast (i32 (i8*)* @vf1 to i8*)]
@vt2 = global [1 x i8*] [i8* bitcast (i32 (i8*)* @vf2 to i8*)]
@vt1 = global [1 x i8*] [i8* bitcast (i32 (i8*)* @vf1 to i8*)], !type !0
@vt2 = global [1 x i8*] [i8* bitcast (i32 (i8*)* @vf2 to i8*)], !type !0

define i32 @vf1(i8* %this) readnone {
%this_int = ptrtoint i8* %this to i32
Expand All @@ -21,7 +21,7 @@ define i32 @call(i8* %obj) {
%vtableptr = bitcast i8* %obj to [1 x i8*]**
%vtable = load [1 x i8*]*, [1 x i8*]** %vtableptr
%vtablei8 = bitcast [1 x i8*]* %vtable to i8*
%p = call i1 @llvm.bitset.test(i8* %vtablei8, metadata !"bitset")
%p = call i1 @llvm.type.test(i8* %vtablei8, metadata !"typeid")
call void @llvm.assume(i1 %p)
%fptrptr = getelementptr [1 x i8*], [1 x i8*]* %vtable, i32 0, i32 0
%fptr = load i8*, i8** %fptrptr
Expand All @@ -31,9 +31,7 @@ define i32 @call(i8* %obj) {
ret i32 %result
}

declare i1 @llvm.bitset.test(i8*, metadata)
declare i1 @llvm.type.test(i8*, metadata)
declare void @llvm.assume(i1)

!0 = !{!"bitset", [1 x i8*]* @vt1, i32 0}
!1 = !{!"bitset", [1 x i8*]* @vt2, i32 0}
!llvm.bitsets = !{!0}
!0 = !{i32 0, !"typeid"}
25 changes: 10 additions & 15 deletions llvm/test/Transforms/WholeProgramDevirt/virtual-const-prop-begin.ll
Original file line number Diff line number Diff line change
Expand Up @@ -8,34 +8,34 @@ target triple = "x86_64-unknown-linux-gnu"
i8* bitcast (i1 (i8*)* @vf0i1 to i8*),
i8* bitcast (i1 (i8*)* @vf1i1 to i8*),
i8* bitcast (i32 (i8*)* @vf1i32 to i8*)
], section "vt1sec"
], section "vt1sec", !type !0

; CHECK: [[VT2DATA:@[^ ]*]] = private constant { [8 x i8], [3 x i8*], [0 x i8] } { [8 x i8] c"\00\00\00\02\02\00\00\00", [3 x i8*] [i8* bitcast (i1 (i8*)* @vf1i1 to i8*), i8* bitcast (i1 (i8*)* @vf0i1 to i8*), i8* bitcast (i32 (i8*)* @vf2i32 to i8*)], [0 x i8] zeroinitializer }{{$}}
@vt2 = constant [3 x i8*] [
i8* bitcast (i1 (i8*)* @vf1i1 to i8*),
i8* bitcast (i1 (i8*)* @vf0i1 to i8*),
i8* bitcast (i32 (i8*)* @vf2i32 to i8*)
]
], !type !0

; CHECK: [[VT3DATA:@[^ ]*]] = private constant { [8 x i8], [3 x i8*], [0 x i8] } { [8 x i8] c"\00\00\00\01\03\00\00\00", [3 x i8*] [i8* bitcast (i1 (i8*)* @vf0i1 to i8*), i8* bitcast (i1 (i8*)* @vf1i1 to i8*), i8* bitcast (i32 (i8*)* @vf3i32 to i8*)], [0 x i8] zeroinitializer }{{$}}
@vt3 = constant [3 x i8*] [
i8* bitcast (i1 (i8*)* @vf0i1 to i8*),
i8* bitcast (i1 (i8*)* @vf1i1 to i8*),
i8* bitcast (i32 (i8*)* @vf3i32 to i8*)
]
], !type !0

; CHECK: [[VT4DATA:@[^ ]*]] = private constant { [8 x i8], [3 x i8*], [0 x i8] } { [8 x i8] c"\00\00\00\02\04\00\00\00", [3 x i8*] [i8* bitcast (i1 (i8*)* @vf1i1 to i8*), i8* bitcast (i1 (i8*)* @vf0i1 to i8*), i8* bitcast (i32 (i8*)* @vf4i32 to i8*)], [0 x i8] zeroinitializer }{{$}}
@vt4 = constant [3 x i8*] [
i8* bitcast (i1 (i8*)* @vf1i1 to i8*),
i8* bitcast (i1 (i8*)* @vf0i1 to i8*),
i8* bitcast (i32 (i8*)* @vf4i32 to i8*)
]
], !type !0

@vt5 = constant [3 x i8*] [
i8* bitcast (void ()* @__cxa_pure_virtual to i8*),
i8* bitcast (void ()* @__cxa_pure_virtual to i8*),
i8* bitcast (void ()* @__cxa_pure_virtual to i8*)
]
], !type !0

; CHECK: @vt1 = alias [3 x i8*], getelementptr inbounds ({ [8 x i8], [3 x i8*], [0 x i8] }, { [8 x i8], [3 x i8*], [0 x i8] }* [[VT1DATA]], i32 0, i32 1)
; CHECK: @vt2 = alias [3 x i8*], getelementptr inbounds ({ [8 x i8], [3 x i8*], [0 x i8] }, { [8 x i8], [3 x i8*], [0 x i8] }* [[VT2DATA]], i32 0, i32 1)
Expand Down Expand Up @@ -72,7 +72,7 @@ define i1 @call1(i8* %obj) {
%vtable = load [3 x i8*]*, [3 x i8*]** %vtableptr
; CHECK: [[VT1:%[^ ]*]] = bitcast [3 x i8*]* {{.*}} to i8*
%vtablei8 = bitcast [3 x i8*]* %vtable to i8*
%p = call i1 @llvm.bitset.test(i8* %vtablei8, metadata !"bitset")
%p = call i1 @llvm.type.test(i8* %vtablei8, metadata !"typeid")
call void @llvm.assume(i1 %p)
%fptrptr = getelementptr [3 x i8*], [3 x i8*]* %vtable, i32 0, i32 0
%fptr = load i8*, i8** %fptrptr
Expand All @@ -92,7 +92,7 @@ define i1 @call2(i8* %obj) {
%vtable = load [3 x i8*]*, [3 x i8*]** %vtableptr
; CHECK: [[VT2:%[^ ]*]] = bitcast [3 x i8*]* {{.*}} to i8*
%vtablei8 = bitcast [3 x i8*]* %vtable to i8*
%p = call i1 @llvm.bitset.test(i8* %vtablei8, metadata !"bitset")
%p = call i1 @llvm.type.test(i8* %vtablei8, metadata !"typeid")
call void @llvm.assume(i1 %p)
%fptrptr = getelementptr [3 x i8*], [3 x i8*]* %vtable, i32 0, i32 1
%fptr = load i8*, i8** %fptrptr
Expand All @@ -112,7 +112,7 @@ define i32 @call3(i8* %obj) {
%vtable = load [3 x i8*]*, [3 x i8*]** %vtableptr
; CHECK: [[VT3:%[^ ]*]] = bitcast [3 x i8*]* {{.*}} to i8*
%vtablei8 = bitcast [3 x i8*]* %vtable to i8*
%p = call i1 @llvm.bitset.test(i8* %vtablei8, metadata !"bitset")
%p = call i1 @llvm.type.test(i8* %vtablei8, metadata !"typeid")
call void @llvm.assume(i1 %p)
%fptrptr = getelementptr [3 x i8*], [3 x i8*]* %vtable, i32 0, i32 2
%fptr = load i8*, i8** %fptrptr
Expand All @@ -125,13 +125,8 @@ define i32 @call3(i8* %obj) {
ret i32 %result
}

declare i1 @llvm.bitset.test(i8*, metadata)
declare i1 @llvm.type.test(i8*, metadata)
declare void @llvm.assume(i1)
declare void @__cxa_pure_virtual()

!0 = !{!"bitset", [3 x i8*]* @vt1, i32 0}
!1 = !{!"bitset", [3 x i8*]* @vt2, i32 0}
!2 = !{!"bitset", [3 x i8*]* @vt3, i32 0}
!3 = !{!"bitset", [3 x i8*]* @vt4, i32 0}
!4 = !{!"bitset", [3 x i8*]* @vt5, i32 0}
!llvm.bitsets = !{!0, !1, !2, !3, !4}
!0 = !{i32 0, !"typeid"}
23 changes: 10 additions & 13 deletions llvm/test/Transforms/WholeProgramDevirt/virtual-const-prop-end.ll
Original file line number Diff line number Diff line change
Expand Up @@ -9,29 +9,29 @@ i8* null,
i8* bitcast (i1 (i8*)* @vf0i1 to i8*),
i8* bitcast (i1 (i8*)* @vf1i1 to i8*),
i8* bitcast (i32 (i8*)* @vf1i32 to i8*)
]
], !type !1

; CHECK: [[VT2DATA:@[^ ]*]] = private constant { [0 x i8], [3 x i8*], [8 x i8] } { [0 x i8] zeroinitializer, [3 x i8*] [i8* bitcast (i1 (i8*)* @vf1i1 to i8*), i8* bitcast (i1 (i8*)* @vf0i1 to i8*), i8* bitcast (i32 (i8*)* @vf2i32 to i8*)], [8 x i8] c"\02\00\00\00\02\00\00\00" }
@vt2 = constant [3 x i8*] [
i8* bitcast (i1 (i8*)* @vf1i1 to i8*),
i8* bitcast (i1 (i8*)* @vf0i1 to i8*),
i8* bitcast (i32 (i8*)* @vf2i32 to i8*)
]
], !type !0

; CHECK: [[VT3DATA:@[^ ]*]] = private constant { [0 x i8], [4 x i8*], [8 x i8] } { [0 x i8] zeroinitializer, [4 x i8*] [i8* null, i8* bitcast (i1 (i8*)* @vf0i1 to i8*), i8* bitcast (i1 (i8*)* @vf1i1 to i8*), i8* bitcast (i32 (i8*)* @vf3i32 to i8*)], [8 x i8] c"\03\00\00\00\01\00\00\00" }
@vt3 = constant [4 x i8*] [
i8* null,
i8* bitcast (i1 (i8*)* @vf0i1 to i8*),
i8* bitcast (i1 (i8*)* @vf1i1 to i8*),
i8* bitcast (i32 (i8*)* @vf3i32 to i8*)
]
], !type !1

; CHECK: [[VT4DATA:@[^ ]*]] = private constant { [0 x i8], [3 x i8*], [8 x i8] } { [0 x i8] zeroinitializer, [3 x i8*] [i8* bitcast (i1 (i8*)* @vf1i1 to i8*), i8* bitcast (i1 (i8*)* @vf0i1 to i8*), i8* bitcast (i32 (i8*)* @vf4i32 to i8*)], [8 x i8] c"\04\00\00\00\02\00\00\00" }
@vt4 = constant [3 x i8*] [
i8* bitcast (i1 (i8*)* @vf1i1 to i8*),
i8* bitcast (i1 (i8*)* @vf0i1 to i8*),
i8* bitcast (i32 (i8*)* @vf4i32 to i8*)
]
], !type !0

; CHECK: @vt1 = alias [4 x i8*], getelementptr inbounds ({ [0 x i8], [4 x i8*], [8 x i8] }, { [0 x i8], [4 x i8*], [8 x i8] }* [[VT1DATA]], i32 0, i32 1)
; CHECK: @vt2 = alias [3 x i8*], getelementptr inbounds ({ [0 x i8], [3 x i8*], [8 x i8] }, { [0 x i8], [3 x i8*], [8 x i8] }* [[VT2DATA]], i32 0, i32 1)
Expand Down Expand Up @@ -68,7 +68,7 @@ define i1 @call1(i8* %obj) {
%vtable = load [3 x i8*]*, [3 x i8*]** %vtableptr
; CHECK: [[VT1:%[^ ]*]] = bitcast [3 x i8*]* {{.*}} to i8*
%vtablei8 = bitcast [3 x i8*]* %vtable to i8*
%p = call i1 @llvm.bitset.test(i8* %vtablei8, metadata !"bitset")
%p = call i1 @llvm.type.test(i8* %vtablei8, metadata !"typeid")
call void @llvm.assume(i1 %p)
%fptrptr = getelementptr [3 x i8*], [3 x i8*]* %vtable, i32 0, i32 0
%fptr = load i8*, i8** %fptrptr
Expand All @@ -88,7 +88,7 @@ define i1 @call2(i8* %obj) {
%vtable = load [3 x i8*]*, [3 x i8*]** %vtableptr
; CHECK: [[VT2:%[^ ]*]] = bitcast [3 x i8*]* {{.*}} to i8*
%vtablei8 = bitcast [3 x i8*]* %vtable to i8*
%p = call i1 @llvm.bitset.test(i8* %vtablei8, metadata !"bitset")
%p = call i1 @llvm.type.test(i8* %vtablei8, metadata !"typeid")
call void @llvm.assume(i1 %p)
%fptrptr = getelementptr [3 x i8*], [3 x i8*]* %vtable, i32 0, i32 1
%fptr = load i8*, i8** %fptrptr
Expand All @@ -108,7 +108,7 @@ define i32 @call3(i8* %obj) {
%vtable = load [3 x i8*]*, [3 x i8*]** %vtableptr
; CHECK: [[VT3:%[^ ]*]] = bitcast [3 x i8*]* {{.*}} to i8*
%vtablei8 = bitcast [3 x i8*]* %vtable to i8*
%p = call i1 @llvm.bitset.test(i8* %vtablei8, metadata !"bitset")
%p = call i1 @llvm.type.test(i8* %vtablei8, metadata !"typeid")
call void @llvm.assume(i1 %p)
%fptrptr = getelementptr [3 x i8*], [3 x i8*]* %vtable, i32 0, i32 2
%fptr = load i8*, i8** %fptrptr
Expand All @@ -121,11 +121,8 @@ define i32 @call3(i8* %obj) {
ret i32 %result
}

declare i1 @llvm.bitset.test(i8*, metadata)
declare i1 @llvm.type.test(i8*, metadata)
declare void @llvm.assume(i1)

!0 = !{!"bitset", [4 x i8*]* @vt1, i32 8}
!1 = !{!"bitset", [3 x i8*]* @vt2, i32 0}
!2 = !{!"bitset", [4 x i8*]* @vt3, i32 8}
!3 = !{!"bitset", [3 x i8*]* @vt4, i32 0}
!llvm.bitsets = !{!0, !1, !2, !3}
!0 = !{i32 0, !"typeid"}
!1 = !{i32 8, !"typeid"}
17 changes: 9 additions & 8 deletions llvm/test/tools/gold/X86/opt-level.ll
Original file line number Diff line number Diff line change
Expand Up @@ -34,17 +34,18 @@ end:
ret i32 %r
}

define void @baz() {
define i1 @baz() {
call void @foo()
%c = call i32 @bar(i1 true)
ret void
%p = call i1 @llvm.type.test(i8* undef, metadata !"typeid1")
ret i1 %p
}

@a = constant i32 1
; CHECK-O0-NOT: !type
; CHECK-O1-NOT: !type
; CHECK-O2-NOT: !type
@a = constant i32 1, !type !0

!0 = !{!"bitset1", i32* @a, i32 0}
!0 = !{i32 0, !"typeid1"}

; CHECK-O0-NOT: llvm.bitsets
; CHECK-O1-NOT: llvm.bitsets
; CHECK-O2-NOT: llvm.bitsets
!llvm.bitsets = !{ !0 }
declare i1 @llvm.type.test(i8* %ptr, metadata %bitset) nounwind readnone
2 changes: 1 addition & 1 deletion llvm/unittests/Transforms/IPO/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@ set(LLVM_LINK_COMPONENTS
)

add_llvm_unittest(IPOTests
LowerBitSets.cpp
LowerTypeTests.cpp
WholeProgramDevirt.cpp
)
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//===- LowerBitSets.cpp - Unit tests for bitset lowering ------------------===//
//===- LowerTypeTests.cpp - Unit tests for type test lowering -------------===//
//
// The LLVM Compiler Infrastructure
//
Expand All @@ -7,13 +7,13 @@
//
//===----------------------------------------------------------------------===//

#include "llvm/Transforms/IPO/LowerBitSets.h"
#include "llvm/Transforms/IPO/LowerTypeTests.h"
#include "gtest/gtest.h"

using namespace llvm;
using namespace lowerbitsets;
using namespace lowertypetests;

TEST(LowerBitSets, BitSetBuilder) {
TEST(LowerTypeTests, BitSetBuilder) {
struct {
std::vector<uint64_t> Offsets;
std::set<uint64_t> Bits;
Expand Down Expand Up @@ -80,7 +80,7 @@ TEST(LowerBitSets, BitSetBuilder) {
}
}

TEST(LowerBitSets, GlobalLayoutBuilder) {
TEST(LowerTypeTests, GlobalLayoutBuilder) {
struct {
uint64_t NumObjects;
std::vector<std::set<uint64_t>> Fragments;
Expand All @@ -107,7 +107,7 @@ TEST(LowerBitSets, GlobalLayoutBuilder) {
}
}

TEST(LowerBitSets, ByteArrayBuilder) {
TEST(LowerTypeTests, ByteArrayBuilder) {
struct BABAlloc {
std::set<uint64_t> Bits;
uint64_t BitSize;
Expand Down
26 changes: 13 additions & 13 deletions llvm/unittests/Transforms/IPO/WholeProgramDevirt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,11 @@ TEST(WholeProgramDevirt, findLowestOffset) {
VT2.Before.BytesUsed = {1 << 1};
VT2.After.BytesUsed = {1 << 0};

BitSetInfo BS1{&VT1, 0};
BitSetInfo BS2{&VT2, 0};
TypeMemberInfo TM1{&VT1, 0};
TypeMemberInfo TM2{&VT2, 0};
VirtualCallTarget Targets[] = {
{&BS1, /*IsBigEndian=*/false},
{&BS2, /*IsBigEndian=*/false},
{&TM1, /*IsBigEndian=*/false},
{&TM2, /*IsBigEndian=*/false},
};

EXPECT_EQ(2ull, findLowestOffset(Targets, /*IsAfter=*/false, 1));
Expand All @@ -38,15 +38,15 @@ TEST(WholeProgramDevirt, findLowestOffset) {
EXPECT_EQ(8ull, findLowestOffset(Targets, /*IsAfter=*/false, 8));
EXPECT_EQ(72ull, findLowestOffset(Targets, /*IsAfter=*/true, 8));

BS1.Offset = 4;
TM1.Offset = 4;
EXPECT_EQ(33ull, findLowestOffset(Targets, /*IsAfter=*/false, 1));
EXPECT_EQ(65ull, findLowestOffset(Targets, /*IsAfter=*/true, 1));

EXPECT_EQ(40ull, findLowestOffset(Targets, /*IsAfter=*/false, 8));
EXPECT_EQ(72ull, findLowestOffset(Targets, /*IsAfter=*/true, 8));

BS1.Offset = 8;
BS2.Offset = 8;
TM1.Offset = 8;
TM2.Offset = 8;
EXPECT_EQ(66ull, findLowestOffset(Targets, /*IsAfter=*/false, 1));
EXPECT_EQ(2ull, findLowestOffset(Targets, /*IsAfter=*/true, 1));

Expand All @@ -66,15 +66,15 @@ TEST(WholeProgramDevirt, setReturnValues) {
VTableBits VT2;
VT2.ObjectSize = 8;

BitSetInfo BS1{&VT1, 0};
BitSetInfo BS2{&VT2, 0};
TypeMemberInfo TM1{&VT1, 0};
TypeMemberInfo TM2{&VT2, 0};
VirtualCallTarget Targets[] = {
{&BS1, /*IsBigEndian=*/false},
{&BS2, /*IsBigEndian=*/false},
{&TM1, /*IsBigEndian=*/false},
{&TM2, /*IsBigEndian=*/false},
};

BS1.Offset = 4;
BS2.Offset = 4;
TM1.Offset = 4;
TM2.Offset = 4;

int64_t OffsetByte;
uint64_t OffsetBit;
Expand Down