1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-10-20 03:23:01 +02:00
llvm-mirror/include/llvm/ADT/PointerUnion.h
Peter Collingbourne 1834ad0e4a Use branch funnels for virtual calls when retpoline mitigation is enabled.
The retpoline mitigation for variant 2 of CVE-2017-5715 inhibits the
branch predictor, and as a result it can lead to a measurable loss of
performance. We can reduce the performance impact of retpolined virtual
calls by replacing them with a special construct known as a branch
funnel, which is an instruction sequence that implements virtual calls
to a set of known targets using a binary tree of direct branches. This
allows the processor to speculately execute valid implementations of the
virtual function without allowing for speculative execution of of calls
to arbitrary addresses.

This patch extends the whole-program devirtualization pass to replace
certain virtual calls with calls to branch funnels, which are
represented using a new llvm.icall.jumptable intrinsic. It also extends
the LowerTypeTests pass to recognize the new intrinsic, generate code
for the branch funnels (x86_64 only for now) and lay out virtual tables
as required for each branch funnel.

The implementation supports full LTO as well as ThinLTO, and extends the
ThinLTO summary format used for whole-program devirtualization to
support branch funnels.

For more details see RFC:
http://lists.llvm.org/pipermail/llvm-dev/2018-January/120672.html

Differential Revision: https://reviews.llvm.org/D42453

llvm-svn: 327163
2018-03-09 19:11:44 +00:00

492 lines
16 KiB
C++

//===- llvm/ADT/PointerUnion.h - Discriminated Union of 2 Ptrs --*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines the PointerUnion class, which is a discriminated union of
// pointer types.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_ADT_POINTERUNION_H
#define LLVM_ADT_POINTERUNION_H
#include "llvm/ADT/DenseMapInfo.h"
#include "llvm/ADT/PointerIntPair.h"
#include "llvm/Support/PointerLikeTypeTraits.h"
#include <cassert>
#include <cstddef>
#include <cstdint>
namespace llvm {
template <typename T> struct PointerUnionTypeSelectorReturn {
using Return = T;
};
/// Get a type based on whether two types are the same or not.
///
/// For:
///
/// \code
/// using Ret = typename PointerUnionTypeSelector<T1, T2, EQ, NE>::Return;
/// \endcode
///
/// Ret will be EQ type if T1 is same as T2 or NE type otherwise.
template <typename T1, typename T2, typename RET_EQ, typename RET_NE>
struct PointerUnionTypeSelector {
using Return = typename PointerUnionTypeSelectorReturn<RET_NE>::Return;
};
template <typename T, typename RET_EQ, typename RET_NE>
struct PointerUnionTypeSelector<T, T, RET_EQ, RET_NE> {
using Return = typename PointerUnionTypeSelectorReturn<RET_EQ>::Return;
};
template <typename T1, typename T2, typename RET_EQ, typename RET_NE>
struct PointerUnionTypeSelectorReturn<
PointerUnionTypeSelector<T1, T2, RET_EQ, RET_NE>> {
using Return =
typename PointerUnionTypeSelector<T1, T2, RET_EQ, RET_NE>::Return;
};
/// Provide PointerLikeTypeTraits for void* that is used by PointerUnion
/// for the two template arguments.
template <typename PT1, typename PT2> class PointerUnionUIntTraits {
public:
static inline void *getAsVoidPointer(void *P) { return P; }
static inline void *getFromVoidPointer(void *P) { return P; }
enum {
PT1BitsAv = (int)(PointerLikeTypeTraits<PT1>::NumLowBitsAvailable),
PT2BitsAv = (int)(PointerLikeTypeTraits<PT2>::NumLowBitsAvailable),
NumLowBitsAvailable = PT1BitsAv < PT2BitsAv ? PT1BitsAv : PT2BitsAv
};
};
/// A discriminated union of two pointer types, with the discriminator in the
/// low bit of the pointer.
///
/// This implementation is extremely efficient in space due to leveraging the
/// low bits of the pointer, while exposing a natural and type-safe API.
///
/// Common use patterns would be something like this:
/// PointerUnion<int*, float*> P;
/// P = (int*)0;
/// printf("%d %d", P.is<int*>(), P.is<float*>()); // prints "1 0"
/// X = P.get<int*>(); // ok.
/// Y = P.get<float*>(); // runtime assertion failure.
/// Z = P.get<double*>(); // compile time failure.
/// P = (float*)0;
/// Y = P.get<float*>(); // ok.
/// X = P.get<int*>(); // runtime assertion failure.
template <typename PT1, typename PT2> class PointerUnion {
public:
using ValTy =
PointerIntPair<void *, 1, bool, PointerUnionUIntTraits<PT1, PT2>>;
private:
ValTy Val;
struct IsPT1 {
static const int Num = 0;
};
struct IsPT2 {
static const int Num = 1;
};
template <typename T> struct UNION_DOESNT_CONTAIN_TYPE {};
public:
PointerUnion() = default;
PointerUnion(PT1 V)
: Val(const_cast<void *>(
PointerLikeTypeTraits<PT1>::getAsVoidPointer(V))) {}
PointerUnion(PT2 V)
: Val(const_cast<void *>(PointerLikeTypeTraits<PT2>::getAsVoidPointer(V)),
1) {}
/// Test if the pointer held in the union is null, regardless of
/// which type it is.
bool isNull() const {
// Convert from the void* to one of the pointer types, to make sure that
// we recursively strip off low bits if we have a nested PointerUnion.
return !PointerLikeTypeTraits<PT1>::getFromVoidPointer(Val.getPointer());
}
explicit operator bool() const { return !isNull(); }
/// Test if the Union currently holds the type matching T.
template <typename T> int is() const {
using Ty = typename ::llvm::PointerUnionTypeSelector<
PT1, T, IsPT1,
::llvm::PointerUnionTypeSelector<PT2, T, IsPT2,
UNION_DOESNT_CONTAIN_TYPE<T>>>::Return;
int TyNo = Ty::Num;
return static_cast<int>(Val.getInt()) == TyNo;
}
/// Returns the value of the specified pointer type.
///
/// If the specified pointer type is incorrect, assert.
template <typename T> T get() const {
assert(is<T>() && "Invalid accessor called");
return PointerLikeTypeTraits<T>::getFromVoidPointer(Val.getPointer());
}
/// Returns the current pointer if it is of the specified pointer type,
/// otherwises returns null.
template <typename T> T dyn_cast() const {
if (is<T>())
return get<T>();
return T();
}
/// If the union is set to the first pointer type get an address pointing to
/// it.
PT1 const *getAddrOfPtr1() const {
return const_cast<PointerUnion *>(this)->getAddrOfPtr1();
}
/// If the union is set to the first pointer type get an address pointing to
/// it.
PT1 *getAddrOfPtr1() {
assert(is<PT1>() && "Val is not the first pointer");
assert(
get<PT1>() == Val.getPointer() &&
"Can't get the address because PointerLikeTypeTraits changes the ptr");
return const_cast<PT1 *>(
reinterpret_cast<const PT1 *>(Val.getAddrOfPointer()));
}
/// Assignment from nullptr which just clears the union.
const PointerUnion &operator=(std::nullptr_t) {
Val.initWithPointer(nullptr);
return *this;
}
/// Assignment operators - Allow assigning into this union from either
/// pointer type, setting the discriminator to remember what it came from.
const PointerUnion &operator=(const PT1 &RHS) {
Val.initWithPointer(
const_cast<void *>(PointerLikeTypeTraits<PT1>::getAsVoidPointer(RHS)));
return *this;
}
const PointerUnion &operator=(const PT2 &RHS) {
Val.setPointerAndInt(
const_cast<void *>(PointerLikeTypeTraits<PT2>::getAsVoidPointer(RHS)),
1);
return *this;
}
void *getOpaqueValue() const { return Val.getOpaqueValue(); }
static inline PointerUnion getFromOpaqueValue(void *VP) {
PointerUnion V;
V.Val = ValTy::getFromOpaqueValue(VP);
return V;
}
};
template <typename PT1, typename PT2>
bool operator==(PointerUnion<PT1, PT2> lhs, PointerUnion<PT1, PT2> rhs) {
return lhs.getOpaqueValue() == rhs.getOpaqueValue();
}
template <typename PT1, typename PT2>
bool operator!=(PointerUnion<PT1, PT2> lhs, PointerUnion<PT1, PT2> rhs) {
return lhs.getOpaqueValue() != rhs.getOpaqueValue();
}
template <typename PT1, typename PT2>
bool operator<(PointerUnion<PT1, PT2> lhs, PointerUnion<PT1, PT2> rhs) {
return lhs.getOpaqueValue() < rhs.getOpaqueValue();
}
// Teach SmallPtrSet that PointerUnion is "basically a pointer", that has
// # low bits available = min(PT1bits,PT2bits)-1.
template <typename PT1, typename PT2>
struct PointerLikeTypeTraits<PointerUnion<PT1, PT2>> {
static inline void *getAsVoidPointer(const PointerUnion<PT1, PT2> &P) {
return P.getOpaqueValue();
}
static inline PointerUnion<PT1, PT2> getFromVoidPointer(void *P) {
return PointerUnion<PT1, PT2>::getFromOpaqueValue(P);
}
// The number of bits available are the min of the two pointer types.
enum {
NumLowBitsAvailable = PointerLikeTypeTraits<
typename PointerUnion<PT1, PT2>::ValTy>::NumLowBitsAvailable
};
};
/// A pointer union of three pointer types. See documentation for PointerUnion
/// for usage.
template <typename PT1, typename PT2, typename PT3> class PointerUnion3 {
public:
using InnerUnion = PointerUnion<PT1, PT2>;
using ValTy = PointerUnion<InnerUnion, PT3>;
private:
ValTy Val;
struct IsInnerUnion {
ValTy Val;
IsInnerUnion(ValTy val) : Val(val) {}
template <typename T> int is() const {
return Val.template is<InnerUnion>() &&
Val.template get<InnerUnion>().template is<T>();
}
template <typename T> T get() const {
return Val.template get<InnerUnion>().template get<T>();
}
};
struct IsPT3 {
ValTy Val;
IsPT3(ValTy val) : Val(val) {}
template <typename T> int is() const { return Val.template is<T>(); }
template <typename T> T get() const { return Val.template get<T>(); }
};
public:
PointerUnion3() = default;
PointerUnion3(PT1 V) { Val = InnerUnion(V); }
PointerUnion3(PT2 V) { Val = InnerUnion(V); }
PointerUnion3(PT3 V) { Val = V; }
/// Test if the pointer held in the union is null, regardless of
/// which type it is.
bool isNull() const { return Val.isNull(); }
explicit operator bool() const { return !isNull(); }
/// Test if the Union currently holds the type matching T.
template <typename T> int is() const {
// If T is PT1/PT2 choose IsInnerUnion otherwise choose IsPT3.
using Ty = typename ::llvm::PointerUnionTypeSelector<
PT1, T, IsInnerUnion,
::llvm::PointerUnionTypeSelector<PT2, T, IsInnerUnion, IsPT3>>::Return;
return Ty(Val).template is<T>();
}
/// Returns the value of the specified pointer type.
///
/// If the specified pointer type is incorrect, assert.
template <typename T> T get() const {
assert(is<T>() && "Invalid accessor called");
// If T is PT1/PT2 choose IsInnerUnion otherwise choose IsPT3.
using Ty = typename ::llvm::PointerUnionTypeSelector<
PT1, T, IsInnerUnion,
::llvm::PointerUnionTypeSelector<PT2, T, IsInnerUnion, IsPT3>>::Return;
return Ty(Val).template get<T>();
}
/// Returns the current pointer if it is of the specified pointer type,
/// otherwises returns null.
template <typename T> T dyn_cast() const {
if (is<T>())
return get<T>();
return T();
}
/// Assignment from nullptr which just clears the union.
const PointerUnion3 &operator=(std::nullptr_t) {
Val = nullptr;
return *this;
}
/// Assignment operators - Allow assigning into this union from either
/// pointer type, setting the discriminator to remember what it came from.
const PointerUnion3 &operator=(const PT1 &RHS) {
Val = InnerUnion(RHS);
return *this;
}
const PointerUnion3 &operator=(const PT2 &RHS) {
Val = InnerUnion(RHS);
return *this;
}
const PointerUnion3 &operator=(const PT3 &RHS) {
Val = RHS;
return *this;
}
void *getOpaqueValue() const { return Val.getOpaqueValue(); }
static inline PointerUnion3 getFromOpaqueValue(void *VP) {
PointerUnion3 V;
V.Val = ValTy::getFromOpaqueValue(VP);
return V;
}
};
// Teach SmallPtrSet that PointerUnion3 is "basically a pointer", that has
// # low bits available = min(PT1bits,PT2bits,PT2bits)-2.
template <typename PT1, typename PT2, typename PT3>
struct PointerLikeTypeTraits<PointerUnion3<PT1, PT2, PT3>> {
static inline void *getAsVoidPointer(const PointerUnion3<PT1, PT2, PT3> &P) {
return P.getOpaqueValue();
}
static inline PointerUnion3<PT1, PT2, PT3> getFromVoidPointer(void *P) {
return PointerUnion3<PT1, PT2, PT3>::getFromOpaqueValue(P);
}
// The number of bits available are the min of the two pointer types.
enum {
NumLowBitsAvailable = PointerLikeTypeTraits<
typename PointerUnion3<PT1, PT2, PT3>::ValTy>::NumLowBitsAvailable
};
};
template <typename PT1, typename PT2, typename PT3>
bool operator<(PointerUnion3<PT1, PT2, PT3> lhs,
PointerUnion3<PT1, PT2, PT3> rhs) {
return lhs.getOpaqueValue() < rhs.getOpaqueValue();
}
/// A pointer union of four pointer types. See documentation for PointerUnion
/// for usage.
template <typename PT1, typename PT2, typename PT3, typename PT4>
class PointerUnion4 {
public:
using InnerUnion1 = PointerUnion<PT1, PT2>;
using InnerUnion2 = PointerUnion<PT3, PT4>;
using ValTy = PointerUnion<InnerUnion1, InnerUnion2>;
private:
ValTy Val;
public:
PointerUnion4() = default;
PointerUnion4(PT1 V) { Val = InnerUnion1(V); }
PointerUnion4(PT2 V) { Val = InnerUnion1(V); }
PointerUnion4(PT3 V) { Val = InnerUnion2(V); }
PointerUnion4(PT4 V) { Val = InnerUnion2(V); }
/// Test if the pointer held in the union is null, regardless of
/// which type it is.
bool isNull() const { return Val.isNull(); }
explicit operator bool() const { return !isNull(); }
/// Test if the Union currently holds the type matching T.
template <typename T> int is() const {
// If T is PT1/PT2 choose InnerUnion1 otherwise choose InnerUnion2.
using Ty = typename ::llvm::PointerUnionTypeSelector<
PT1, T, InnerUnion1,
::llvm::PointerUnionTypeSelector<PT2, T, InnerUnion1,
InnerUnion2>>::Return;
return Val.template is<Ty>() && Val.template get<Ty>().template is<T>();
}
/// Returns the value of the specified pointer type.
///
/// If the specified pointer type is incorrect, assert.
template <typename T> T get() const {
assert(is<T>() && "Invalid accessor called");
// If T is PT1/PT2 choose InnerUnion1 otherwise choose InnerUnion2.
using Ty = typename ::llvm::PointerUnionTypeSelector<
PT1, T, InnerUnion1,
::llvm::PointerUnionTypeSelector<PT2, T, InnerUnion1,
InnerUnion2>>::Return;
return Val.template get<Ty>().template get<T>();
}
/// Returns the current pointer if it is of the specified pointer type,
/// otherwises returns null.
template <typename T> T dyn_cast() const {
if (is<T>())
return get<T>();
return T();
}
/// Assignment from nullptr which just clears the union.
const PointerUnion4 &operator=(std::nullptr_t) {
Val = nullptr;
return *this;
}
/// Assignment operators - Allow assigning into this union from either
/// pointer type, setting the discriminator to remember what it came from.
const PointerUnion4 &operator=(const PT1 &RHS) {
Val = InnerUnion1(RHS);
return *this;
}
const PointerUnion4 &operator=(const PT2 &RHS) {
Val = InnerUnion1(RHS);
return *this;
}
const PointerUnion4 &operator=(const PT3 &RHS) {
Val = InnerUnion2(RHS);
return *this;
}
const PointerUnion4 &operator=(const PT4 &RHS) {
Val = InnerUnion2(RHS);
return *this;
}
void *getOpaqueValue() const { return Val.getOpaqueValue(); }
static inline PointerUnion4 getFromOpaqueValue(void *VP) {
PointerUnion4 V;
V.Val = ValTy::getFromOpaqueValue(VP);
return V;
}
};
// Teach SmallPtrSet that PointerUnion4 is "basically a pointer", that has
// # low bits available = min(PT1bits,PT2bits,PT2bits)-2.
template <typename PT1, typename PT2, typename PT3, typename PT4>
struct PointerLikeTypeTraits<PointerUnion4<PT1, PT2, PT3, PT4>> {
static inline void *
getAsVoidPointer(const PointerUnion4<PT1, PT2, PT3, PT4> &P) {
return P.getOpaqueValue();
}
static inline PointerUnion4<PT1, PT2, PT3, PT4> getFromVoidPointer(void *P) {
return PointerUnion4<PT1, PT2, PT3, PT4>::getFromOpaqueValue(P);
}
// The number of bits available are the min of the two pointer types.
enum {
NumLowBitsAvailable = PointerLikeTypeTraits<
typename PointerUnion4<PT1, PT2, PT3, PT4>::ValTy>::NumLowBitsAvailable
};
};
// Teach DenseMap how to use PointerUnions as keys.
template <typename T, typename U> struct DenseMapInfo<PointerUnion<T, U>> {
using Pair = PointerUnion<T, U>;
using FirstInfo = DenseMapInfo<T>;
using SecondInfo = DenseMapInfo<U>;
static inline Pair getEmptyKey() { return Pair(FirstInfo::getEmptyKey()); }
static inline Pair getTombstoneKey() {
return Pair(FirstInfo::getTombstoneKey());
}
static unsigned getHashValue(const Pair &PairVal) {
intptr_t key = (intptr_t)PairVal.getOpaqueValue();
return DenseMapInfo<intptr_t>::getHashValue(key);
}
static bool isEqual(const Pair &LHS, const Pair &RHS) {
return LHS.template is<T>() == RHS.template is<T>() &&
(LHS.template is<T>() ? FirstInfo::isEqual(LHS.template get<T>(),
RHS.template get<T>())
: SecondInfo::isEqual(LHS.template get<U>(),
RHS.template get<U>()));
}
};
} // end namespace llvm
#endif // LLVM_ADT_POINTERUNION_H