Update llvm, clang and lldb to trunk r257626, and update build glue.
This commit is contained in:
commit
8e5c968a84
@ -53,10 +53,10 @@ class IntEqClasses {
|
||||
NumClasses = 0;
|
||||
}
|
||||
|
||||
/// join - Join the equivalence classes of a and b. After joining classes,
|
||||
/// findLeader(a) == findLeader(b).
|
||||
/// This requires an uncompressed map.
|
||||
void join(unsigned a, unsigned b);
|
||||
/// Join the equivalence classes of a and b. After joining classes,
|
||||
/// findLeader(a) == findLeader(b). This requires an uncompressed map.
|
||||
/// Returns the new leader.
|
||||
unsigned join(unsigned a, unsigned b);
|
||||
|
||||
/// findLeader - Compute the leader of a's equivalence class. This is the
|
||||
/// smallest member of the class.
|
||||
|
103
contrib/llvm/include/llvm/ADT/PointerEmbeddedInt.h
Normal file
103
contrib/llvm/include/llvm/ADT/PointerEmbeddedInt.h
Normal file
@ -0,0 +1,103 @@
|
||||
//===- llvm/ADT/PointerEmbeddedInt.h ----------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_ADT_POINTEREMBEDDEDINT_H
|
||||
#define LLVM_ADT_POINTEREMBEDDEDINT_H
|
||||
|
||||
#include "llvm/ADT/DenseMapInfo.h"
|
||||
#include "llvm/Support/PointerLikeTypeTraits.h"
|
||||
#include <climits>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
/// Utility to embed an integer into a pointer-like type. This is specifically
|
||||
/// intended to allow embedding integers where fewer bits are required than
|
||||
/// exist in a pointer, and the integer can participate in abstractions along
|
||||
/// side other pointer-like types. For example it can be placed into a \c
|
||||
/// PointerSumType or \c PointerUnion.
|
||||
///
|
||||
/// Note that much like pointers, an integer value of zero has special utility
|
||||
/// due to boolean conversions. For example, a non-null value can be tested for
|
||||
/// in the above abstractions without testing the particular active member.
|
||||
/// Also, the default constructed value zero initializes the integer.
|
||||
template <typename IntT, int Bits = sizeof(IntT) * CHAR_BIT>
|
||||
class PointerEmbeddedInt {
|
||||
uintptr_t Value;
|
||||
|
||||
static_assert(Bits < sizeof(uintptr_t) * CHAR_BIT,
|
||||
"Cannot embed more bits than we have in a pointer!");
|
||||
|
||||
enum : uintptr_t {
|
||||
// We shift as many zeros into the value as we can while preserving the
|
||||
// number of bits desired for the integer.
|
||||
Shift = sizeof(uintptr_t) * CHAR_BIT - Bits,
|
||||
|
||||
// We also want to be able to mask out the preserved bits for asserts.
|
||||
Mask = static_cast<uintptr_t>(-1) << Bits
|
||||
};
|
||||
|
||||
friend class PointerLikeTypeTraits<PointerEmbeddedInt>;
|
||||
|
||||
explicit PointerEmbeddedInt(uintptr_t Value) : Value(Value) {}
|
||||
|
||||
public:
|
||||
PointerEmbeddedInt() : Value(0) {}
|
||||
|
||||
PointerEmbeddedInt(IntT I) : Value(static_cast<uintptr_t>(I) << Shift) {
|
||||
assert((I & Mask) == 0 && "Integer has bits outside those preserved!");
|
||||
}
|
||||
|
||||
PointerEmbeddedInt &operator=(IntT I) {
|
||||
assert((I & Mask) == 0 && "Integer has bits outside those preserved!");
|
||||
Value = static_cast<uintptr_t>(I) << Shift;
|
||||
}
|
||||
|
||||
// Note that this imilict conversion additionally allows all of the basic
|
||||
// comparison operators to work transparently, etc.
|
||||
operator IntT() const { return static_cast<IntT>(Value >> Shift); }
|
||||
};
|
||||
|
||||
// Provide pointer like traits to support use with pointer unions and sum
|
||||
// types.
|
||||
template <typename IntT, int Bits>
|
||||
class PointerLikeTypeTraits<PointerEmbeddedInt<IntT, Bits>> {
|
||||
typedef PointerEmbeddedInt<IntT, Bits> T;
|
||||
|
||||
public:
|
||||
static inline void *getAsVoidPointer(const T &P) {
|
||||
return reinterpret_cast<void *>(P.Value);
|
||||
}
|
||||
static inline T getFromVoidPointer(void *P) {
|
||||
return T(reinterpret_cast<uintptr_t>(P));
|
||||
}
|
||||
static inline T getFromVoidPointer(const void *P) {
|
||||
return T(reinterpret_cast<uintptr_t>(P));
|
||||
}
|
||||
|
||||
enum { NumLowBitsAvailable = T::Shift };
|
||||
};
|
||||
|
||||
// Teach DenseMap how to use PointerEmbeddedInt objects as keys if the Int type
|
||||
// itself can be a key.
|
||||
template <typename IntT, int Bits>
|
||||
struct DenseMapInfo<PointerEmbeddedInt<IntT, Bits>> {
|
||||
typedef PointerEmbeddedInt<IntT, Bits> T;
|
||||
|
||||
typedef DenseMapInfo<IntT> IntInfo;
|
||||
|
||||
static inline T getEmptyKey() { return IntInfo::getEmptyKey(); }
|
||||
static inline T getTombstoneKey() { return IntInfo::getTombstoneKey(); }
|
||||
static unsigned getHashValue(const T &Arg) {
|
||||
return IntInfo::getHashValue(Arg);
|
||||
}
|
||||
static bool isEqual(const T &LHS, const T &RHS) { return LHS == RHS; }
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
@ -55,20 +55,25 @@ class PointerIntPair {
|
||||
|
||||
PointerTy getPointer() const { return Info::getPointer(Value); }
|
||||
|
||||
IntType getInt() const { return (IntType)Info::getInt(Value); }
|
||||
IntType getInt() const {
|
||||
return (IntType)Info::getInt(Value);
|
||||
}
|
||||
|
||||
void setPointer(PointerTy PtrVal) {
|
||||
Value = Info::updatePointer(Value, PtrVal);
|
||||
}
|
||||
|
||||
void setInt(IntType IntVal) { Value = Info::updateInt(Value, IntVal); }
|
||||
void setInt(IntType IntVal) {
|
||||
Value = Info::updateInt(Value, static_cast<intptr_t>(IntVal));
|
||||
}
|
||||
|
||||
void initWithPointer(PointerTy PtrVal) {
|
||||
Value = Info::updatePointer(0, PtrVal);
|
||||
}
|
||||
|
||||
void setPointerAndInt(PointerTy PtrVal, IntType IntVal) {
|
||||
Value = Info::updateInt(Info::updatePointer(0, PtrVal), IntVal);
|
||||
Value = Info::updateInt(Info::updatePointer(0, PtrVal),
|
||||
static_cast<intptr_t>(IntVal));
|
||||
}
|
||||
|
||||
PointerTy const *getAddrOfPointer() const {
|
||||
|
205
contrib/llvm/include/llvm/ADT/PointerSumType.h
Normal file
205
contrib/llvm/include/llvm/ADT/PointerSumType.h
Normal file
@ -0,0 +1,205 @@
|
||||
//===- llvm/ADT/PointerSumType.h --------------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_ADT_POINTERSUMTYPE_H
|
||||
#define LLVM_ADT_POINTERSUMTYPE_H
|
||||
|
||||
#include "llvm/ADT/DenseMapInfo.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include "llvm/Support/PointerLikeTypeTraits.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
/// A compile time pair of an integer tag and the pointer-like type which it
|
||||
/// indexes within a sum type. Also allows the user to specify a particular
|
||||
/// traits class for pointer types with custom behavior such as over-aligned
|
||||
/// allocation.
|
||||
template <uintptr_t N, typename PointerArgT,
|
||||
typename TraitsArgT = PointerLikeTypeTraits<PointerArgT>>
|
||||
struct PointerSumTypeMember {
|
||||
enum { Tag = N };
|
||||
typedef PointerArgT PointerT;
|
||||
typedef TraitsArgT TraitsT;
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <typename TagT, typename... MemberTs>
|
||||
struct PointerSumTypeHelper;
|
||||
|
||||
}
|
||||
|
||||
/// A sum type over pointer-like types.
|
||||
///
|
||||
/// This is a normal tagged union across pointer-like types that uses the low
|
||||
/// bits of the pointers to store the tag.
|
||||
///
|
||||
/// Each member of the sum type is specified by passing a \c
|
||||
/// PointerSumTypeMember specialization in the variadic member argument list.
|
||||
/// This allows the user to control the particular tag value associated with
|
||||
/// a particular type, use the same type for multiple different tags, and
|
||||
/// customize the pointer-like traits used for a particular member. Note that
|
||||
/// these *must* be specializations of \c PointerSumTypeMember, no other type
|
||||
/// will suffice, even if it provides a compatible interface.
|
||||
///
|
||||
/// This type implements all of the comparison operators and even hash table
|
||||
/// support by comparing the underlying storage of the pointer values. It
|
||||
/// doesn't support delegating to particular members for comparisons.
|
||||
///
|
||||
/// It also default constructs to a zero tag with a null pointer, whatever that
|
||||
/// would be. This means that the zero value for the tag type is significant
|
||||
/// and may be desireable to set to a state that is particularly desirable to
|
||||
/// default construct.
|
||||
///
|
||||
/// There is no support for constructing or accessing with a dynamic tag as
|
||||
/// that would fundamentally violate the type safety provided by the sum type.
|
||||
template <typename TagT, typename... MemberTs> class PointerSumType {
|
||||
uintptr_t Value;
|
||||
|
||||
typedef detail::PointerSumTypeHelper<TagT, MemberTs...> HelperT;
|
||||
|
||||
public:
|
||||
PointerSumType() : Value(0) {}
|
||||
|
||||
/// A typed constructor for a specific tagged member of the sum type.
|
||||
template <TagT N>
|
||||
static PointerSumType
|
||||
create(typename HelperT::template Lookup<N>::PointerT Pointer) {
|
||||
PointerSumType Result;
|
||||
void *V = HelperT::template Lookup<N>::TraitsT::getAsVoidPointer(Pointer);
|
||||
assert((reinterpret_cast<uintptr_t>(V) & HelperT::TagMask) == 0 &&
|
||||
"Pointer is insufficiently aligned to store the discriminant!");
|
||||
Result.Value = reinterpret_cast<uintptr_t>(V) | N;
|
||||
return Result;
|
||||
}
|
||||
|
||||
TagT getTag() const { return static_cast<TagT>(Value & HelperT::TagMask); }
|
||||
|
||||
template <TagT N> bool is() const { return N == getTag(); }
|
||||
|
||||
template <TagT N> typename HelperT::template Lookup<N>::PointerT get() const {
|
||||
void *P = is<N>() ? getImpl() : nullptr;
|
||||
return HelperT::template Lookup<N>::TraitsT::getFromVoidPointer(P);
|
||||
}
|
||||
|
||||
template <TagT N>
|
||||
typename HelperT::template Lookup<N>::PointerT cast() const {
|
||||
assert(is<N>() && "This instance has a different active member.");
|
||||
return HelperT::template Lookup<N>::TraitsT::getFromVoidPointer(getImpl());
|
||||
}
|
||||
|
||||
operator bool() const { return Value & HelperT::PointerMask; }
|
||||
bool operator==(const PointerSumType &R) const { return Value == R.Value; }
|
||||
bool operator!=(const PointerSumType &R) const { return Value != R.Value; }
|
||||
bool operator<(const PointerSumType &R) const { return Value < R.Value; }
|
||||
bool operator>(const PointerSumType &R) const { return Value > R.Value; }
|
||||
bool operator<=(const PointerSumType &R) const { return Value <= R.Value; }
|
||||
bool operator>=(const PointerSumType &R) const { return Value >= R.Value; }
|
||||
|
||||
uintptr_t getOpaqueValue() const { return Value; }
|
||||
|
||||
protected:
|
||||
void *getImpl() const {
|
||||
return reinterpret_cast<void *>(Value & HelperT::PointerMask);
|
||||
}
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
|
||||
/// A helper template for implementing \c PointerSumType. It provides fast
|
||||
/// compile-time lookup of the member from a particular tag value, along with
|
||||
/// useful constants and compile time checking infrastructure..
|
||||
template <typename TagT, typename... MemberTs>
|
||||
struct PointerSumTypeHelper : MemberTs... {
|
||||
// First we use a trick to allow quickly looking up information about
|
||||
// a particular member of the sum type. This works because we arranged to
|
||||
// have this type derive from all of the member type templates. We can select
|
||||
// the matching member for a tag using type deduction during overload
|
||||
// resolution.
|
||||
template <TagT N, typename PointerT, typename TraitsT>
|
||||
static PointerSumTypeMember<N, PointerT, TraitsT>
|
||||
LookupOverload(PointerSumTypeMember<N, PointerT, TraitsT> *);
|
||||
template <TagT N> static void LookupOverload(...);
|
||||
template <TagT N> struct Lookup {
|
||||
// Compute a particular member type by resolving the lookup helper ovorload.
|
||||
typedef decltype(LookupOverload<N>(
|
||||
static_cast<PointerSumTypeHelper *>(nullptr))) MemberT;
|
||||
|
||||
/// The Nth member's pointer type.
|
||||
typedef typename MemberT::PointerT PointerT;
|
||||
|
||||
/// The Nth member's traits type.
|
||||
typedef typename MemberT::TraitsT TraitsT;
|
||||
};
|
||||
|
||||
// Next we need to compute the number of bits available for the discriminant
|
||||
// by taking the min of the bits available for each member. Much of this
|
||||
// would be amazingly easier with good constexpr support.
|
||||
template <uintptr_t V, uintptr_t... Vs>
|
||||
struct Min : std::integral_constant<
|
||||
uintptr_t, (V < Min<Vs...>::value ? V : Min<Vs...>::value)> {
|
||||
};
|
||||
template <uintptr_t V>
|
||||
struct Min<V> : std::integral_constant<uintptr_t, V> {};
|
||||
enum { NumTagBits = Min<MemberTs::TraitsT::NumLowBitsAvailable...>::value };
|
||||
|
||||
// Also compute the smallest discriminant and various masks for convenience.
|
||||
enum : uint64_t {
|
||||
MinTag = Min<MemberTs::Tag...>::value,
|
||||
PointerMask = static_cast<uint64_t>(-1) << NumTagBits,
|
||||
TagMask = ~PointerMask
|
||||
};
|
||||
|
||||
// Finally we need a recursive template to do static checks of each
|
||||
// member.
|
||||
template <typename MemberT, typename... InnerMemberTs>
|
||||
struct Checker : Checker<InnerMemberTs...> {
|
||||
static_assert(MemberT::Tag < (1 << NumTagBits),
|
||||
"This discriminant value requires too many bits!");
|
||||
};
|
||||
template <typename MemberT> struct Checker<MemberT> : std::true_type {
|
||||
static_assert(MemberT::Tag < (1 << NumTagBits),
|
||||
"This discriminant value requires too many bits!");
|
||||
};
|
||||
static_assert(Checker<MemberTs...>::value,
|
||||
"Each member must pass the checker.");
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
// Teach DenseMap how to use PointerSumTypes as keys.
|
||||
template <typename TagT, typename... MemberTs>
|
||||
struct DenseMapInfo<PointerSumType<TagT, MemberTs...>> {
|
||||
typedef PointerSumType<TagT, MemberTs...> SumType;
|
||||
|
||||
typedef detail::PointerSumTypeHelper<TagT, MemberTs...> HelperT;
|
||||
enum { SomeTag = HelperT::MinTag };
|
||||
typedef typename HelperT::template Lookup<HelperT::MinTag>::PointerT
|
||||
SomePointerT;
|
||||
typedef DenseMapInfo<SomePointerT> SomePointerInfo;
|
||||
|
||||
static inline SumType getEmptyKey() {
|
||||
return SumType::create<SomeTag>(SomePointerInfo::getEmptyKey());
|
||||
}
|
||||
static inline SumType getTombstoneKey() {
|
||||
return SumType::create<SomeTag>(
|
||||
SomePointerInfo::getTombstoneKey());
|
||||
}
|
||||
static unsigned getHashValue(const SumType &Arg) {
|
||||
uintptr_t OpaqueValue = Arg.getOpaqueValue();
|
||||
return DenseMapInfo<uintptr_t>::getHashValue(OpaqueValue);
|
||||
}
|
||||
static bool isEqual(const SumType &LHS, const SumType &RHS) {
|
||||
return LHS == RHS;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@ -101,15 +101,13 @@ namespace llvm {
|
||||
/// A pointer to a SmallString instance.
|
||||
SmallStringKind,
|
||||
|
||||
/// A char value reinterpreted as a pointer, to render as a character.
|
||||
/// A char value, to render as a character.
|
||||
CharKind,
|
||||
|
||||
/// An unsigned int value reinterpreted as a pointer, to render as an
|
||||
/// unsigned decimal integer.
|
||||
/// An unsigned int value, to render as an unsigned decimal integer.
|
||||
DecUIKind,
|
||||
|
||||
/// An int value reinterpreted as a pointer, to render as a signed
|
||||
/// decimal integer.
|
||||
/// An int value, to render as a signed decimal integer.
|
||||
DecIKind,
|
||||
|
||||
/// A pointer to an unsigned long value, to render as an unsigned decimal
|
||||
|
@ -104,54 +104,10 @@ class LazyCallGraph {
|
||||
public:
|
||||
class Node;
|
||||
class SCC;
|
||||
class iterator;
|
||||
typedef SmallVector<PointerUnion<Function *, Node *>, 4> NodeVectorT;
|
||||
typedef SmallVectorImpl<PointerUnion<Function *, Node *>> NodeVectorImplT;
|
||||
|
||||
/// A lazy iterator used for both the entry nodes and child nodes.
|
||||
///
|
||||
/// When this iterator is dereferenced, if not yet available, a function will
|
||||
/// be scanned for "calls" or uses of functions and its child information
|
||||
/// will be constructed. All of these results are accumulated and cached in
|
||||
/// the graph.
|
||||
class iterator
|
||||
: public iterator_adaptor_base<iterator, NodeVectorImplT::iterator,
|
||||
std::forward_iterator_tag, Node> {
|
||||
friend class LazyCallGraph;
|
||||
friend class LazyCallGraph::Node;
|
||||
|
||||
LazyCallGraph *G;
|
||||
NodeVectorImplT::iterator E;
|
||||
|
||||
// Build the iterator for a specific position in a node list.
|
||||
iterator(LazyCallGraph &G, NodeVectorImplT::iterator NI,
|
||||
NodeVectorImplT::iterator E)
|
||||
: iterator_adaptor_base(NI), G(&G), E(E) {
|
||||
while (I != E && I->isNull())
|
||||
++I;
|
||||
}
|
||||
|
||||
public:
|
||||
iterator() {}
|
||||
|
||||
using iterator_adaptor_base::operator++;
|
||||
iterator &operator++() {
|
||||
do {
|
||||
++I;
|
||||
} while (I != E && I->isNull());
|
||||
return *this;
|
||||
}
|
||||
|
||||
reference operator*() const {
|
||||
if (I->is<Node *>())
|
||||
return *I->get<Node *>();
|
||||
|
||||
Function *F = I->get<Function *>();
|
||||
Node &ChildN = G->get(*F);
|
||||
*I = &ChildN;
|
||||
return ChildN;
|
||||
}
|
||||
};
|
||||
|
||||
/// A node in the call graph.
|
||||
///
|
||||
/// This represents a single node. It's primary roles are to cache the list of
|
||||
@ -200,6 +156,51 @@ class LazyCallGraph {
|
||||
bool operator!=(const Node &N) const { return !operator==(N); }
|
||||
};
|
||||
|
||||
/// A lazy iterator used for both the entry nodes and child nodes.
|
||||
///
|
||||
/// When this iterator is dereferenced, if not yet available, a function will
|
||||
/// be scanned for "calls" or uses of functions and its child information
|
||||
/// will be constructed. All of these results are accumulated and cached in
|
||||
/// the graph.
|
||||
class iterator
|
||||
: public iterator_adaptor_base<iterator, NodeVectorImplT::iterator,
|
||||
std::forward_iterator_tag, Node> {
|
||||
friend class LazyCallGraph;
|
||||
friend class LazyCallGraph::Node;
|
||||
|
||||
LazyCallGraph *G;
|
||||
NodeVectorImplT::iterator E;
|
||||
|
||||
// Build the iterator for a specific position in a node list.
|
||||
iterator(LazyCallGraph &G, NodeVectorImplT::iterator NI,
|
||||
NodeVectorImplT::iterator E)
|
||||
: iterator_adaptor_base(NI), G(&G), E(E) {
|
||||
while (I != E && I->isNull())
|
||||
++I;
|
||||
}
|
||||
|
||||
public:
|
||||
iterator() {}
|
||||
|
||||
using iterator_adaptor_base::operator++;
|
||||
iterator &operator++() {
|
||||
do {
|
||||
++I;
|
||||
} while (I != E && I->isNull());
|
||||
return *this;
|
||||
}
|
||||
|
||||
reference operator*() const {
|
||||
if (I->is<Node *>())
|
||||
return *I->get<Node *>();
|
||||
|
||||
Function *F = I->get<Function *>();
|
||||
Node &ChildN = G->get(*F);
|
||||
*I = &ChildN;
|
||||
return ChildN;
|
||||
}
|
||||
};
|
||||
|
||||
/// An SCC of the call graph.
|
||||
///
|
||||
/// This represents a Strongly Connected Component of the call graph as
|
||||
|
@ -59,38 +59,37 @@ template<class N, class M> class LoopInfoBase;
|
||||
template<class N, class M> class LoopBase;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// LoopBase class - Instances of this class are used to represent loops that
|
||||
/// are detected in the flow graph
|
||||
/// Instances of this class are used to represent loops that are detected in the
|
||||
/// flow graph.
|
||||
///
|
||||
template<class BlockT, class LoopT>
|
||||
class LoopBase {
|
||||
LoopT *ParentLoop;
|
||||
// SubLoops - Loops contained entirely within this one.
|
||||
// Loops contained entirely within this one.
|
||||
std::vector<LoopT *> SubLoops;
|
||||
|
||||
// Blocks - The list of blocks in this loop. First entry is the header node.
|
||||
// The list of blocks in this loop. First entry is the header node.
|
||||
std::vector<BlockT*> Blocks;
|
||||
|
||||
SmallPtrSet<const BlockT*, 8> DenseBlockSet;
|
||||
|
||||
/// Indicator that this loops has been "unlooped", so there's no loop here
|
||||
/// anymore.
|
||||
bool IsUnloop = false;
|
||||
/// Indicator that this loop is no longer a valid loop.
|
||||
bool IsInvalid = false;
|
||||
|
||||
LoopBase(const LoopBase<BlockT, LoopT> &) = delete;
|
||||
const LoopBase<BlockT, LoopT>&
|
||||
operator=(const LoopBase<BlockT, LoopT> &) = delete;
|
||||
public:
|
||||
/// Loop ctor - This creates an empty loop.
|
||||
/// This creates an empty loop.
|
||||
LoopBase() : ParentLoop(nullptr) {}
|
||||
~LoopBase() {
|
||||
for (size_t i = 0, e = SubLoops.size(); i != e; ++i)
|
||||
delete SubLoops[i];
|
||||
}
|
||||
|
||||
/// getLoopDepth - Return the nesting level of this loop. An outer-most
|
||||
/// loop has depth 1, for consistency with loop depth values used for basic
|
||||
/// blocks, where depth 0 is used for blocks not inside any loops.
|
||||
/// Return the nesting level of this loop. An outer-most loop has depth 1,
|
||||
/// for consistency with loop depth values used for basic blocks, where depth
|
||||
/// 0 is used for blocks not inside any loops.
|
||||
unsigned getLoopDepth() const {
|
||||
unsigned D = 1;
|
||||
for (const LoopT *CurLoop = ParentLoop; CurLoop;
|
||||
@ -101,33 +100,28 @@ class LoopBase {
|
||||
BlockT *getHeader() const { return Blocks.front(); }
|
||||
LoopT *getParentLoop() const { return ParentLoop; }
|
||||
|
||||
/// setParentLoop is a raw interface for bypassing addChildLoop.
|
||||
/// This is a raw interface for bypassing addChildLoop.
|
||||
void setParentLoop(LoopT *L) { ParentLoop = L; }
|
||||
|
||||
/// contains - Return true if the specified loop is contained within in
|
||||
/// this loop.
|
||||
///
|
||||
/// Return true if the specified loop is contained within in this loop.
|
||||
bool contains(const LoopT *L) const {
|
||||
if (L == this) return true;
|
||||
if (!L) return false;
|
||||
return contains(L->getParentLoop());
|
||||
}
|
||||
|
||||
/// contains - Return true if the specified basic block is in this loop.
|
||||
///
|
||||
/// Return true if the specified basic block is in this loop.
|
||||
bool contains(const BlockT *BB) const {
|
||||
return DenseBlockSet.count(BB);
|
||||
}
|
||||
|
||||
/// contains - Return true if the specified instruction is in this loop.
|
||||
///
|
||||
/// Return true if the specified instruction is in this loop.
|
||||
template<class InstT>
|
||||
bool contains(const InstT *Inst) const {
|
||||
return contains(Inst->getParent());
|
||||
}
|
||||
|
||||
/// iterator/begin/end - Return the loops contained entirely within this loop.
|
||||
///
|
||||
/// Return the loops contained entirely within this loop.
|
||||
const std::vector<LoopT *> &getSubLoops() const { return SubLoops; }
|
||||
std::vector<LoopT *> &getSubLoopsVector() { return SubLoops; }
|
||||
typedef typename std::vector<LoopT *>::const_iterator iterator;
|
||||
@ -139,8 +133,7 @@ class LoopBase {
|
||||
reverse_iterator rend() const { return SubLoops.rend(); }
|
||||
bool empty() const { return SubLoops.empty(); }
|
||||
|
||||
/// getBlocks - Get a list of the basic blocks which make up this loop.
|
||||
///
|
||||
/// Get a list of the basic blocks which make up this loop.
|
||||
const std::vector<BlockT*> &getBlocks() const { return Blocks; }
|
||||
typedef typename std::vector<BlockT*>::const_iterator block_iterator;
|
||||
block_iterator block_begin() const { return Blocks.begin(); }
|
||||
@ -149,21 +142,19 @@ class LoopBase {
|
||||
return make_range(block_begin(), block_end());
|
||||
}
|
||||
|
||||
/// getNumBlocks - Get the number of blocks in this loop in constant time.
|
||||
/// Get the number of blocks in this loop in constant time.
|
||||
unsigned getNumBlocks() const {
|
||||
return Blocks.size();
|
||||
}
|
||||
|
||||
/// Mark this loop as having been unlooped - the last backedge was removed and
|
||||
/// we no longer have a loop.
|
||||
void markUnlooped() { IsUnloop = true; }
|
||||
/// Invalidate the loop, indicating that it is no longer a loop.
|
||||
void invalidate() { IsInvalid = true; }
|
||||
|
||||
/// Return true if this no longer represents a loop.
|
||||
bool isUnloop() const { return IsUnloop; }
|
||||
/// Return true if this loop is no longer valid.
|
||||
bool isInvalid() { return IsInvalid; }
|
||||
|
||||
/// isLoopExiting - True if terminator in the block can branch to another
|
||||
/// block that is outside of the current loop.
|
||||
///
|
||||
/// True if terminator in the block can branch to another block that is
|
||||
/// outside of the current loop.
|
||||
bool isLoopExiting(const BlockT *BB) const {
|
||||
typedef GraphTraits<const BlockT*> BlockTraits;
|
||||
for (typename BlockTraits::ChildIteratorType SI =
|
||||
@ -175,8 +166,7 @@ class LoopBase {
|
||||
return false;
|
||||
}
|
||||
|
||||
/// getNumBackEdges - Calculate the number of back edges to the loop header
|
||||
///
|
||||
/// Calculate the number of back edges to the loop header.
|
||||
unsigned getNumBackEdges() const {
|
||||
unsigned NumBackEdges = 0;
|
||||
BlockT *H = getHeader();
|
||||
@ -199,53 +189,49 @@ class LoopBase {
|
||||
// induction variable canonicalization pass should be used to normalize loops
|
||||
// for easy analysis. These methods assume canonical loops.
|
||||
|
||||
/// getExitingBlocks - Return all blocks inside the loop that have successors
|
||||
/// outside of the loop. These are the blocks _inside of the current loop_
|
||||
/// which branch out. The returned list is always unique.
|
||||
///
|
||||
/// Return all blocks inside the loop that have successors outside of the
|
||||
/// loop. These are the blocks _inside of the current loop_ which branch out.
|
||||
/// The returned list is always unique.
|
||||
void getExitingBlocks(SmallVectorImpl<BlockT *> &ExitingBlocks) const;
|
||||
|
||||
/// getExitingBlock - If getExitingBlocks would return exactly one block,
|
||||
/// return that block. Otherwise return null.
|
||||
/// If getExitingBlocks would return exactly one block, return that block.
|
||||
/// Otherwise return null.
|
||||
BlockT *getExitingBlock() const;
|
||||
|
||||
/// getExitBlocks - Return all of the successor blocks of this loop. These
|
||||
/// are the blocks _outside of the current loop_ which are branched to.
|
||||
///
|
||||
/// Return all of the successor blocks of this loop. These are the blocks
|
||||
/// _outside of the current loop_ which are branched to.
|
||||
void getExitBlocks(SmallVectorImpl<BlockT*> &ExitBlocks) const;
|
||||
|
||||
/// getExitBlock - If getExitBlocks would return exactly one block,
|
||||
/// return that block. Otherwise return null.
|
||||
/// If getExitBlocks would return exactly one block, return that block.
|
||||
/// Otherwise return null.
|
||||
BlockT *getExitBlock() const;
|
||||
|
||||
/// Edge type.
|
||||
typedef std::pair<const BlockT*, const BlockT*> Edge;
|
||||
|
||||
/// getExitEdges - Return all pairs of (_inside_block_,_outside_block_).
|
||||
/// Return all pairs of (_inside_block_,_outside_block_).
|
||||
void getExitEdges(SmallVectorImpl<Edge> &ExitEdges) const;
|
||||
|
||||
/// getLoopPreheader - If there is a preheader for this loop, return it. A
|
||||
/// loop has a preheader if there is only one edge to the header of the loop
|
||||
/// from outside of the loop. If this is the case, the block branching to the
|
||||
/// header of the loop is the preheader node.
|
||||
/// If there is a preheader for this loop, return it. A loop has a preheader
|
||||
/// if there is only one edge to the header of the loop from outside of the
|
||||
/// loop. If this is the case, the block branching to the header of the loop
|
||||
/// is the preheader node.
|
||||
///
|
||||
/// This method returns null if there is no preheader for the loop.
|
||||
///
|
||||
BlockT *getLoopPreheader() const;
|
||||
|
||||
/// getLoopPredecessor - If the given loop's header has exactly one unique
|
||||
/// predecessor outside the loop, return it. Otherwise return null.
|
||||
/// This is less strict that the loop "preheader" concept, which requires
|
||||
/// If the given loop's header has exactly one unique predecessor outside the
|
||||
/// loop, return it. Otherwise return null.
|
||||
/// This is less strict that the loop "preheader" concept, which requires
|
||||
/// the predecessor to have exactly one successor.
|
||||
///
|
||||
BlockT *getLoopPredecessor() const;
|
||||
|
||||
/// getLoopLatch - If there is a single latch block for this loop, return it.
|
||||
/// If there is a single latch block for this loop, return it.
|
||||
/// A latch block is a block that contains a branch back to the header.
|
||||
BlockT *getLoopLatch() const;
|
||||
|
||||
/// getLoopLatches - Return all loop latch blocks of this loop. A latch block
|
||||
/// is a block that contains a branch back to the header.
|
||||
/// Return all loop latch blocks of this loop. A latch block is a block that
|
||||
/// contains a branch back to the header.
|
||||
void getLoopLatches(SmallVectorImpl<BlockT *> &LoopLatches) const {
|
||||
BlockT *H = getHeader();
|
||||
typedef GraphTraits<Inverse<BlockT*> > InvBlockTraits;
|
||||
@ -260,32 +246,29 @@ class LoopBase {
|
||||
// APIs for updating loop information after changing the CFG
|
||||
//
|
||||
|
||||
/// addBasicBlockToLoop - This method is used by other analyses to update loop
|
||||
/// information. NewBB is set to be a new member of the current loop.
|
||||
/// This method is used by other analyses to update loop information.
|
||||
/// NewBB is set to be a new member of the current loop.
|
||||
/// Because of this, it is added as a member of all parent loops, and is added
|
||||
/// to the specified LoopInfo object as being in the current basic block. It
|
||||
/// is not valid to replace the loop header with this method.
|
||||
///
|
||||
void addBasicBlockToLoop(BlockT *NewBB, LoopInfoBase<BlockT, LoopT> &LI);
|
||||
|
||||
/// replaceChildLoopWith - This is used when splitting loops up. It replaces
|
||||
/// the OldChild entry in our children list with NewChild, and updates the
|
||||
/// parent pointer of OldChild to be null and the NewChild to be this loop.
|
||||
/// This is used when splitting loops up. It replaces the OldChild entry in
|
||||
/// our children list with NewChild, and updates the parent pointer of
|
||||
/// OldChild to be null and the NewChild to be this loop.
|
||||
/// This updates the loop depth of the new child.
|
||||
void replaceChildLoopWith(LoopT *OldChild, LoopT *NewChild);
|
||||
|
||||
/// addChildLoop - Add the specified loop to be a child of this loop. This
|
||||
/// updates the loop depth of the new child.
|
||||
///
|
||||
/// Add the specified loop to be a child of this loop.
|
||||
/// This updates the loop depth of the new child.
|
||||
void addChildLoop(LoopT *NewChild) {
|
||||
assert(!NewChild->ParentLoop && "NewChild already has a parent!");
|
||||
NewChild->ParentLoop = static_cast<LoopT *>(this);
|
||||
SubLoops.push_back(NewChild);
|
||||
}
|
||||
|
||||
/// removeChildLoop - This removes the specified child from being a subloop of
|
||||
/// this loop. The loop is not deleted, as it will presumably be inserted
|
||||
/// into another loop.
|
||||
/// This removes the specified child from being a subloop of this loop. The
|
||||
/// loop is not deleted, as it will presumably be inserted into another loop.
|
||||
LoopT *removeChildLoop(iterator I) {
|
||||
assert(I != SubLoops.end() && "Cannot remove end iterator!");
|
||||
LoopT *Child = *I;
|
||||
@ -295,7 +278,7 @@ class LoopBase {
|
||||
return Child;
|
||||
}
|
||||
|
||||
/// addBlockEntry - This adds a basic block directly to the basic block list.
|
||||
/// This adds a basic block directly to the basic block list.
|
||||
/// This should only be used by transformations that create new loops. Other
|
||||
/// transformations should use addBasicBlockToLoop.
|
||||
void addBlockEntry(BlockT *BB) {
|
||||
@ -303,19 +286,18 @@ class LoopBase {
|
||||
DenseBlockSet.insert(BB);
|
||||
}
|
||||
|
||||
/// reverseBlocks - interface to reverse Blocks[from, end of loop] in this loop
|
||||
/// interface to reverse Blocks[from, end of loop] in this loop
|
||||
void reverseBlock(unsigned from) {
|
||||
std::reverse(Blocks.begin() + from, Blocks.end());
|
||||
}
|
||||
|
||||
/// reserveBlocks- interface to do reserve() for Blocks
|
||||
/// interface to do reserve() for Blocks
|
||||
void reserveBlocks(unsigned size) {
|
||||
Blocks.reserve(size);
|
||||
}
|
||||
|
||||
/// moveToHeader - This method is used to move BB (which must be part of this
|
||||
/// loop) to be the loop header of the loop (the block that dominates all
|
||||
/// others).
|
||||
/// This method is used to move BB (which must be part of this loop) to be the
|
||||
/// loop header of the loop (the block that dominates all others).
|
||||
void moveToHeader(BlockT *BB) {
|
||||
if (Blocks[0] == BB) return;
|
||||
for (unsigned i = 0; ; ++i) {
|
||||
@ -328,9 +310,9 @@ class LoopBase {
|
||||
}
|
||||
}
|
||||
|
||||
/// removeBlockFromLoop - This removes the specified basic block from the
|
||||
/// current loop, updating the Blocks as appropriate. This does not update
|
||||
/// the mapping in the LoopInfo class.
|
||||
/// This removes the specified basic block from the current loop, updating the
|
||||
/// Blocks as appropriate. This does not update the mapping in the LoopInfo
|
||||
/// class.
|
||||
void removeBlockFromLoop(BlockT *BB) {
|
||||
auto I = std::find(Blocks.begin(), Blocks.end(), BB);
|
||||
assert(I != Blocks.end() && "N is not in this list!");
|
||||
@ -339,10 +321,10 @@ class LoopBase {
|
||||
DenseBlockSet.erase(BB);
|
||||
}
|
||||
|
||||
/// verifyLoop - Verify loop structure
|
||||
/// Verify loop structure
|
||||
void verifyLoop() const;
|
||||
|
||||
/// verifyLoop - Verify loop structure of this loop and all nested loops.
|
||||
/// Verify loop structure of this loop and all nested loops.
|
||||
void verifyLoopNest(DenseSet<const LoopT*> *Loops) const;
|
||||
|
||||
void print(raw_ostream &OS, unsigned Depth = 0) const;
|
||||
@ -368,28 +350,26 @@ class Loop : public LoopBase<BasicBlock, Loop> {
|
||||
public:
|
||||
Loop() {}
|
||||
|
||||
/// isLoopInvariant - Return true if the specified value is loop invariant
|
||||
///
|
||||
/// Return true if the specified value is loop invariant.
|
||||
bool isLoopInvariant(const Value *V) const;
|
||||
|
||||
/// hasLoopInvariantOperands - Return true if all the operands of the
|
||||
/// specified instruction are loop invariant.
|
||||
/// Return true if all the operands of the specified instruction are loop
|
||||
/// invariant.
|
||||
bool hasLoopInvariantOperands(const Instruction *I) const;
|
||||
|
||||
/// makeLoopInvariant - If the given value is an instruction inside of the
|
||||
/// loop and it can be hoisted, do so to make it trivially loop-invariant.
|
||||
/// If the given value is an instruction inside of the loop and it can be
|
||||
/// hoisted, do so to make it trivially loop-invariant.
|
||||
/// Return true if the value after any hoisting is loop invariant. This
|
||||
/// function can be used as a slightly more aggressive replacement for
|
||||
/// isLoopInvariant.
|
||||
///
|
||||
/// If InsertPt is specified, it is the point to hoist instructions to.
|
||||
/// If null, the terminator of the loop preheader is used.
|
||||
///
|
||||
bool makeLoopInvariant(Value *V, bool &Changed,
|
||||
Instruction *InsertPt = nullptr) const;
|
||||
|
||||
/// makeLoopInvariant - If the given instruction is inside of the
|
||||
/// loop and it can be hoisted, do so to make it trivially loop-invariant.
|
||||
/// If the given instruction is inside of the loop and it can be hoisted, do
|
||||
/// so to make it trivially loop-invariant.
|
||||
/// Return true if the instruction after any hoisting is loop invariant. This
|
||||
/// function can be used as a slightly more aggressive replacement for
|
||||
/// isLoopInvariant.
|
||||
@ -400,28 +380,26 @@ class Loop : public LoopBase<BasicBlock, Loop> {
|
||||
bool makeLoopInvariant(Instruction *I, bool &Changed,
|
||||
Instruction *InsertPt = nullptr) const;
|
||||
|
||||
/// getCanonicalInductionVariable - Check to see if the loop has a canonical
|
||||
/// induction variable: an integer recurrence that starts at 0 and increments
|
||||
/// by one each time through the loop. If so, return the phi node that
|
||||
/// corresponds to it.
|
||||
/// Check to see if the loop has a canonical induction variable: an integer
|
||||
/// recurrence that starts at 0 and increments by one each time through the
|
||||
/// loop. If so, return the phi node that corresponds to it.
|
||||
///
|
||||
/// The IndVarSimplify pass transforms loops to have a canonical induction
|
||||
/// variable.
|
||||
///
|
||||
PHINode *getCanonicalInductionVariable() const;
|
||||
|
||||
/// isLCSSAForm - Return true if the Loop is in LCSSA form
|
||||
/// Return true if the Loop is in LCSSA form.
|
||||
bool isLCSSAForm(DominatorTree &DT) const;
|
||||
|
||||
/// \brief Return true if this Loop and all inner subloops are in LCSSA form.
|
||||
/// Return true if this Loop and all inner subloops are in LCSSA form.
|
||||
bool isRecursivelyLCSSAForm(DominatorTree &DT) const;
|
||||
|
||||
/// isLoopSimplifyForm - Return true if the Loop is in the form that
|
||||
/// the LoopSimplify form transforms loops to, which is sometimes called
|
||||
/// normal form.
|
||||
/// Return true if the Loop is in the form that the LoopSimplify form
|
||||
/// transforms loops to, which is sometimes called normal form.
|
||||
bool isLoopSimplifyForm() const;
|
||||
|
||||
/// isSafeToClone - Return true if the loop body is safe to clone in practice.
|
||||
/// Return true if the loop body is safe to clone in practice.
|
||||
bool isSafeToClone() const;
|
||||
|
||||
/// Returns true if the loop is annotated parallel.
|
||||
@ -454,23 +432,22 @@ class Loop : public LoopBase<BasicBlock, Loop> {
|
||||
/// operand should should be the node itself.
|
||||
void setLoopID(MDNode *LoopID) const;
|
||||
|
||||
/// hasDedicatedExits - Return true if no exit block for the loop
|
||||
/// has a predecessor that is outside the loop.
|
||||
/// Return true if no exit block for the loop has a predecessor that is
|
||||
/// outside the loop.
|
||||
bool hasDedicatedExits() const;
|
||||
|
||||
/// getUniqueExitBlocks - Return all unique successor blocks of this loop.
|
||||
/// Return all unique successor blocks of this loop.
|
||||
/// These are the blocks _outside of the current loop_ which are branched to.
|
||||
/// This assumes that loop exits are in canonical form.
|
||||
///
|
||||
void getUniqueExitBlocks(SmallVectorImpl<BasicBlock *> &ExitBlocks) const;
|
||||
|
||||
/// getUniqueExitBlock - If getUniqueExitBlocks would return exactly one
|
||||
/// block, return that block. Otherwise return null.
|
||||
/// If getUniqueExitBlocks would return exactly one block, return that block.
|
||||
/// Otherwise return null.
|
||||
BasicBlock *getUniqueExitBlock() const;
|
||||
|
||||
void dump() const;
|
||||
|
||||
/// \brief Return the debug location of the start of this loop.
|
||||
/// Return the debug location of the start of this loop.
|
||||
/// This looks for a BB terminating instruction with a known debug
|
||||
/// location by looking at the preheader and header blocks. If it
|
||||
/// cannot find a terminating instruction with location information,
|
||||
@ -498,7 +475,7 @@ class Loop : public LoopBase<BasicBlock, Loop> {
|
||||
};
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// LoopInfo - This class builds and contains all of the top level loop
|
||||
/// This class builds and contains all of the top-level loop
|
||||
/// structures in the specified function.
|
||||
///
|
||||
|
||||
@ -507,6 +484,8 @@ class LoopInfoBase {
|
||||
// BBMap - Mapping of basic blocks to the inner most loop they occur in
|
||||
DenseMap<const BlockT *, LoopT *> BBMap;
|
||||
std::vector<LoopT *> TopLevelLoops;
|
||||
std::vector<LoopT *> RemovedLoops;
|
||||
|
||||
friend class LoopBase<BlockT, LoopT>;
|
||||
friend class LoopInfo;
|
||||
|
||||
@ -538,6 +517,9 @@ class LoopInfoBase {
|
||||
for (auto *L : TopLevelLoops)
|
||||
delete L;
|
||||
TopLevelLoops.clear();
|
||||
for (auto *L : RemovedLoops)
|
||||
delete L;
|
||||
RemovedLoops.clear();
|
||||
}
|
||||
|
||||
/// iterator/begin/end - The interface to the top-level loops in the current
|
||||
@ -552,33 +534,30 @@ class LoopInfoBase {
|
||||
reverse_iterator rend() const { return TopLevelLoops.rend(); }
|
||||
bool empty() const { return TopLevelLoops.empty(); }
|
||||
|
||||
/// getLoopFor - Return the inner most loop that BB lives in. If a basic
|
||||
/// block is in no loop (for example the entry node), null is returned.
|
||||
///
|
||||
/// Return the inner most loop that BB lives in. If a basic block is in no
|
||||
/// loop (for example the entry node), null is returned.
|
||||
LoopT *getLoopFor(const BlockT *BB) const { return BBMap.lookup(BB); }
|
||||
|
||||
/// operator[] - same as getLoopFor...
|
||||
///
|
||||
/// Same as getLoopFor.
|
||||
const LoopT *operator[](const BlockT *BB) const {
|
||||
return getLoopFor(BB);
|
||||
}
|
||||
|
||||
/// getLoopDepth - Return the loop nesting level of the specified block. A
|
||||
/// depth of 0 means the block is not inside any loop.
|
||||
///
|
||||
/// Return the loop nesting level of the specified block. A depth of 0 means
|
||||
/// the block is not inside any loop.
|
||||
unsigned getLoopDepth(const BlockT *BB) const {
|
||||
const LoopT *L = getLoopFor(BB);
|
||||
return L ? L->getLoopDepth() : 0;
|
||||
}
|
||||
|
||||
// isLoopHeader - True if the block is a loop header node
|
||||
// True if the block is a loop header node
|
||||
bool isLoopHeader(const BlockT *BB) const {
|
||||
const LoopT *L = getLoopFor(BB);
|
||||
return L && L->getHeader() == BB;
|
||||
}
|
||||
|
||||
/// removeLoop - This removes the specified top-level loop from this loop info
|
||||
/// object. The loop is not deleted, as it will presumably be inserted into
|
||||
/// This removes the specified top-level loop from this loop info object.
|
||||
/// The loop is not deleted, as it will presumably be inserted into
|
||||
/// another loop.
|
||||
LoopT *removeLoop(iterator I) {
|
||||
assert(I != end() && "Cannot remove end iterator!");
|
||||
@ -588,9 +567,9 @@ class LoopInfoBase {
|
||||
return L;
|
||||
}
|
||||
|
||||
/// changeLoopFor - Change the top-level loop that contains BB to the
|
||||
/// specified loop. This should be used by transformations that restructure
|
||||
/// the loop hierarchy tree.
|
||||
/// Change the top-level loop that contains BB to the specified loop.
|
||||
/// This should be used by transformations that restructure the loop hierarchy
|
||||
/// tree.
|
||||
void changeLoopFor(BlockT *BB, LoopT *L) {
|
||||
if (!L) {
|
||||
BBMap.erase(BB);
|
||||
@ -599,8 +578,8 @@ class LoopInfoBase {
|
||||
BBMap[BB] = L;
|
||||
}
|
||||
|
||||
/// changeTopLevelLoop - Replace the specified loop in the top-level loops
|
||||
/// list with the indicated loop.
|
||||
/// Replace the specified loop in the top-level loops list with the indicated
|
||||
/// loop.
|
||||
void changeTopLevelLoop(LoopT *OldLoop,
|
||||
LoopT *NewLoop) {
|
||||
auto I = std::find(TopLevelLoops.begin(), TopLevelLoops.end(), OldLoop);
|
||||
@ -610,14 +589,13 @@ class LoopInfoBase {
|
||||
"Loops already embedded into a subloop!");
|
||||
}
|
||||
|
||||
/// addTopLevelLoop - This adds the specified loop to the collection of
|
||||
/// top-level loops.
|
||||
/// This adds the specified loop to the collection of top-level loops.
|
||||
void addTopLevelLoop(LoopT *New) {
|
||||
assert(!New->getParentLoop() && "Loop already in subloop!");
|
||||
TopLevelLoops.push_back(New);
|
||||
}
|
||||
|
||||
/// removeBlock - This method completely removes BB from all data structures,
|
||||
/// This method completely removes BB from all data structures,
|
||||
/// including all of the Loop objects it is nested in and our mapping from
|
||||
/// BasicBlocks to loops.
|
||||
void removeBlock(BlockT *BB) {
|
||||
@ -670,15 +648,14 @@ class LoopInfo : public LoopInfoBase<BasicBlock, Loop> {
|
||||
|
||||
// Most of the public interface is provided via LoopInfoBase.
|
||||
|
||||
/// updateUnloop - Update LoopInfo after removing the last backedge from a
|
||||
/// loop--now the "unloop". This updates the loop forest and parent loops for
|
||||
/// each block so that Unloop is no longer referenced, but does not actually
|
||||
/// delete the Unloop object. Generally, the loop pass manager should manage
|
||||
/// deleting the Unloop.
|
||||
void updateUnloop(Loop *Unloop);
|
||||
/// Update LoopInfo after removing the last backedge from a loop. This updates
|
||||
/// the loop forest and parent loops for each block so that \c L is no longer
|
||||
/// referenced, but does not actually delete \c L immediately. The pointer
|
||||
/// will remain valid until this LoopInfo's memory is released.
|
||||
void markAsRemoved(Loop *L);
|
||||
|
||||
/// replacementPreservesLCSSAForm - Returns true if replacing From with To
|
||||
/// everywhere is guaranteed to preserve LCSSA form.
|
||||
/// Returns true if replacing From with To everywhere is guaranteed to
|
||||
/// preserve LCSSA form.
|
||||
bool replacementPreservesLCSSAForm(Instruction *From, Value *To) {
|
||||
// Preserving LCSSA form is only problematic if the replacing value is an
|
||||
// instruction.
|
||||
@ -698,8 +675,7 @@ class LoopInfo : public LoopInfoBase<BasicBlock, Loop> {
|
||||
return ToLoop->contains(getLoopFor(From->getParent()));
|
||||
}
|
||||
|
||||
/// \brief Checks if moving a specific instruction can break LCSSA in any
|
||||
/// loop.
|
||||
/// Checks if moving a specific instruction can break LCSSA in any loop.
|
||||
///
|
||||
/// Return true if moving \p Inst to before \p NewLoc will break LCSSA,
|
||||
/// assuming that the function containing \p Inst and \p NewLoc is currently
|
||||
|
@ -259,7 +259,7 @@ class AsmPrinter : public MachineFunctionPass {
|
||||
void EmitAlignment(unsigned NumBits, const GlobalObject *GO = nullptr) const;
|
||||
|
||||
/// Lower the specified LLVM Constant to an MCExpr.
|
||||
const MCExpr *lowerConstant(const Constant *CV);
|
||||
virtual const MCExpr *lowerConstant(const Constant *CV);
|
||||
|
||||
/// \brief Print a general LLVM constant to the .s file.
|
||||
void EmitGlobalConstant(const DataLayout &DL, const Constant *CV);
|
||||
|
@ -29,6 +29,48 @@ class MCSymbol;
|
||||
class raw_ostream;
|
||||
class DwarfTypeUnit;
|
||||
|
||||
// AsmStreamerBase - A base abstract interface class defines methods that
|
||||
// can be implemented to stream objects or can be implemented to
|
||||
// calculate the size of the streamed objects.
|
||||
// The derived classes will use an AsmPrinter to implement the methods.
|
||||
//
|
||||
// TODO: complete this interface and use it to merge EmitValue and SizeOf
|
||||
// methods in the DIE classes below.
|
||||
class AsmStreamerBase {
|
||||
protected:
|
||||
const AsmPrinter *AP;
|
||||
AsmStreamerBase(const AsmPrinter *AP) : AP(AP) {}
|
||||
|
||||
public:
|
||||
virtual ~AsmStreamerBase() {}
|
||||
virtual unsigned emitULEB128(uint64_t Value, const char *Desc = nullptr,
|
||||
unsigned PadTo = 0) = 0;
|
||||
virtual unsigned emitInt8(unsigned char Value) = 0;
|
||||
virtual unsigned emitBytes(StringRef Data) = 0;
|
||||
};
|
||||
|
||||
/// EmittingAsmStreamer - Implements AbstractAsmStreamer to stream objects.
|
||||
/// Notice that the return value is not the actual size of the streamed object.
|
||||
/// For size calculation use SizeReporterAsmStreamer.
|
||||
class EmittingAsmStreamer : public AsmStreamerBase {
|
||||
public:
|
||||
EmittingAsmStreamer(const AsmPrinter *AP) : AsmStreamerBase(AP) {}
|
||||
unsigned emitULEB128(uint64_t Value, const char *Desc = nullptr,
|
||||
unsigned PadTo = 0) override;
|
||||
unsigned emitInt8(unsigned char Value) override;
|
||||
unsigned emitBytes(StringRef Data) override;
|
||||
};
|
||||
|
||||
/// SizeReporterAsmStreamer - Only reports the size of the streamed objects.
|
||||
class SizeReporterAsmStreamer : public AsmStreamerBase {
|
||||
public:
|
||||
SizeReporterAsmStreamer(const AsmPrinter *AP) : AsmStreamerBase(AP) {}
|
||||
unsigned emitULEB128(uint64_t Value, const char *Desc = nullptr,
|
||||
unsigned PadTo = 0) override;
|
||||
unsigned emitInt8(unsigned char Value) override;
|
||||
unsigned emitBytes(StringRef Data) override;
|
||||
};
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
/// DIEAbbrevData - Dwarf abbreviation data, describes one attribute of a
|
||||
/// Dwarf abbreviation.
|
||||
|
@ -848,9 +848,9 @@ namespace llvm {
|
||||
public:
|
||||
explicit ConnectedVNInfoEqClasses(LiveIntervals &lis) : LIS(lis) {}
|
||||
|
||||
/// Classify - Classify the values in LI into connected components.
|
||||
/// Return the number of connected components.
|
||||
unsigned Classify(const LiveInterval *LI);
|
||||
/// Classify the values in \p LR into connected components.
|
||||
/// Returns the number of connected components.
|
||||
unsigned Classify(const LiveRange &LR);
|
||||
|
||||
/// getEqClass - Classify creates equivalence classes numbered 0..N. Return
|
||||
/// the equivalence class assigned the VNI.
|
||||
|
@ -141,6 +141,28 @@ class PressureDiff {
|
||||
LLVM_DUMP_METHOD void dump(const TargetRegisterInfo &TRI) const;
|
||||
};
|
||||
|
||||
/// List of registers defined and used by a machine instruction.
|
||||
class RegisterOperands {
|
||||
public:
|
||||
/// List of virtual regiserts and register units read by the instruction.
|
||||
SmallVector<unsigned, 8> Uses;
|
||||
/// \brief List of virtual registers and register units defined by the
|
||||
/// instruction which are not dead.
|
||||
SmallVector<unsigned, 8> Defs;
|
||||
/// \brief List of virtual registers and register units defined by the
|
||||
/// instruction but dead.
|
||||
SmallVector<unsigned, 8> DeadDefs;
|
||||
|
||||
/// Analyze the given instruction \p MI and fill in the Uses, Defs and
|
||||
/// DeadDefs list based on the MachineOperand flags.
|
||||
void collect(const MachineInstr &MI, const TargetRegisterInfo &TRI,
|
||||
const MachineRegisterInfo &MRI, bool IgnoreDead = false);
|
||||
|
||||
/// Use liveness information to find dead defs not marked with a dead flag
|
||||
/// and move them to the DeadDefs vector.
|
||||
void detectDeadDefs(const MachineInstr &MI, const LiveIntervals &LIS);
|
||||
};
|
||||
|
||||
/// Array of PressureDiffs.
|
||||
class PressureDiffs {
|
||||
PressureDiff *PDiffArray;
|
||||
@ -161,6 +183,10 @@ class PressureDiffs {
|
||||
const PressureDiff &operator[](unsigned Idx) const {
|
||||
return const_cast<PressureDiffs*>(this)->operator[](Idx);
|
||||
}
|
||||
/// \brief Record pressure difference induced by the given operand list to
|
||||
/// node with index \p Idx.
|
||||
void addInstruction(unsigned Idx, const RegisterOperands &RegOpers,
|
||||
const MachineRegisterInfo &MRI);
|
||||
};
|
||||
|
||||
/// Store the effects of a change in pressure on things that MI scheduler cares
|
||||
@ -329,8 +355,17 @@ class RegPressureTracker {
|
||||
void setPos(MachineBasicBlock::const_iterator Pos) { CurrPos = Pos; }
|
||||
|
||||
/// Recede across the previous instruction.
|
||||
void recede(SmallVectorImpl<unsigned> *LiveUses = nullptr,
|
||||
PressureDiff *PDiff = nullptr);
|
||||
void recede(SmallVectorImpl<unsigned> *LiveUses = nullptr);
|
||||
|
||||
/// Recede across the previous instruction.
|
||||
/// This "low-level" variant assumes that recedeSkipDebugValues() was
|
||||
/// called previously and takes precomputed RegisterOperands for the
|
||||
/// instruction.
|
||||
void recede(const RegisterOperands &RegOpers,
|
||||
SmallVectorImpl<unsigned> *LiveUses = nullptr);
|
||||
|
||||
/// Recede until we find an instruction which is not a DebugValue.
|
||||
void recedeSkipDebugValues();
|
||||
|
||||
/// Advance across the current instruction.
|
||||
void advance();
|
||||
|
@ -93,8 +93,6 @@ struct WinEHFuncInfo {
|
||||
DenseMap<const Instruction *, int> EHPadStateMap;
|
||||
DenseMap<const FuncletPadInst *, int> FuncletBaseStateMap;
|
||||
DenseMap<const InvokeInst *, int> InvokeStateMap;
|
||||
DenseMap<const CatchReturnInst *, const BasicBlock *>
|
||||
CatchRetSuccessorColorMap;
|
||||
DenseMap<MCSymbol *, std::pair<int, MCSymbol *>> LabelToStateMap;
|
||||
SmallVector<CxxUnwindMapEntry, 4> CxxUnwindMap;
|
||||
SmallVector<WinEHTryBlockMapEntry, 4> TryBlockMap;
|
||||
@ -125,8 +123,5 @@ void calculateSEHStateNumbers(const Function *ParentFn,
|
||||
WinEHFuncInfo &FuncInfo);
|
||||
|
||||
void calculateClrEHStateNumbers(const Function *Fn, WinEHFuncInfo &FuncInfo);
|
||||
|
||||
void calculateCatchReturnSuccessorColors(const Function *Fn,
|
||||
WinEHFuncInfo &FuncInfo);
|
||||
}
|
||||
#endif // LLVM_CODEGEN_WINEHFUNCINFO_H
|
||||
|
@ -28,13 +28,16 @@ class DIPrinter {
|
||||
raw_ostream &OS;
|
||||
bool PrintFunctionNames;
|
||||
bool PrintPretty;
|
||||
void printName(const DILineInfo &Info, bool Inlined);
|
||||
int PrintSourceContext;
|
||||
|
||||
void print(const DILineInfo &Info, bool Inlined);
|
||||
void printContext(std::string FileName, int64_t Line);
|
||||
|
||||
public:
|
||||
DIPrinter(raw_ostream &OS, bool PrintFunctionNames = true,
|
||||
bool PrintPretty = false)
|
||||
bool PrintPretty = false, int PrintSourceContext = 0)
|
||||
: OS(OS), PrintFunctionNames(PrintFunctionNames),
|
||||
PrintPretty(PrintPretty) {}
|
||||
PrintPretty(PrintPretty), PrintSourceContext(PrintSourceContext) {}
|
||||
|
||||
DIPrinter &operator<<(const DILineInfo &Info);
|
||||
DIPrinter &operator<<(const DIInliningInfo &Info);
|
||||
|
@ -19,7 +19,6 @@
|
||||
#include "LambdaResolver.h"
|
||||
#include "LogicalDylib.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/ExecutionEngine/SectionMemoryManager.h"
|
||||
#include "llvm/Transforms/Utils/Cloning.h"
|
||||
#include <list>
|
||||
#include <memory>
|
||||
@ -61,31 +60,36 @@ class CompileOnDemandLayer {
|
||||
|
||||
typedef typename BaseLayerT::ModuleSetHandleT BaseLayerModuleSetHandleT;
|
||||
|
||||
class ModuleOwner {
|
||||
// Provide type-erasure for the Modules and MemoryManagers.
|
||||
template <typename ResourceT>
|
||||
class ResourceOwner {
|
||||
public:
|
||||
ModuleOwner() = default;
|
||||
ModuleOwner(const ModuleOwner&) = delete;
|
||||
ModuleOwner& operator=(const ModuleOwner&) = delete;
|
||||
virtual ~ModuleOwner() { }
|
||||
virtual Module& getModule() const = 0;
|
||||
ResourceOwner() = default;
|
||||
ResourceOwner(const ResourceOwner&) = delete;
|
||||
ResourceOwner& operator=(const ResourceOwner&) = delete;
|
||||
virtual ~ResourceOwner() { }
|
||||
virtual ResourceT& getResource() const = 0;
|
||||
};
|
||||
|
||||
template <typename ModulePtrT>
|
||||
class ModuleOwnerImpl : public ModuleOwner {
|
||||
template <typename ResourceT, typename ResourcePtrT>
|
||||
class ResourceOwnerImpl : public ResourceOwner<ResourceT> {
|
||||
public:
|
||||
ModuleOwnerImpl(ModulePtrT ModulePtr) : ModulePtr(std::move(ModulePtr)) {}
|
||||
Module& getModule() const override { return *ModulePtr; }
|
||||
ResourceOwnerImpl(ResourcePtrT ResourcePtr)
|
||||
: ResourcePtr(std::move(ResourcePtr)) {}
|
||||
ResourceT& getResource() const override { return *ResourcePtr; }
|
||||
private:
|
||||
ModulePtrT ModulePtr;
|
||||
ResourcePtrT ResourcePtr;
|
||||
};
|
||||
|
||||
template <typename ModulePtrT>
|
||||
std::unique_ptr<ModuleOwner> wrapOwnership(ModulePtrT ModulePtr) {
|
||||
return llvm::make_unique<ModuleOwnerImpl<ModulePtrT>>(std::move(ModulePtr));
|
||||
template <typename ResourceT, typename ResourcePtrT>
|
||||
std::unique_ptr<ResourceOwner<ResourceT>>
|
||||
wrapOwnership(ResourcePtrT ResourcePtr) {
|
||||
typedef ResourceOwnerImpl<ResourceT, ResourcePtrT> RO;
|
||||
return llvm::make_unique<RO>(std::move(ResourcePtr));
|
||||
}
|
||||
|
||||
struct LogicalModuleResources {
|
||||
std::unique_ptr<ModuleOwner> SourceModuleOwner;
|
||||
std::unique_ptr<ResourceOwner<Module>> SourceModule;
|
||||
std::set<const Function*> StubsToClone;
|
||||
std::unique_ptr<IndirectStubsMgrT> StubsMgr;
|
||||
|
||||
@ -93,15 +97,16 @@ class CompileOnDemandLayer {
|
||||
|
||||
// Explicit move constructor to make MSVC happy.
|
||||
LogicalModuleResources(LogicalModuleResources &&Other)
|
||||
: SourceModuleOwner(std::move(Other.SourceModuleOwner)),
|
||||
: SourceModule(std::move(Other.SourceModule)),
|
||||
StubsToClone(std::move(Other.StubsToClone)),
|
||||
StubsMgr(std::move(Other.StubsMgr)) {}
|
||||
|
||||
// Explicit move assignment to make MSVC happy.
|
||||
LogicalModuleResources& operator=(LogicalModuleResources &&Other) {
|
||||
SourceModuleOwner = std::move(Other.SourceModuleOwner);
|
||||
SourceModule = std::move(Other.SourceModule);
|
||||
StubsToClone = std::move(Other.StubsToClone);
|
||||
StubsMgr = std::move(Other.StubsMgr);
|
||||
return *this;
|
||||
}
|
||||
|
||||
JITSymbol findSymbol(StringRef Name, bool ExportedSymbolsOnly) {
|
||||
@ -114,12 +119,35 @@ class CompileOnDemandLayer {
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct LogicalDylibResources {
|
||||
typedef std::function<RuntimeDyld::SymbolInfo(const std::string&)>
|
||||
SymbolResolverFtor;
|
||||
|
||||
typedef std::function<typename BaseLayerT::ModuleSetHandleT(
|
||||
BaseLayerT&,
|
||||
std::unique_ptr<Module>,
|
||||
std::unique_ptr<RuntimeDyld::SymbolResolver>)>
|
||||
ModuleAdderFtor;
|
||||
|
||||
LogicalDylibResources() = default;
|
||||
|
||||
// Explicit move constructor to make MSVC happy.
|
||||
LogicalDylibResources(LogicalDylibResources &&Other)
|
||||
: ExternalSymbolResolver(std::move(Other.ExternalSymbolResolver)),
|
||||
MemMgr(std::move(Other.MemMgr)),
|
||||
ModuleAdder(std::move(Other.ModuleAdder)) {}
|
||||
|
||||
// Explicit move assignment operator to make MSVC happy.
|
||||
LogicalDylibResources& operator=(LogicalDylibResources &&Other) {
|
||||
ExternalSymbolResolver = std::move(Other.ExternalSymbolResolver);
|
||||
MemMgr = std::move(Other.MemMgr);
|
||||
ModuleAdder = std::move(Other.ModuleAdder);
|
||||
return *this;
|
||||
}
|
||||
|
||||
SymbolResolverFtor ExternalSymbolResolver;
|
||||
std::unique_ptr<ResourceOwner<RuntimeDyld::MemoryManager>> MemMgr;
|
||||
ModuleAdderFtor ModuleAdder;
|
||||
};
|
||||
|
||||
typedef LogicalDylib<BaseLayerT, LogicalModuleResources,
|
||||
@ -157,9 +185,6 @@ class CompileOnDemandLayer {
|
||||
MemoryManagerPtrT MemMgr,
|
||||
SymbolResolverPtrT Resolver) {
|
||||
|
||||
assert(MemMgr == nullptr &&
|
||||
"User supplied memory managers not supported with COD yet.");
|
||||
|
||||
LogicalDylibs.push_back(CODLogicalDylib(BaseLayer));
|
||||
auto &LDResources = LogicalDylibs.back().getDylibResources();
|
||||
|
||||
@ -168,6 +193,18 @@ class CompileOnDemandLayer {
|
||||
return Resolver->findSymbol(Name);
|
||||
};
|
||||
|
||||
auto &MemMgrRef = *MemMgr;
|
||||
LDResources.MemMgr =
|
||||
wrapOwnership<RuntimeDyld::MemoryManager>(std::move(MemMgr));
|
||||
|
||||
LDResources.ModuleAdder =
|
||||
[&MemMgrRef](BaseLayerT &B, std::unique_ptr<Module> M,
|
||||
std::unique_ptr<RuntimeDyld::SymbolResolver> R) {
|
||||
std::vector<std::unique_ptr<Module>> Ms;
|
||||
Ms.push_back(std::move(M));
|
||||
return B.addModuleSet(std::move(Ms), &MemMgrRef, std::move(R));
|
||||
};
|
||||
|
||||
// Process each of the modules in this module set.
|
||||
for (auto &M : Ms)
|
||||
addLogicalModule(LogicalDylibs.back(), std::move(M));
|
||||
@ -215,9 +252,9 @@ class CompileOnDemandLayer {
|
||||
auto LMH = LD.createLogicalModule();
|
||||
auto &LMResources = LD.getLogicalModuleResources(LMH);
|
||||
|
||||
LMResources.SourceModuleOwner = wrapOwnership(std::move(SrcMPtr));
|
||||
LMResources.SourceModule = wrapOwnership<Module>(std::move(SrcMPtr));
|
||||
|
||||
Module &SrcM = LMResources.SourceModuleOwner->getModule();
|
||||
Module &SrcM = LMResources.SourceModule->getResource();
|
||||
|
||||
// Create the GlobalValues module.
|
||||
const DataLayout &DL = SrcM.getDataLayout();
|
||||
@ -326,12 +363,9 @@ class CompileOnDemandLayer {
|
||||
return RuntimeDyld::SymbolInfo(nullptr);
|
||||
});
|
||||
|
||||
std::vector<std::unique_ptr<Module>> GVsMSet;
|
||||
GVsMSet.push_back(std::move(GVsM));
|
||||
auto GVsH =
|
||||
BaseLayer.addModuleSet(std::move(GVsMSet),
|
||||
llvm::make_unique<SectionMemoryManager>(),
|
||||
std::move(GVsResolver));
|
||||
LD.getDylibResources().ModuleAdder(BaseLayer, std::move(GVsM),
|
||||
std::move(GVsResolver));
|
||||
LD.addToLogicalModule(LMH, GVsH);
|
||||
}
|
||||
|
||||
@ -348,7 +382,7 @@ class CompileOnDemandLayer {
|
||||
LogicalModuleHandle LMH,
|
||||
Function &F) {
|
||||
auto &LMResources = LD.getLogicalModuleResources(LMH);
|
||||
Module &SrcM = LMResources.SourceModuleOwner->getModule();
|
||||
Module &SrcM = LMResources.SourceModule->getResource();
|
||||
|
||||
// If F is a declaration we must already have compiled it.
|
||||
if (F.isDeclaration())
|
||||
@ -386,7 +420,7 @@ class CompileOnDemandLayer {
|
||||
LogicalModuleHandle LMH,
|
||||
const PartitionT &Part) {
|
||||
auto &LMResources = LD.getLogicalModuleResources(LMH);
|
||||
Module &SrcM = LMResources.SourceModuleOwner->getModule();
|
||||
Module &SrcM = LMResources.SourceModule->getResource();
|
||||
|
||||
// Create the module.
|
||||
std::string NewName = SrcM.getName();
|
||||
@ -445,7 +479,6 @@ class CompileOnDemandLayer {
|
||||
moveFunctionBody(*F, VMap, &Materializer);
|
||||
|
||||
// Create memory manager and symbol resolver.
|
||||
auto MemMgr = llvm::make_unique<SectionMemoryManager>();
|
||||
auto Resolver = createLambdaResolver(
|
||||
[this, &LD, LMH](const std::string &Name) {
|
||||
if (auto Symbol = LD.findSymbolInternally(LMH, Name))
|
||||
@ -459,10 +492,9 @@ class CompileOnDemandLayer {
|
||||
Symbol.getFlags());
|
||||
return RuntimeDyld::SymbolInfo(nullptr);
|
||||
});
|
||||
std::vector<std::unique_ptr<Module>> PartMSet;
|
||||
PartMSet.push_back(std::move(M));
|
||||
return BaseLayer.addModuleSet(std::move(PartMSet), std::move(MemMgr),
|
||||
std::move(Resolver));
|
||||
|
||||
return LD.getDylibResources().ModuleAdder(BaseLayer, std::move(M),
|
||||
std::move(Resolver));
|
||||
}
|
||||
|
||||
BaseLayerT &BaseLayer;
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include "llvm/IR/Mangler.h"
|
||||
#include "llvm/IR/Module.h"
|
||||
#include "llvm/Transforms/Utils/ValueMapper.h"
|
||||
#include "llvm/Support/Process.h"
|
||||
#include <sstream>
|
||||
|
||||
namespace llvm {
|
||||
@ -179,14 +180,15 @@ class LocalJITCompileCallbackManager : public JITCompileCallbackManager {
|
||||
std::error_code EC;
|
||||
auto TrampolineBlock =
|
||||
sys::OwningMemoryBlock(
|
||||
sys::Memory::allocateMappedMemory(TargetT::PageSize, nullptr,
|
||||
sys::Memory::allocateMappedMemory(sys::Process::getPageSize(), nullptr,
|
||||
sys::Memory::MF_READ |
|
||||
sys::Memory::MF_WRITE, EC));
|
||||
assert(!EC && "Failed to allocate trampoline block");
|
||||
|
||||
|
||||
unsigned NumTrampolines =
|
||||
(TargetT::PageSize - TargetT::PointerSize) / TargetT::TrampolineSize;
|
||||
(sys::Process::getPageSize() - TargetT::PointerSize) /
|
||||
TargetT::TrampolineSize;
|
||||
|
||||
uint8_t *TrampolineMem = static_cast<uint8_t*>(TrampolineBlock.base());
|
||||
TargetT::writeTrampolines(TrampolineMem, ResolverBlock.base(),
|
||||
@ -240,8 +242,8 @@ class IndirectStubsManager {
|
||||
virtual void anchor();
|
||||
};
|
||||
|
||||
/// @brief IndirectStubsManager implementation for a concrete target, e.g.
|
||||
/// OrcX86_64. (See OrcTargetSupport.h).
|
||||
/// @brief IndirectStubsManager implementation for the host architecture, e.g.
|
||||
/// OrcX86_64. (See OrcArchitectureSupport.h).
|
||||
template <typename TargetT>
|
||||
class LocalIndirectStubsManager : public IndirectStubsManager {
|
||||
public:
|
||||
|
@ -108,9 +108,7 @@ class ObjectLinkingLayer : public ObjectLinkingLayerBase {
|
||||
|
||||
void Finalize() override {
|
||||
State = Finalizing;
|
||||
RTDyld->resolveRelocations();
|
||||
RTDyld->registerEHFrames();
|
||||
MemMgr->finalizeMemory();
|
||||
RTDyld->finalizeWithMemoryManagerLocking();
|
||||
State = Finalized;
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
//===-- OrcTargetSupport.h - Code to support specific targets --*- C++ -*-===//
|
||||
//===-- OrcArchitectureSupport.h - Architecture support code ---*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
@ -7,32 +7,76 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Target specific code for Orc, e.g. callback assembly.
|
||||
// Architecture specific code for Orc, e.g. callback assembly.
|
||||
//
|
||||
// Target classes should be part of the JIT *target* process, not the host
|
||||
// Architecture classes should be part of the JIT *target* process, not the host
|
||||
// process (except where you're doing hosted JITing and the two are one and the
|
||||
// same).
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_EXECUTIONENGINE_ORC_ORCTARGETSUPPORT_H
|
||||
#define LLVM_EXECUTIONENGINE_ORC_ORCTARGETSUPPORT_H
|
||||
#ifndef LLVM_EXECUTIONENGINE_ORC_ORCARCHITECTURESUPPORT_H
|
||||
#define LLVM_EXECUTIONENGINE_ORC_ORCARCHITECTURESUPPORT_H
|
||||
|
||||
#include "IndirectionUtils.h"
|
||||
#include "llvm/Support/Memory.h"
|
||||
#include "llvm/Support/Process.h"
|
||||
|
||||
namespace llvm {
|
||||
namespace orc {
|
||||
|
||||
/// Generic ORC Architecture support.
|
||||
///
|
||||
/// This class can be substituted as the target architecure support class for
|
||||
/// ORC templates that require one (e.g. IndirectStubsManagers). It does not
|
||||
/// support lazy JITing however, and any attempt to use that functionality
|
||||
/// will result in execution of an llvm_unreachable.
|
||||
class OrcGenericArchitecture {
|
||||
public:
|
||||
static const unsigned PointerSize = sizeof(uintptr_t);
|
||||
static const unsigned TrampolineSize = 1;
|
||||
static const unsigned ResolverCodeSize = 1;
|
||||
|
||||
typedef TargetAddress (*JITReentryFn)(void *CallbackMgr, void *TrampolineId);
|
||||
|
||||
static void writeResolverCode(uint8_t *ResolveMem, JITReentryFn Reentry,
|
||||
void *CallbackMgr) {
|
||||
llvm_unreachable("writeResolverCode is not supported by the generic host "
|
||||
"support class");
|
||||
}
|
||||
|
||||
static void writeTrampolines(uint8_t *TrampolineMem, void *ResolverAddr,
|
||||
unsigned NumTrampolines) {
|
||||
llvm_unreachable("writeTrampolines is not supported by the generic host "
|
||||
"support class");
|
||||
}
|
||||
|
||||
class IndirectStubsInfo {
|
||||
public:
|
||||
const static unsigned StubSize = 1;
|
||||
unsigned getNumStubs() const { llvm_unreachable("Not supported"); }
|
||||
void *getStub(unsigned Idx) const { llvm_unreachable("Not supported"); }
|
||||
void **getPtr(unsigned Idx) const { llvm_unreachable("Not supported"); }
|
||||
};
|
||||
|
||||
static std::error_code emitIndirectStubsBlock(IndirectStubsInfo &StubsInfo,
|
||||
unsigned MinStubs,
|
||||
void *InitialPtrVal) {
|
||||
llvm_unreachable("emitIndirectStubsBlock is not supported by the generic "
|
||||
"host support class");
|
||||
}
|
||||
};
|
||||
|
||||
/// @brief X86_64 support.
|
||||
///
|
||||
/// X86_64 supports lazy JITing.
|
||||
class OrcX86_64 {
|
||||
public:
|
||||
static const unsigned PageSize = 4096;
|
||||
static const unsigned PointerSize = 8;
|
||||
static const unsigned TrampolineSize = 8;
|
||||
static const unsigned ResolverCodeSize = 0x78;
|
||||
|
||||
typedef TargetAddress (*JITReentryFn)(void *CallbackMgr,
|
||||
void *TrampolineId);
|
||||
typedef TargetAddress (*JITReentryFn)(void *CallbackMgr, void *TrampolineId);
|
||||
|
||||
/// @brief Write the resolver code into the given memory. The user is be
|
||||
/// responsible for allocating the memory and setting permissions.
|
||||
@ -49,16 +93,16 @@ class OrcX86_64 {
|
||||
/// makeIndirectStubsBlock function.
|
||||
class IndirectStubsInfo {
|
||||
friend class OrcX86_64;
|
||||
|
||||
public:
|
||||
const static unsigned StubSize = 8;
|
||||
const static unsigned PtrSize = 8;
|
||||
|
||||
IndirectStubsInfo() : NumStubs(0) {}
|
||||
IndirectStubsInfo(IndirectStubsInfo &&Other)
|
||||
: NumStubs(Other.NumStubs), StubsMem(std::move(Other.StubsMem)) {
|
||||
Other.NumStubs = 0;
|
||||
}
|
||||
IndirectStubsInfo& operator=(IndirectStubsInfo &&Other) {
|
||||
IndirectStubsInfo &operator=(IndirectStubsInfo &&Other) {
|
||||
NumStubs = Other.NumStubs;
|
||||
Other.NumStubs = 0;
|
||||
StubsMem = std::move(Other.StubsMem);
|
||||
@ -70,17 +114,18 @@ class OrcX86_64 {
|
||||
|
||||
/// @brief Get a pointer to the stub at the given index, which must be in
|
||||
/// the range 0 .. getNumStubs() - 1.
|
||||
void* getStub(unsigned Idx) const {
|
||||
return static_cast<uint64_t*>(StubsMem.base()) + Idx;
|
||||
void *getStub(unsigned Idx) const {
|
||||
return static_cast<uint64_t *>(StubsMem.base()) + Idx;
|
||||
}
|
||||
|
||||
/// @brief Get a pointer to the implementation-pointer at the given index,
|
||||
/// which must be in the range 0 .. getNumStubs() - 1.
|
||||
void** getPtr(unsigned Idx) const {
|
||||
void **getPtr(unsigned Idx) const {
|
||||
char *PtrsBase =
|
||||
static_cast<char*>(StubsMem.base()) + NumStubs * StubSize;
|
||||
return reinterpret_cast<void**>(PtrsBase) + Idx;
|
||||
static_cast<char *>(StubsMem.base()) + NumStubs * StubSize;
|
||||
return reinterpret_cast<void **>(PtrsBase) + Idx;
|
||||
}
|
||||
|
||||
private:
|
||||
unsigned NumStubs;
|
||||
sys::OwningMemoryBlock StubsMem;
|
||||
@ -100,4 +145,4 @@ class OrcX86_64 {
|
||||
} // End namespace orc.
|
||||
} // End namespace llvm.
|
||||
|
||||
#endif // LLVM_EXECUTIONENGINE_ORC_ORCTARGETSUPPORT_H
|
||||
#endif // LLVM_EXECUTIONENGINE_ORC_ORCARCHITECTURESUPPORT_H
|
37
contrib/llvm/include/llvm/ExecutionEngine/Orc/OrcError.h
Normal file
37
contrib/llvm/include/llvm/ExecutionEngine/Orc/OrcError.h
Normal file
@ -0,0 +1,37 @@
|
||||
//===------ OrcError.h - Reject symbol lookup requests ------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Define an error category, error codes, and helper utilities for Orc.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_EXECUTIONENGINE_ORC_ORCERROR_H
|
||||
#define LLVM_EXECUTIONENGINE_ORC_ORCERROR_H
|
||||
|
||||
#include <system_error>
|
||||
|
||||
namespace llvm {
|
||||
namespace orc {
|
||||
|
||||
enum class OrcErrorCode : int {
|
||||
// RPC Errors
|
||||
RemoteAllocatorDoesNotExist = 1,
|
||||
RemoteAllocatorIdAlreadyInUse,
|
||||
RemoteMProtectAddrUnrecognized,
|
||||
RemoteIndirectStubsOwnerDoesNotExist,
|
||||
RemoteIndirectStubsOwnerIdAlreadyInUse,
|
||||
UnexpectedRPCCall
|
||||
};
|
||||
|
||||
std::error_code orcError(OrcErrorCode ErrCode);
|
||||
|
||||
} // End namespace orc.
|
||||
} // End namespace llvm.
|
||||
|
||||
#endif // LLVM_EXECUTIONENGINE_ORC_ORCERROR_H
|
@ -0,0 +1,784 @@
|
||||
//===---- OrcRemoteTargetClient.h - Orc Remote-target Client ----*- 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 OrcRemoteTargetClient class and helpers. This class
|
||||
// can be used to communicate over an RPCChannel with an OrcRemoteTargetServer
|
||||
// instance to support remote-JITing.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_EXECUTIONENGINE_ORC_ORCREMOTETARGETCLIENT_H
|
||||
#define LLVM_EXECUTIONENGINE_ORC_ORCREMOTETARGETCLIENT_H
|
||||
|
||||
#include "IndirectionUtils.h"
|
||||
#include "OrcRemoteTargetRPCAPI.h"
|
||||
#include <system_error>
|
||||
|
||||
#define DEBUG_TYPE "orc-remote"
|
||||
|
||||
namespace llvm {
|
||||
namespace orc {
|
||||
namespace remote {
|
||||
|
||||
/// This class provides utilities (including memory manager, indirect stubs
|
||||
/// manager, and compile callback manager types) that support remote JITing
|
||||
/// in ORC.
|
||||
///
|
||||
/// Each of the utility classes talks to a JIT server (an instance of the
|
||||
/// OrcRemoteTargetServer class) via an RPC system (see RPCUtils.h) to carry out
|
||||
/// its actions.
|
||||
template <typename ChannelT>
|
||||
class OrcRemoteTargetClient : public OrcRemoteTargetRPCAPI {
|
||||
public:
|
||||
/// Remote memory manager.
|
||||
class RCMemoryManager : public RuntimeDyld::MemoryManager {
|
||||
public:
|
||||
RCMemoryManager(OrcRemoteTargetClient &Client, ResourceIdMgr::ResourceId Id)
|
||||
: Client(Client), Id(Id) {
|
||||
DEBUG(dbgs() << "Created remote allocator " << Id << "\n");
|
||||
}
|
||||
|
||||
RCMemoryManager(RCMemoryManager &&Other)
|
||||
: Client(std::move(Other.Client)), Id(std::move(Other.Id)),
|
||||
Unmapped(std::move(Other.Unmapped)),
|
||||
Unfinalized(std::move(Other.Unfinalized)) {}
|
||||
|
||||
RCMemoryManager operator=(RCMemoryManager &&Other) {
|
||||
Client = std::move(Other.Client);
|
||||
Id = std::move(Other.Id);
|
||||
Unmapped = std::move(Other.Unmapped);
|
||||
Unfinalized = std::move(Other.Unfinalized);
|
||||
return *this;
|
||||
}
|
||||
|
||||
~RCMemoryManager() {
|
||||
Client.destroyRemoteAllocator(Id);
|
||||
DEBUG(dbgs() << "Destroyed remote allocator " << Id << "\n");
|
||||
}
|
||||
|
||||
uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment,
|
||||
unsigned SectionID,
|
||||
StringRef SectionName) override {
|
||||
Unmapped.back().CodeAllocs.emplace_back(Size, Alignment);
|
||||
uint8_t *Alloc = reinterpret_cast<uint8_t *>(
|
||||
Unmapped.back().CodeAllocs.back().getLocalAddress());
|
||||
DEBUG(dbgs() << "Allocator " << Id << " allocated code for "
|
||||
<< SectionName << ": " << Alloc << " (" << Size
|
||||
<< " bytes, alignment " << Alignment << ")\n");
|
||||
return Alloc;
|
||||
}
|
||||
|
||||
uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment,
|
||||
unsigned SectionID, StringRef SectionName,
|
||||
bool IsReadOnly) override {
|
||||
if (IsReadOnly) {
|
||||
Unmapped.back().RODataAllocs.emplace_back(Size, Alignment);
|
||||
uint8_t *Alloc = reinterpret_cast<uint8_t *>(
|
||||
Unmapped.back().RODataAllocs.back().getLocalAddress());
|
||||
DEBUG(dbgs() << "Allocator " << Id << " allocated ro-data for "
|
||||
<< SectionName << ": " << Alloc << " (" << Size
|
||||
<< " bytes, alignment " << Alignment << ")\n");
|
||||
return Alloc;
|
||||
} // else...
|
||||
|
||||
Unmapped.back().RWDataAllocs.emplace_back(Size, Alignment);
|
||||
uint8_t *Alloc = reinterpret_cast<uint8_t *>(
|
||||
Unmapped.back().RWDataAllocs.back().getLocalAddress());
|
||||
DEBUG(dbgs() << "Allocator " << Id << " allocated rw-data for "
|
||||
<< SectionName << ": " << Alloc << " (" << Size
|
||||
<< " bytes, alignment " << Alignment << ")\n");
|
||||
return Alloc;
|
||||
}
|
||||
|
||||
void reserveAllocationSpace(uintptr_t CodeSize, uint32_t CodeAlign,
|
||||
uintptr_t RODataSize, uint32_t RODataAlign,
|
||||
uintptr_t RWDataSize,
|
||||
uint32_t RWDataAlign) override {
|
||||
Unmapped.push_back(ObjectAllocs());
|
||||
|
||||
DEBUG(dbgs() << "Allocator " << Id << " reserved:\n");
|
||||
|
||||
if (CodeSize != 0) {
|
||||
std::error_code EC = Client.reserveMem(Unmapped.back().RemoteCodeAddr,
|
||||
Id, CodeSize, CodeAlign);
|
||||
// FIXME; Add error to poll.
|
||||
assert(!EC && "Failed reserving remote memory.");
|
||||
(void)EC;
|
||||
DEBUG(dbgs() << " code: "
|
||||
<< format("0x%016x", Unmapped.back().RemoteCodeAddr)
|
||||
<< " (" << CodeSize << " bytes, alignment " << CodeAlign
|
||||
<< ")\n");
|
||||
}
|
||||
|
||||
if (RODataSize != 0) {
|
||||
std::error_code EC = Client.reserveMem(Unmapped.back().RemoteRODataAddr,
|
||||
Id, RODataSize, RODataAlign);
|
||||
// FIXME; Add error to poll.
|
||||
assert(!EC && "Failed reserving remote memory.");
|
||||
(void)EC;
|
||||
DEBUG(dbgs() << " ro-data: "
|
||||
<< format("0x%016x", Unmapped.back().RemoteRODataAddr)
|
||||
<< " (" << RODataSize << " bytes, alignment "
|
||||
<< RODataAlign << ")\n");
|
||||
}
|
||||
|
||||
if (RWDataSize != 0) {
|
||||
std::error_code EC = Client.reserveMem(Unmapped.back().RemoteRWDataAddr,
|
||||
Id, RWDataSize, RWDataAlign);
|
||||
// FIXME; Add error to poll.
|
||||
assert(!EC && "Failed reserving remote memory.");
|
||||
(void)EC;
|
||||
DEBUG(dbgs() << " rw-data: "
|
||||
<< format("0x%016x", Unmapped.back().RemoteRWDataAddr)
|
||||
<< " (" << RWDataSize << " bytes, alignment "
|
||||
<< RWDataAlign << ")\n");
|
||||
}
|
||||
}
|
||||
|
||||
bool needsToReserveAllocationSpace() override { return true; }
|
||||
|
||||
void registerEHFrames(uint8_t *Addr, uint64_t LoadAddr,
|
||||
size_t Size) override {}
|
||||
|
||||
void deregisterEHFrames(uint8_t *addr, uint64_t LoadAddr,
|
||||
size_t Size) override {}
|
||||
|
||||
void notifyObjectLoaded(RuntimeDyld &Dyld,
|
||||
const object::ObjectFile &Obj) override {
|
||||
DEBUG(dbgs() << "Allocator " << Id << " applied mappings:\n");
|
||||
for (auto &ObjAllocs : Unmapped) {
|
||||
{
|
||||
TargetAddress NextCodeAddr = ObjAllocs.RemoteCodeAddr;
|
||||
for (auto &Alloc : ObjAllocs.CodeAllocs) {
|
||||
NextCodeAddr = RoundUpToAlignment(NextCodeAddr, Alloc.getAlign());
|
||||
Dyld.mapSectionAddress(Alloc.getLocalAddress(), NextCodeAddr);
|
||||
DEBUG(dbgs() << " code: "
|
||||
<< static_cast<void *>(Alloc.getLocalAddress())
|
||||
<< " -> " << format("0x%016x", NextCodeAddr) << "\n");
|
||||
Alloc.setRemoteAddress(NextCodeAddr);
|
||||
NextCodeAddr += Alloc.getSize();
|
||||
}
|
||||
}
|
||||
{
|
||||
TargetAddress NextRODataAddr = ObjAllocs.RemoteRODataAddr;
|
||||
for (auto &Alloc : ObjAllocs.RODataAllocs) {
|
||||
NextRODataAddr =
|
||||
RoundUpToAlignment(NextRODataAddr, Alloc.getAlign());
|
||||
Dyld.mapSectionAddress(Alloc.getLocalAddress(), NextRODataAddr);
|
||||
DEBUG(dbgs() << " ro-data: "
|
||||
<< static_cast<void *>(Alloc.getLocalAddress())
|
||||
<< " -> " << format("0x%016x", NextRODataAddr)
|
||||
<< "\n");
|
||||
Alloc.setRemoteAddress(NextRODataAddr);
|
||||
NextRODataAddr += Alloc.getSize();
|
||||
}
|
||||
}
|
||||
{
|
||||
TargetAddress NextRWDataAddr = ObjAllocs.RemoteRWDataAddr;
|
||||
for (auto &Alloc : ObjAllocs.RWDataAllocs) {
|
||||
NextRWDataAddr =
|
||||
RoundUpToAlignment(NextRWDataAddr, Alloc.getAlign());
|
||||
Dyld.mapSectionAddress(Alloc.getLocalAddress(), NextRWDataAddr);
|
||||
DEBUG(dbgs() << " rw-data: "
|
||||
<< static_cast<void *>(Alloc.getLocalAddress())
|
||||
<< " -> " << format("0x%016x", NextRWDataAddr)
|
||||
<< "\n");
|
||||
Alloc.setRemoteAddress(NextRWDataAddr);
|
||||
NextRWDataAddr += Alloc.getSize();
|
||||
}
|
||||
}
|
||||
Unfinalized.push_back(std::move(ObjAllocs));
|
||||
}
|
||||
Unmapped.clear();
|
||||
}
|
||||
|
||||
bool finalizeMemory(std::string *ErrMsg = nullptr) override {
|
||||
DEBUG(dbgs() << "Allocator " << Id << " finalizing:\n");
|
||||
|
||||
for (auto &ObjAllocs : Unfinalized) {
|
||||
|
||||
for (auto &Alloc : ObjAllocs.CodeAllocs) {
|
||||
DEBUG(dbgs() << " copying code: "
|
||||
<< static_cast<void *>(Alloc.getLocalAddress()) << " -> "
|
||||
<< format("0x%016x", Alloc.getRemoteAddress()) << " ("
|
||||
<< Alloc.getSize() << " bytes)\n");
|
||||
Client.writeMem(Alloc.getRemoteAddress(), Alloc.getLocalAddress(),
|
||||
Alloc.getSize());
|
||||
}
|
||||
|
||||
if (ObjAllocs.RemoteCodeAddr) {
|
||||
DEBUG(dbgs() << " setting R-X permissions on code block: "
|
||||
<< format("0x%016x", ObjAllocs.RemoteCodeAddr) << "\n");
|
||||
Client.setProtections(Id, ObjAllocs.RemoteCodeAddr,
|
||||
sys::Memory::MF_READ | sys::Memory::MF_EXEC);
|
||||
}
|
||||
|
||||
for (auto &Alloc : ObjAllocs.RODataAllocs) {
|
||||
DEBUG(dbgs() << " copying ro-data: "
|
||||
<< static_cast<void *>(Alloc.getLocalAddress()) << " -> "
|
||||
<< format("0x%016x", Alloc.getRemoteAddress()) << " ("
|
||||
<< Alloc.getSize() << " bytes)\n");
|
||||
Client.writeMem(Alloc.getRemoteAddress(), Alloc.getLocalAddress(),
|
||||
Alloc.getSize());
|
||||
}
|
||||
|
||||
if (ObjAllocs.RemoteRODataAddr) {
|
||||
DEBUG(dbgs() << " setting R-- permissions on ro-data block: "
|
||||
<< format("0x%016x", ObjAllocs.RemoteRODataAddr)
|
||||
<< "\n");
|
||||
Client.setProtections(Id, ObjAllocs.RemoteRODataAddr,
|
||||
sys::Memory::MF_READ);
|
||||
}
|
||||
|
||||
for (auto &Alloc : ObjAllocs.RWDataAllocs) {
|
||||
DEBUG(dbgs() << " copying rw-data: "
|
||||
<< static_cast<void *>(Alloc.getLocalAddress()) << " -> "
|
||||
<< format("0x%016x", Alloc.getRemoteAddress()) << " ("
|
||||
<< Alloc.getSize() << " bytes)\n");
|
||||
Client.writeMem(Alloc.getRemoteAddress(), Alloc.getLocalAddress(),
|
||||
Alloc.getSize());
|
||||
}
|
||||
|
||||
if (ObjAllocs.RemoteRWDataAddr) {
|
||||
DEBUG(dbgs() << " setting RW- permissions on rw-data block: "
|
||||
<< format("0x%016x", ObjAllocs.RemoteRWDataAddr)
|
||||
<< "\n");
|
||||
Client.setProtections(Id, ObjAllocs.RemoteRWDataAddr,
|
||||
sys::Memory::MF_READ | sys::Memory::MF_WRITE);
|
||||
}
|
||||
}
|
||||
Unfinalized.clear();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
class Alloc {
|
||||
public:
|
||||
Alloc(uint64_t Size, unsigned Align)
|
||||
: Size(Size), Align(Align), Contents(new char[Size + Align - 1]),
|
||||
RemoteAddr(0) {}
|
||||
|
||||
Alloc(Alloc &&Other)
|
||||
: Size(std::move(Other.Size)), Align(std::move(Other.Align)),
|
||||
Contents(std::move(Other.Contents)),
|
||||
RemoteAddr(std::move(Other.RemoteAddr)) {}
|
||||
|
||||
Alloc &operator=(Alloc &&Other) {
|
||||
Size = std::move(Other.Size);
|
||||
Align = std::move(Other.Align);
|
||||
Contents = std::move(Other.Contents);
|
||||
RemoteAddr = std::move(Other.RemoteAddr);
|
||||
return *this;
|
||||
}
|
||||
|
||||
uint64_t getSize() const { return Size; }
|
||||
|
||||
unsigned getAlign() const { return Align; }
|
||||
|
||||
char *getLocalAddress() const {
|
||||
uintptr_t LocalAddr = reinterpret_cast<uintptr_t>(Contents.get());
|
||||
LocalAddr = RoundUpToAlignment(LocalAddr, Align);
|
||||
return reinterpret_cast<char *>(LocalAddr);
|
||||
}
|
||||
|
||||
void setRemoteAddress(TargetAddress RemoteAddr) {
|
||||
this->RemoteAddr = RemoteAddr;
|
||||
}
|
||||
|
||||
TargetAddress getRemoteAddress() const { return RemoteAddr; }
|
||||
|
||||
private:
|
||||
uint64_t Size;
|
||||
unsigned Align;
|
||||
std::unique_ptr<char[]> Contents;
|
||||
TargetAddress RemoteAddr;
|
||||
};
|
||||
|
||||
struct ObjectAllocs {
|
||||
ObjectAllocs()
|
||||
: RemoteCodeAddr(0), RemoteRODataAddr(0), RemoteRWDataAddr(0) {}
|
||||
|
||||
ObjectAllocs(ObjectAllocs &&Other)
|
||||
: RemoteCodeAddr(std::move(Other.RemoteCodeAddr)),
|
||||
RemoteRODataAddr(std::move(Other.RemoteRODataAddr)),
|
||||
RemoteRWDataAddr(std::move(Other.RemoteRWDataAddr)),
|
||||
CodeAllocs(std::move(Other.CodeAllocs)),
|
||||
RODataAllocs(std::move(Other.RODataAllocs)),
|
||||
RWDataAllocs(std::move(Other.RWDataAllocs)) {}
|
||||
|
||||
ObjectAllocs &operator=(ObjectAllocs &&Other) {
|
||||
RemoteCodeAddr = std::move(Other.RemoteCodeAddr);
|
||||
RemoteRODataAddr = std::move(Other.RemoteRODataAddr);
|
||||
RemoteRWDataAddr = std::move(Other.RemoteRWDataAddr);
|
||||
CodeAllocs = std::move(Other.CodeAllocs);
|
||||
RODataAllocs = std::move(Other.RODataAllocs);
|
||||
RWDataAllocs = std::move(Other.RWDataAllocs);
|
||||
return *this;
|
||||
}
|
||||
|
||||
TargetAddress RemoteCodeAddr;
|
||||
TargetAddress RemoteRODataAddr;
|
||||
TargetAddress RemoteRWDataAddr;
|
||||
std::vector<Alloc> CodeAllocs, RODataAllocs, RWDataAllocs;
|
||||
};
|
||||
|
||||
OrcRemoteTargetClient &Client;
|
||||
ResourceIdMgr::ResourceId Id;
|
||||
std::vector<ObjectAllocs> Unmapped;
|
||||
std::vector<ObjectAllocs> Unfinalized;
|
||||
};
|
||||
|
||||
/// Remote indirect stubs manager.
|
||||
class RCIndirectStubsManager : public IndirectStubsManager {
|
||||
public:
|
||||
RCIndirectStubsManager(OrcRemoteTargetClient &Remote,
|
||||
ResourceIdMgr::ResourceId Id)
|
||||
: Remote(Remote), Id(Id) {}
|
||||
|
||||
~RCIndirectStubsManager() { Remote.destroyIndirectStubsManager(Id); }
|
||||
|
||||
std::error_code createStub(StringRef StubName, TargetAddress StubAddr,
|
||||
JITSymbolFlags StubFlags) override {
|
||||
if (auto EC = reserveStubs(1))
|
||||
return EC;
|
||||
|
||||
return createStubInternal(StubName, StubAddr, StubFlags);
|
||||
}
|
||||
|
||||
std::error_code createStubs(const StubInitsMap &StubInits) override {
|
||||
if (auto EC = reserveStubs(StubInits.size()))
|
||||
return EC;
|
||||
|
||||
for (auto &Entry : StubInits)
|
||||
if (auto EC = createStubInternal(Entry.first(), Entry.second.first,
|
||||
Entry.second.second))
|
||||
return EC;
|
||||
|
||||
return std::error_code();
|
||||
}
|
||||
|
||||
JITSymbol findStub(StringRef Name, bool ExportedStubsOnly) override {
|
||||
auto I = StubIndexes.find(Name);
|
||||
if (I == StubIndexes.end())
|
||||
return nullptr;
|
||||
auto Key = I->second.first;
|
||||
auto Flags = I->second.second;
|
||||
auto StubSymbol = JITSymbol(getStubAddr(Key), Flags);
|
||||
if (ExportedStubsOnly && !StubSymbol.isExported())
|
||||
return nullptr;
|
||||
return StubSymbol;
|
||||
}
|
||||
|
||||
JITSymbol findPointer(StringRef Name) override {
|
||||
auto I = StubIndexes.find(Name);
|
||||
if (I == StubIndexes.end())
|
||||
return nullptr;
|
||||
auto Key = I->second.first;
|
||||
auto Flags = I->second.second;
|
||||
return JITSymbol(getPtrAddr(Key), Flags);
|
||||
}
|
||||
|
||||
std::error_code updatePointer(StringRef Name,
|
||||
TargetAddress NewAddr) override {
|
||||
auto I = StubIndexes.find(Name);
|
||||
assert(I != StubIndexes.end() && "No stub pointer for symbol");
|
||||
auto Key = I->second.first;
|
||||
return Remote.writePointer(getPtrAddr(Key), NewAddr);
|
||||
}
|
||||
|
||||
private:
|
||||
struct RemoteIndirectStubsInfo {
|
||||
RemoteIndirectStubsInfo(TargetAddress StubBase, TargetAddress PtrBase,
|
||||
unsigned NumStubs)
|
||||
: StubBase(StubBase), PtrBase(PtrBase), NumStubs(NumStubs) {}
|
||||
TargetAddress StubBase;
|
||||
TargetAddress PtrBase;
|
||||
unsigned NumStubs;
|
||||
};
|
||||
|
||||
OrcRemoteTargetClient &Remote;
|
||||
ResourceIdMgr::ResourceId Id;
|
||||
std::vector<RemoteIndirectStubsInfo> RemoteIndirectStubsInfos;
|
||||
typedef std::pair<uint16_t, uint16_t> StubKey;
|
||||
std::vector<StubKey> FreeStubs;
|
||||
StringMap<std::pair<StubKey, JITSymbolFlags>> StubIndexes;
|
||||
|
||||
std::error_code reserveStubs(unsigned NumStubs) {
|
||||
if (NumStubs <= FreeStubs.size())
|
||||
return std::error_code();
|
||||
|
||||
unsigned NewStubsRequired = NumStubs - FreeStubs.size();
|
||||
TargetAddress StubBase;
|
||||
TargetAddress PtrBase;
|
||||
unsigned NumStubsEmitted;
|
||||
|
||||
Remote.emitIndirectStubs(StubBase, PtrBase, NumStubsEmitted, Id,
|
||||
NewStubsRequired);
|
||||
|
||||
unsigned NewBlockId = RemoteIndirectStubsInfos.size();
|
||||
RemoteIndirectStubsInfos.push_back(
|
||||
RemoteIndirectStubsInfo(StubBase, PtrBase, NumStubsEmitted));
|
||||
|
||||
for (unsigned I = 0; I < NumStubsEmitted; ++I)
|
||||
FreeStubs.push_back(std::make_pair(NewBlockId, I));
|
||||
|
||||
return std::error_code();
|
||||
}
|
||||
|
||||
std::error_code createStubInternal(StringRef StubName,
|
||||
TargetAddress InitAddr,
|
||||
JITSymbolFlags StubFlags) {
|
||||
auto Key = FreeStubs.back();
|
||||
FreeStubs.pop_back();
|
||||
StubIndexes[StubName] = std::make_pair(Key, StubFlags);
|
||||
return Remote.writePointer(getPtrAddr(Key), InitAddr);
|
||||
}
|
||||
|
||||
TargetAddress getStubAddr(StubKey K) {
|
||||
assert(RemoteIndirectStubsInfos[K.first].StubBase != 0 &&
|
||||
"Missing stub address");
|
||||
return RemoteIndirectStubsInfos[K.first].StubBase +
|
||||
K.second * Remote.getIndirectStubSize();
|
||||
}
|
||||
|
||||
TargetAddress getPtrAddr(StubKey K) {
|
||||
assert(RemoteIndirectStubsInfos[K.first].PtrBase != 0 &&
|
||||
"Missing pointer address");
|
||||
return RemoteIndirectStubsInfos[K.first].PtrBase +
|
||||
K.second * Remote.getPointerSize();
|
||||
}
|
||||
};
|
||||
|
||||
/// Remote compile callback manager.
|
||||
class RCCompileCallbackManager : public JITCompileCallbackManager {
|
||||
public:
|
||||
RCCompileCallbackManager(TargetAddress ErrorHandlerAddress,
|
||||
OrcRemoteTargetClient &Remote)
|
||||
: JITCompileCallbackManager(ErrorHandlerAddress), Remote(Remote) {
|
||||
assert(!Remote.CompileCallback && "Compile callback already set");
|
||||
Remote.CompileCallback = [this](TargetAddress TrampolineAddr) {
|
||||
return executeCompileCallback(TrampolineAddr);
|
||||
};
|
||||
Remote.emitResolverBlock();
|
||||
}
|
||||
|
||||
private:
|
||||
void grow() {
|
||||
TargetAddress BlockAddr = 0;
|
||||
uint32_t NumTrampolines = 0;
|
||||
auto EC = Remote.emitTrampolineBlock(BlockAddr, NumTrampolines);
|
||||
assert(!EC && "Failed to create trampolines");
|
||||
|
||||
uint32_t TrampolineSize = Remote.getTrampolineSize();
|
||||
for (unsigned I = 0; I < NumTrampolines; ++I)
|
||||
this->AvailableTrampolines.push_back(BlockAddr + (I * TrampolineSize));
|
||||
}
|
||||
|
||||
OrcRemoteTargetClient &Remote;
|
||||
};
|
||||
|
||||
/// Create an OrcRemoteTargetClient.
|
||||
/// Channel is the ChannelT instance to communicate on. It is assumed that
|
||||
/// the channel is ready to be read from and written to.
|
||||
static ErrorOr<OrcRemoteTargetClient> Create(ChannelT &Channel) {
|
||||
std::error_code EC;
|
||||
OrcRemoteTargetClient H(Channel, EC);
|
||||
if (EC)
|
||||
return EC;
|
||||
return H;
|
||||
}
|
||||
|
||||
/// Call the int(void) function at the given address in the target and return
|
||||
/// its result.
|
||||
std::error_code callIntVoid(int &Result, TargetAddress Addr) {
|
||||
DEBUG(dbgs() << "Calling int(*)(void) " << format("0x%016x", Addr) << "\n");
|
||||
|
||||
if (auto EC = call<CallIntVoid>(Channel, Addr))
|
||||
return EC;
|
||||
|
||||
unsigned NextProcId;
|
||||
if (auto EC = listenForCompileRequests(NextProcId))
|
||||
return EC;
|
||||
|
||||
if (NextProcId != CallIntVoidResponseId)
|
||||
return orcError(OrcErrorCode::UnexpectedRPCCall);
|
||||
|
||||
return handle<CallIntVoidResponse>(Channel, [&](int R) {
|
||||
Result = R;
|
||||
DEBUG(dbgs() << "Result: " << R << "\n");
|
||||
return std::error_code();
|
||||
});
|
||||
}
|
||||
|
||||
/// Call the int(int, char*[]) function at the given address in the target and
|
||||
/// return its result.
|
||||
std::error_code callMain(int &Result, TargetAddress Addr,
|
||||
const std::vector<std::string> &Args) {
|
||||
DEBUG(dbgs() << "Calling int(*)(int, char*[]) " << format("0x%016x", Addr)
|
||||
<< "\n");
|
||||
|
||||
if (auto EC = call<CallMain>(Channel, Addr, Args))
|
||||
return EC;
|
||||
|
||||
unsigned NextProcId;
|
||||
if (auto EC = listenForCompileRequests(NextProcId))
|
||||
return EC;
|
||||
|
||||
if (NextProcId != CallMainResponseId)
|
||||
return orcError(OrcErrorCode::UnexpectedRPCCall);
|
||||
|
||||
return handle<CallMainResponse>(Channel, [&](int R) {
|
||||
Result = R;
|
||||
DEBUG(dbgs() << "Result: " << R << "\n");
|
||||
return std::error_code();
|
||||
});
|
||||
}
|
||||
|
||||
/// Call the void() function at the given address in the target and wait for
|
||||
/// it to finish.
|
||||
std::error_code callVoidVoid(TargetAddress Addr) {
|
||||
DEBUG(dbgs() << "Calling void(*)(void) " << format("0x%016x", Addr)
|
||||
<< "\n");
|
||||
|
||||
if (auto EC = call<CallVoidVoid>(Channel, Addr))
|
||||
return EC;
|
||||
|
||||
unsigned NextProcId;
|
||||
if (auto EC = listenForCompileRequests(NextProcId))
|
||||
return EC;
|
||||
|
||||
if (NextProcId != CallVoidVoidResponseId)
|
||||
return orcError(OrcErrorCode::UnexpectedRPCCall);
|
||||
|
||||
return handle<CallVoidVoidResponse>(Channel, doNothing);
|
||||
}
|
||||
|
||||
/// Create an RCMemoryManager which will allocate its memory on the remote
|
||||
/// target.
|
||||
std::error_code
|
||||
createRemoteMemoryManager(std::unique_ptr<RCMemoryManager> &MM) {
|
||||
assert(!MM && "MemoryManager should be null before creation.");
|
||||
|
||||
auto Id = AllocatorIds.getNext();
|
||||
if (auto EC = call<CreateRemoteAllocator>(Channel, Id))
|
||||
return EC;
|
||||
MM = llvm::make_unique<RCMemoryManager>(*this, Id);
|
||||
return std::error_code();
|
||||
}
|
||||
|
||||
/// Create an RCIndirectStubsManager that will allocate stubs on the remote
|
||||
/// target.
|
||||
std::error_code
|
||||
createIndirectStubsManager(std::unique_ptr<RCIndirectStubsManager> &I) {
|
||||
assert(!I && "Indirect stubs manager should be null before creation.");
|
||||
auto Id = IndirectStubOwnerIds.getNext();
|
||||
if (auto EC = call<CreateIndirectStubsOwner>(Channel, Id))
|
||||
return EC;
|
||||
I = llvm::make_unique<RCIndirectStubsManager>(*this, Id);
|
||||
return std::error_code();
|
||||
}
|
||||
|
||||
/// Search for symbols in the remote process. Note: This should be used by
|
||||
/// symbol resolvers *after* they've searched the local symbol table in the
|
||||
/// JIT stack.
|
||||
std::error_code getSymbolAddress(TargetAddress &Addr, StringRef Name) {
|
||||
// Check for an 'out-of-band' error, e.g. from an MM destructor.
|
||||
if (ExistingError)
|
||||
return ExistingError;
|
||||
|
||||
// Request remote symbol address.
|
||||
if (auto EC = call<GetSymbolAddress>(Channel, Name))
|
||||
return EC;
|
||||
|
||||
return expect<GetSymbolAddressResponse>(Channel, [&](TargetAddress &A) {
|
||||
Addr = A;
|
||||
DEBUG(dbgs() << "Remote address lookup " << Name << " = "
|
||||
<< format("0x%016x", Addr) << "\n");
|
||||
return std::error_code();
|
||||
});
|
||||
}
|
||||
|
||||
/// Get the triple for the remote target.
|
||||
const std::string &getTargetTriple() const { return RemoteTargetTriple; }
|
||||
|
||||
std::error_code terminateSession() { return call<TerminateSession>(Channel); }
|
||||
|
||||
private:
|
||||
OrcRemoteTargetClient(ChannelT &Channel, std::error_code &EC)
|
||||
: Channel(Channel), RemotePointerSize(0), RemotePageSize(0),
|
||||
RemoteTrampolineSize(0), RemoteIndirectStubSize(0) {
|
||||
if ((EC = call<GetRemoteInfo>(Channel)))
|
||||
return;
|
||||
|
||||
EC = expect<GetRemoteInfoResponse>(
|
||||
Channel, readArgs(RemoteTargetTriple, RemotePointerSize, RemotePageSize,
|
||||
RemoteTrampolineSize, RemoteIndirectStubSize));
|
||||
}
|
||||
|
||||
void destroyRemoteAllocator(ResourceIdMgr::ResourceId Id) {
|
||||
if (auto EC = call<DestroyRemoteAllocator>(Channel, Id)) {
|
||||
// FIXME: This will be triggered by a removeModuleSet call: Propagate
|
||||
// error return up through that.
|
||||
llvm_unreachable("Failed to destroy remote allocator.");
|
||||
AllocatorIds.release(Id);
|
||||
}
|
||||
}
|
||||
|
||||
std::error_code destroyIndirectStubsManager(ResourceIdMgr::ResourceId Id) {
|
||||
IndirectStubOwnerIds.release(Id);
|
||||
return call<DestroyIndirectStubsOwner>(Channel, Id);
|
||||
}
|
||||
|
||||
std::error_code emitIndirectStubs(TargetAddress &StubBase,
|
||||
TargetAddress &PtrBase,
|
||||
uint32_t &NumStubsEmitted,
|
||||
ResourceIdMgr::ResourceId Id,
|
||||
uint32_t NumStubsRequired) {
|
||||
if (auto EC = call<EmitIndirectStubs>(Channel, Id, NumStubsRequired))
|
||||
return EC;
|
||||
|
||||
return expect<EmitIndirectStubsResponse>(
|
||||
Channel, readArgs(StubBase, PtrBase, NumStubsEmitted));
|
||||
}
|
||||
|
||||
std::error_code emitResolverBlock() {
|
||||
// Check for an 'out-of-band' error, e.g. from an MM destructor.
|
||||
if (ExistingError)
|
||||
return ExistingError;
|
||||
|
||||
return call<EmitResolverBlock>(Channel);
|
||||
}
|
||||
|
||||
std::error_code emitTrampolineBlock(TargetAddress &BlockAddr,
|
||||
uint32_t &NumTrampolines) {
|
||||
// Check for an 'out-of-band' error, e.g. from an MM destructor.
|
||||
if (ExistingError)
|
||||
return ExistingError;
|
||||
|
||||
if (auto EC = call<EmitTrampolineBlock>(Channel))
|
||||
return EC;
|
||||
|
||||
return expect<EmitTrampolineBlockResponse>(
|
||||
Channel, [&](TargetAddress BAddr, uint32_t NTrampolines) {
|
||||
BlockAddr = BAddr;
|
||||
NumTrampolines = NTrampolines;
|
||||
return std::error_code();
|
||||
});
|
||||
}
|
||||
|
||||
uint32_t getIndirectStubSize() const { return RemoteIndirectStubSize; }
|
||||
uint32_t getPageSize() const { return RemotePageSize; }
|
||||
uint32_t getPointerSize() const { return RemotePointerSize; }
|
||||
|
||||
uint32_t getTrampolineSize() const { return RemoteTrampolineSize; }
|
||||
|
||||
std::error_code listenForCompileRequests(uint32_t &NextId) {
|
||||
// Check for an 'out-of-band' error, e.g. from an MM destructor.
|
||||
if (ExistingError)
|
||||
return ExistingError;
|
||||
|
||||
if (auto EC = getNextProcId(Channel, NextId))
|
||||
return EC;
|
||||
|
||||
while (NextId == RequestCompileId) {
|
||||
TargetAddress TrampolineAddr = 0;
|
||||
if (auto EC = handle<RequestCompile>(Channel, readArgs(TrampolineAddr)))
|
||||
return EC;
|
||||
|
||||
TargetAddress ImplAddr = CompileCallback(TrampolineAddr);
|
||||
if (auto EC = call<RequestCompileResponse>(Channel, ImplAddr))
|
||||
return EC;
|
||||
|
||||
if (auto EC = getNextProcId(Channel, NextId))
|
||||
return EC;
|
||||
}
|
||||
|
||||
return std::error_code();
|
||||
}
|
||||
|
||||
std::error_code readMem(char *Dst, TargetAddress Src, uint64_t Size) {
|
||||
// Check for an 'out-of-band' error, e.g. from an MM destructor.
|
||||
if (ExistingError)
|
||||
return ExistingError;
|
||||
|
||||
if (auto EC = call<ReadMem>(Channel, Src, Size))
|
||||
return EC;
|
||||
|
||||
if (auto EC = expect<ReadMemResponse>(
|
||||
Channel, [&]() { return Channel.readBytes(Dst, Size); }))
|
||||
return EC;
|
||||
|
||||
return std::error_code();
|
||||
}
|
||||
|
||||
std::error_code reserveMem(TargetAddress &RemoteAddr,
|
||||
ResourceIdMgr::ResourceId Id, uint64_t Size,
|
||||
uint32_t Align) {
|
||||
|
||||
// Check for an 'out-of-band' error, e.g. from an MM destructor.
|
||||
if (ExistingError)
|
||||
return ExistingError;
|
||||
|
||||
if (std::error_code EC = call<ReserveMem>(Channel, Id, Size, Align))
|
||||
return EC;
|
||||
|
||||
return expect<ReserveMemResponse>(Channel, readArgs(RemoteAddr));
|
||||
}
|
||||
|
||||
std::error_code setProtections(ResourceIdMgr::ResourceId Id,
|
||||
TargetAddress RemoteSegAddr,
|
||||
unsigned ProtFlags) {
|
||||
return call<SetProtections>(Channel, Id, RemoteSegAddr, ProtFlags);
|
||||
}
|
||||
|
||||
std::error_code writeMem(TargetAddress Addr, const char *Src, uint64_t Size) {
|
||||
// Check for an 'out-of-band' error, e.g. from an MM destructor.
|
||||
if (ExistingError)
|
||||
return ExistingError;
|
||||
|
||||
// Make the send call.
|
||||
if (auto EC = call<WriteMem>(Channel, Addr, Size))
|
||||
return EC;
|
||||
|
||||
// Follow this up with the section contents.
|
||||
if (auto EC = Channel.appendBytes(Src, Size))
|
||||
return EC;
|
||||
|
||||
return Channel.send();
|
||||
}
|
||||
|
||||
std::error_code writePointer(TargetAddress Addr, TargetAddress PtrVal) {
|
||||
// Check for an 'out-of-band' error, e.g. from an MM destructor.
|
||||
if (ExistingError)
|
||||
return ExistingError;
|
||||
|
||||
return call<WritePtr>(Channel, Addr, PtrVal);
|
||||
}
|
||||
|
||||
static std::error_code doNothing() { return std::error_code(); }
|
||||
|
||||
ChannelT &Channel;
|
||||
std::error_code ExistingError;
|
||||
std::string RemoteTargetTriple;
|
||||
uint32_t RemotePointerSize;
|
||||
uint32_t RemotePageSize;
|
||||
uint32_t RemoteTrampolineSize;
|
||||
uint32_t RemoteIndirectStubSize;
|
||||
ResourceIdMgr AllocatorIds, IndirectStubOwnerIds;
|
||||
std::function<TargetAddress(TargetAddress)> CompileCallback;
|
||||
};
|
||||
|
||||
} // end namespace remote
|
||||
} // end namespace orc
|
||||
} // end namespace llvm
|
||||
|
||||
#undef DEBUG_TYPE
|
||||
|
||||
#endif
|
@ -0,0 +1,185 @@
|
||||
//===--- OrcRemoteTargetRPCAPI.h - Orc Remote-target RPC API ----*- 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 Orc remote-target RPC API. It should not be used
|
||||
// directly, but is used by the RemoteTargetClient and RemoteTargetServer
|
||||
// classes.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_EXECUTIONENGINE_ORC_ORCREMOTETARGETRPCAPI_H
|
||||
#define LLVM_EXECUTIONENGINE_ORC_ORCREMOTETARGETRPCAPI_H
|
||||
|
||||
#include "JITSymbol.h"
|
||||
#include "RPCChannel.h"
|
||||
#include "RPCUtils.h"
|
||||
|
||||
namespace llvm {
|
||||
namespace orc {
|
||||
namespace remote {
|
||||
|
||||
class OrcRemoteTargetRPCAPI : public RPC<RPCChannel> {
|
||||
protected:
|
||||
class ResourceIdMgr {
|
||||
public:
|
||||
typedef uint64_t ResourceId;
|
||||
ResourceIdMgr() : NextId(0) {}
|
||||
ResourceId getNext() {
|
||||
if (!FreeIds.empty()) {
|
||||
ResourceId I = FreeIds.back();
|
||||
FreeIds.pop_back();
|
||||
return I;
|
||||
}
|
||||
return NextId++;
|
||||
}
|
||||
void release(ResourceId I) { FreeIds.push_back(I); }
|
||||
|
||||
private:
|
||||
ResourceId NextId;
|
||||
std::vector<ResourceId> FreeIds;
|
||||
};
|
||||
|
||||
public:
|
||||
enum JITProcId : uint32_t {
|
||||
InvalidId = 0,
|
||||
CallIntVoidId,
|
||||
CallIntVoidResponseId,
|
||||
CallMainId,
|
||||
CallMainResponseId,
|
||||
CallVoidVoidId,
|
||||
CallVoidVoidResponseId,
|
||||
CreateRemoteAllocatorId,
|
||||
CreateIndirectStubsOwnerId,
|
||||
DestroyRemoteAllocatorId,
|
||||
DestroyIndirectStubsOwnerId,
|
||||
EmitIndirectStubsId,
|
||||
EmitIndirectStubsResponseId,
|
||||
EmitResolverBlockId,
|
||||
EmitTrampolineBlockId,
|
||||
EmitTrampolineBlockResponseId,
|
||||
GetSymbolAddressId,
|
||||
GetSymbolAddressResponseId,
|
||||
GetRemoteInfoId,
|
||||
GetRemoteInfoResponseId,
|
||||
ReadMemId,
|
||||
ReadMemResponseId,
|
||||
ReserveMemId,
|
||||
ReserveMemResponseId,
|
||||
RequestCompileId,
|
||||
RequestCompileResponseId,
|
||||
SetProtectionsId,
|
||||
TerminateSessionId,
|
||||
WriteMemId,
|
||||
WritePtrId
|
||||
};
|
||||
|
||||
static const char *getJITProcIdName(JITProcId Id);
|
||||
|
||||
typedef Procedure<CallIntVoidId, TargetAddress /* FnAddr */> CallIntVoid;
|
||||
|
||||
typedef Procedure<CallIntVoidResponseId, int /* Result */>
|
||||
CallIntVoidResponse;
|
||||
|
||||
typedef Procedure<CallMainId, TargetAddress /* FnAddr */,
|
||||
std::vector<std::string> /* Args */>
|
||||
CallMain;
|
||||
|
||||
typedef Procedure<CallMainResponseId, int /* Result */> CallMainResponse;
|
||||
|
||||
typedef Procedure<CallVoidVoidId, TargetAddress /* FnAddr */> CallVoidVoid;
|
||||
|
||||
typedef Procedure<CallVoidVoidResponseId> CallVoidVoidResponse;
|
||||
|
||||
typedef Procedure<CreateRemoteAllocatorId,
|
||||
ResourceIdMgr::ResourceId /* Allocator ID */>
|
||||
CreateRemoteAllocator;
|
||||
|
||||
typedef Procedure<CreateIndirectStubsOwnerId,
|
||||
ResourceIdMgr::ResourceId /* StubsOwner ID */>
|
||||
CreateIndirectStubsOwner;
|
||||
|
||||
typedef Procedure<DestroyRemoteAllocatorId,
|
||||
ResourceIdMgr::ResourceId /* Allocator ID */>
|
||||
DestroyRemoteAllocator;
|
||||
|
||||
typedef Procedure<DestroyIndirectStubsOwnerId,
|
||||
ResourceIdMgr::ResourceId /* StubsOwner ID */>
|
||||
DestroyIndirectStubsOwner;
|
||||
|
||||
typedef Procedure<EmitIndirectStubsId,
|
||||
ResourceIdMgr::ResourceId /* StubsOwner ID */,
|
||||
uint32_t /* NumStubsRequired */>
|
||||
EmitIndirectStubs;
|
||||
|
||||
typedef Procedure<
|
||||
EmitIndirectStubsResponseId, TargetAddress /* StubsBaseAddr */,
|
||||
TargetAddress /* PtrsBaseAddr */, uint32_t /* NumStubsEmitted */>
|
||||
EmitIndirectStubsResponse;
|
||||
|
||||
typedef Procedure<EmitResolverBlockId> EmitResolverBlock;
|
||||
|
||||
typedef Procedure<EmitTrampolineBlockId> EmitTrampolineBlock;
|
||||
|
||||
typedef Procedure<EmitTrampolineBlockResponseId,
|
||||
TargetAddress /* BlockAddr */,
|
||||
uint32_t /* NumTrampolines */>
|
||||
EmitTrampolineBlockResponse;
|
||||
|
||||
typedef Procedure<GetSymbolAddressId, std::string /*SymbolName*/>
|
||||
GetSymbolAddress;
|
||||
|
||||
typedef Procedure<GetSymbolAddressResponseId, uint64_t /* SymbolAddr */>
|
||||
GetSymbolAddressResponse;
|
||||
|
||||
typedef Procedure<GetRemoteInfoId> GetRemoteInfo;
|
||||
|
||||
typedef Procedure<GetRemoteInfoResponseId, std::string /* Triple */,
|
||||
uint32_t /* PointerSize */, uint32_t /* PageSize */,
|
||||
uint32_t /* TrampolineSize */,
|
||||
uint32_t /* IndirectStubSize */>
|
||||
GetRemoteInfoResponse;
|
||||
|
||||
typedef Procedure<ReadMemId, TargetAddress /* Src */, uint64_t /* Size */>
|
||||
ReadMem;
|
||||
|
||||
typedef Procedure<ReadMemResponseId> ReadMemResponse;
|
||||
|
||||
typedef Procedure<ReserveMemId, ResourceIdMgr::ResourceId /* Id */,
|
||||
uint64_t /* Size */, uint32_t /* Align */>
|
||||
ReserveMem;
|
||||
|
||||
typedef Procedure<ReserveMemResponseId, TargetAddress /* Addr */>
|
||||
ReserveMemResponse;
|
||||
|
||||
typedef Procedure<RequestCompileId, TargetAddress /* TrampolineAddr */>
|
||||
RequestCompile;
|
||||
|
||||
typedef Procedure<RequestCompileResponseId, TargetAddress /* ImplAddr */>
|
||||
RequestCompileResponse;
|
||||
|
||||
typedef Procedure<SetProtectionsId, ResourceIdMgr::ResourceId /* Id */,
|
||||
TargetAddress /* Dst */, uint32_t /* ProtFlags */>
|
||||
SetProtections;
|
||||
|
||||
typedef Procedure<TerminateSessionId> TerminateSession;
|
||||
|
||||
typedef Procedure<WriteMemId, TargetAddress /* Dst */, uint64_t /* Size */
|
||||
/* Data should follow */>
|
||||
WriteMem;
|
||||
|
||||
typedef Procedure<WritePtrId, TargetAddress /* Dst */,
|
||||
TargetAddress /* Val */>
|
||||
WritePtr;
|
||||
};
|
||||
|
||||
} // end namespace remote
|
||||
} // end namespace orc
|
||||
} // end namespace llvm
|
||||
|
||||
#endif
|
@ -0,0 +1,432 @@
|
||||
//===---- OrcRemoteTargetServer.h - Orc Remote-target Server ----*- 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 OrcRemoteTargetServer class. It can be used to build a
|
||||
// JIT server that can execute code sent from an OrcRemoteTargetClient.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_EXECUTIONENGINE_ORC_ORCREMOTETARGETSERVER_H
|
||||
#define LLVM_EXECUTIONENGINE_ORC_ORCREMOTETARGETSERVER_H
|
||||
|
||||
#include "OrcRemoteTargetRPCAPI.h"
|
||||
#include "llvm/ExecutionEngine/RTDyldMemoryManager.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/Format.h"
|
||||
#include "llvm/Support/Process.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include <map>
|
||||
|
||||
#define DEBUG_TYPE "orc-remote"
|
||||
|
||||
namespace llvm {
|
||||
namespace orc {
|
||||
namespace remote {
|
||||
|
||||
template <typename ChannelT, typename TargetT>
|
||||
class OrcRemoteTargetServer : public OrcRemoteTargetRPCAPI {
|
||||
public:
|
||||
typedef std::function<TargetAddress(const std::string &Name)>
|
||||
SymbolLookupFtor;
|
||||
|
||||
OrcRemoteTargetServer(ChannelT &Channel, SymbolLookupFtor SymbolLookup)
|
||||
: Channel(Channel), SymbolLookup(std::move(SymbolLookup)) {}
|
||||
|
||||
std::error_code getNextProcId(JITProcId &Id) {
|
||||
return deserialize(Channel, Id);
|
||||
}
|
||||
|
||||
std::error_code handleKnownProcedure(JITProcId Id) {
|
||||
typedef OrcRemoteTargetServer ThisT;
|
||||
|
||||
DEBUG(dbgs() << "Handling known proc: " << getJITProcIdName(Id) << "\n");
|
||||
|
||||
switch (Id) {
|
||||
case CallIntVoidId:
|
||||
return handle<CallIntVoid>(Channel, *this, &ThisT::handleCallIntVoid);
|
||||
case CallMainId:
|
||||
return handle<CallMain>(Channel, *this, &ThisT::handleCallMain);
|
||||
case CallVoidVoidId:
|
||||
return handle<CallVoidVoid>(Channel, *this, &ThisT::handleCallVoidVoid);
|
||||
case CreateRemoteAllocatorId:
|
||||
return handle<CreateRemoteAllocator>(Channel, *this,
|
||||
&ThisT::handleCreateRemoteAllocator);
|
||||
case CreateIndirectStubsOwnerId:
|
||||
return handle<CreateIndirectStubsOwner>(
|
||||
Channel, *this, &ThisT::handleCreateIndirectStubsOwner);
|
||||
case DestroyRemoteAllocatorId:
|
||||
return handle<DestroyRemoteAllocator>(
|
||||
Channel, *this, &ThisT::handleDestroyRemoteAllocator);
|
||||
case DestroyIndirectStubsOwnerId:
|
||||
return handle<DestroyIndirectStubsOwner>(
|
||||
Channel, *this, &ThisT::handleDestroyIndirectStubsOwner);
|
||||
case EmitIndirectStubsId:
|
||||
return handle<EmitIndirectStubs>(Channel, *this,
|
||||
&ThisT::handleEmitIndirectStubs);
|
||||
case EmitResolverBlockId:
|
||||
return handle<EmitResolverBlock>(Channel, *this,
|
||||
&ThisT::handleEmitResolverBlock);
|
||||
case EmitTrampolineBlockId:
|
||||
return handle<EmitTrampolineBlock>(Channel, *this,
|
||||
&ThisT::handleEmitTrampolineBlock);
|
||||
case GetSymbolAddressId:
|
||||
return handle<GetSymbolAddress>(Channel, *this,
|
||||
&ThisT::handleGetSymbolAddress);
|
||||
case GetRemoteInfoId:
|
||||
return handle<GetRemoteInfo>(Channel, *this, &ThisT::handleGetRemoteInfo);
|
||||
case ReadMemId:
|
||||
return handle<ReadMem>(Channel, *this, &ThisT::handleReadMem);
|
||||
case ReserveMemId:
|
||||
return handle<ReserveMem>(Channel, *this, &ThisT::handleReserveMem);
|
||||
case SetProtectionsId:
|
||||
return handle<SetProtections>(Channel, *this,
|
||||
&ThisT::handleSetProtections);
|
||||
case WriteMemId:
|
||||
return handle<WriteMem>(Channel, *this, &ThisT::handleWriteMem);
|
||||
case WritePtrId:
|
||||
return handle<WritePtr>(Channel, *this, &ThisT::handleWritePtr);
|
||||
default:
|
||||
return orcError(OrcErrorCode::UnexpectedRPCCall);
|
||||
}
|
||||
|
||||
llvm_unreachable("Unhandled JIT RPC procedure Id.");
|
||||
}
|
||||
|
||||
std::error_code requestCompile(TargetAddress &CompiledFnAddr,
|
||||
TargetAddress TrampolineAddr) {
|
||||
if (auto EC = call<RequestCompile>(Channel, TrampolineAddr))
|
||||
return EC;
|
||||
|
||||
while (1) {
|
||||
JITProcId Id = InvalidId;
|
||||
if (auto EC = getNextProcId(Id))
|
||||
return EC;
|
||||
|
||||
switch (Id) {
|
||||
case RequestCompileResponseId:
|
||||
return handle<RequestCompileResponse>(Channel,
|
||||
readArgs(CompiledFnAddr));
|
||||
default:
|
||||
if (auto EC = handleKnownProcedure(Id))
|
||||
return EC;
|
||||
}
|
||||
}
|
||||
|
||||
llvm_unreachable("Fell through request-compile command loop.");
|
||||
}
|
||||
|
||||
private:
|
||||
struct Allocator {
|
||||
Allocator() = default;
|
||||
Allocator(Allocator &&Other) : Allocs(std::move(Other.Allocs)) {}
|
||||
Allocator &operator=(Allocator &&Other) {
|
||||
Allocs = std::move(Other.Allocs);
|
||||
return *this;
|
||||
}
|
||||
|
||||
~Allocator() {
|
||||
for (auto &Alloc : Allocs)
|
||||
sys::Memory::releaseMappedMemory(Alloc.second);
|
||||
}
|
||||
|
||||
std::error_code allocate(void *&Addr, size_t Size, uint32_t Align) {
|
||||
std::error_code EC;
|
||||
sys::MemoryBlock MB = sys::Memory::allocateMappedMemory(
|
||||
Size, nullptr, sys::Memory::MF_READ | sys::Memory::MF_WRITE, EC);
|
||||
if (EC)
|
||||
return EC;
|
||||
|
||||
Addr = MB.base();
|
||||
assert(Allocs.find(MB.base()) == Allocs.end() && "Duplicate alloc");
|
||||
Allocs[MB.base()] = std::move(MB);
|
||||
return std::error_code();
|
||||
}
|
||||
|
||||
std::error_code setProtections(void *block, unsigned Flags) {
|
||||
auto I = Allocs.find(block);
|
||||
if (I == Allocs.end())
|
||||
return orcError(OrcErrorCode::RemoteMProtectAddrUnrecognized);
|
||||
return sys::Memory::protectMappedMemory(I->second, Flags);
|
||||
}
|
||||
|
||||
private:
|
||||
std::map<void *, sys::MemoryBlock> Allocs;
|
||||
};
|
||||
|
||||
static std::error_code doNothing() { return std::error_code(); }
|
||||
|
||||
static TargetAddress reenter(void *JITTargetAddr, void *TrampolineAddr) {
|
||||
TargetAddress CompiledFnAddr = 0;
|
||||
|
||||
auto T = static_cast<OrcRemoteTargetServer *>(JITTargetAddr);
|
||||
auto EC = T->requestCompile(
|
||||
CompiledFnAddr, static_cast<TargetAddress>(
|
||||
reinterpret_cast<uintptr_t>(TrampolineAddr)));
|
||||
assert(!EC && "Compile request failed");
|
||||
(void)EC;
|
||||
return CompiledFnAddr;
|
||||
}
|
||||
|
||||
std::error_code handleCallIntVoid(TargetAddress Addr) {
|
||||
typedef int (*IntVoidFnTy)();
|
||||
IntVoidFnTy Fn =
|
||||
reinterpret_cast<IntVoidFnTy>(static_cast<uintptr_t>(Addr));
|
||||
|
||||
DEBUG(dbgs() << " Calling "
|
||||
<< reinterpret_cast<void *>(reinterpret_cast<intptr_t>(Fn))
|
||||
<< "\n");
|
||||
int Result = Fn();
|
||||
DEBUG(dbgs() << " Result = " << Result << "\n");
|
||||
|
||||
return call<CallIntVoidResponse>(Channel, Result);
|
||||
}
|
||||
|
||||
std::error_code handleCallMain(TargetAddress Addr,
|
||||
std::vector<std::string> Args) {
|
||||
typedef int (*MainFnTy)(int, const char *[]);
|
||||
|
||||
MainFnTy Fn = reinterpret_cast<MainFnTy>(static_cast<uintptr_t>(Addr));
|
||||
int ArgC = Args.size() + 1;
|
||||
int Idx = 1;
|
||||
std::unique_ptr<const char *[]> ArgV(new const char *[ArgC + 1]);
|
||||
ArgV[0] = "<jit process>";
|
||||
for (auto &Arg : Args)
|
||||
ArgV[Idx++] = Arg.c_str();
|
||||
|
||||
DEBUG(dbgs() << " Calling " << reinterpret_cast<void *>(Fn) << "\n");
|
||||
int Result = Fn(ArgC, ArgV.get());
|
||||
DEBUG(dbgs() << " Result = " << Result << "\n");
|
||||
|
||||
return call<CallMainResponse>(Channel, Result);
|
||||
}
|
||||
|
||||
std::error_code handleCallVoidVoid(TargetAddress Addr) {
|
||||
typedef void (*VoidVoidFnTy)();
|
||||
VoidVoidFnTy Fn =
|
||||
reinterpret_cast<VoidVoidFnTy>(static_cast<uintptr_t>(Addr));
|
||||
|
||||
DEBUG(dbgs() << " Calling " << reinterpret_cast<void *>(Fn) << "\n");
|
||||
Fn();
|
||||
DEBUG(dbgs() << " Complete.\n");
|
||||
|
||||
return call<CallVoidVoidResponse>(Channel);
|
||||
}
|
||||
|
||||
std::error_code handleCreateRemoteAllocator(ResourceIdMgr::ResourceId Id) {
|
||||
auto I = Allocators.find(Id);
|
||||
if (I != Allocators.end())
|
||||
return orcError(OrcErrorCode::RemoteAllocatorIdAlreadyInUse);
|
||||
DEBUG(dbgs() << " Created allocator " << Id << "\n");
|
||||
Allocators[Id] = Allocator();
|
||||
return std::error_code();
|
||||
}
|
||||
|
||||
std::error_code handleCreateIndirectStubsOwner(ResourceIdMgr::ResourceId Id) {
|
||||
auto I = IndirectStubsOwners.find(Id);
|
||||
if (I != IndirectStubsOwners.end())
|
||||
return orcError(OrcErrorCode::RemoteIndirectStubsOwnerIdAlreadyInUse);
|
||||
DEBUG(dbgs() << " Create indirect stubs owner " << Id << "\n");
|
||||
IndirectStubsOwners[Id] = ISBlockOwnerList();
|
||||
return std::error_code();
|
||||
}
|
||||
|
||||
std::error_code handleDestroyRemoteAllocator(ResourceIdMgr::ResourceId Id) {
|
||||
auto I = Allocators.find(Id);
|
||||
if (I == Allocators.end())
|
||||
return orcError(OrcErrorCode::RemoteAllocatorDoesNotExist);
|
||||
Allocators.erase(I);
|
||||
DEBUG(dbgs() << " Destroyed allocator " << Id << "\n");
|
||||
return std::error_code();
|
||||
}
|
||||
|
||||
std::error_code
|
||||
handleDestroyIndirectStubsOwner(ResourceIdMgr::ResourceId Id) {
|
||||
auto I = IndirectStubsOwners.find(Id);
|
||||
if (I == IndirectStubsOwners.end())
|
||||
return orcError(OrcErrorCode::RemoteIndirectStubsOwnerDoesNotExist);
|
||||
IndirectStubsOwners.erase(I);
|
||||
return std::error_code();
|
||||
}
|
||||
|
||||
std::error_code handleEmitIndirectStubs(ResourceIdMgr::ResourceId Id,
|
||||
uint32_t NumStubsRequired) {
|
||||
DEBUG(dbgs() << " ISMgr " << Id << " request " << NumStubsRequired
|
||||
<< " stubs.\n");
|
||||
|
||||
auto StubOwnerItr = IndirectStubsOwners.find(Id);
|
||||
if (StubOwnerItr == IndirectStubsOwners.end())
|
||||
return orcError(OrcErrorCode::RemoteIndirectStubsOwnerDoesNotExist);
|
||||
|
||||
typename TargetT::IndirectStubsInfo IS;
|
||||
if (auto EC =
|
||||
TargetT::emitIndirectStubsBlock(IS, NumStubsRequired, nullptr))
|
||||
return EC;
|
||||
|
||||
TargetAddress StubsBase =
|
||||
static_cast<TargetAddress>(reinterpret_cast<uintptr_t>(IS.getStub(0)));
|
||||
TargetAddress PtrsBase =
|
||||
static_cast<TargetAddress>(reinterpret_cast<uintptr_t>(IS.getPtr(0)));
|
||||
uint32_t NumStubsEmitted = IS.getNumStubs();
|
||||
|
||||
auto &BlockList = StubOwnerItr->second;
|
||||
BlockList.push_back(std::move(IS));
|
||||
|
||||
return call<EmitIndirectStubsResponse>(Channel, StubsBase, PtrsBase,
|
||||
NumStubsEmitted);
|
||||
}
|
||||
|
||||
std::error_code handleEmitResolverBlock() {
|
||||
std::error_code EC;
|
||||
ResolverBlock = sys::OwningMemoryBlock(sys::Memory::allocateMappedMemory(
|
||||
TargetT::ResolverCodeSize, nullptr,
|
||||
sys::Memory::MF_READ | sys::Memory::MF_WRITE, EC));
|
||||
if (EC)
|
||||
return EC;
|
||||
|
||||
TargetT::writeResolverCode(static_cast<uint8_t *>(ResolverBlock.base()),
|
||||
&reenter, this);
|
||||
|
||||
return sys::Memory::protectMappedMemory(ResolverBlock.getMemoryBlock(),
|
||||
sys::Memory::MF_READ |
|
||||
sys::Memory::MF_EXEC);
|
||||
}
|
||||
|
||||
std::error_code handleEmitTrampolineBlock() {
|
||||
std::error_code EC;
|
||||
auto TrampolineBlock =
|
||||
sys::OwningMemoryBlock(sys::Memory::allocateMappedMemory(
|
||||
sys::Process::getPageSize(), nullptr,
|
||||
sys::Memory::MF_READ | sys::Memory::MF_WRITE, EC));
|
||||
if (EC)
|
||||
return EC;
|
||||
|
||||
unsigned NumTrampolines =
|
||||
(sys::Process::getPageSize() - TargetT::PointerSize) /
|
||||
TargetT::TrampolineSize;
|
||||
|
||||
uint8_t *TrampolineMem = static_cast<uint8_t *>(TrampolineBlock.base());
|
||||
TargetT::writeTrampolines(TrampolineMem, ResolverBlock.base(),
|
||||
NumTrampolines);
|
||||
|
||||
EC = sys::Memory::protectMappedMemory(TrampolineBlock.getMemoryBlock(),
|
||||
sys::Memory::MF_READ |
|
||||
sys::Memory::MF_EXEC);
|
||||
|
||||
TrampolineBlocks.push_back(std::move(TrampolineBlock));
|
||||
|
||||
return call<EmitTrampolineBlockResponse>(
|
||||
Channel,
|
||||
static_cast<TargetAddress>(reinterpret_cast<uintptr_t>(TrampolineMem)),
|
||||
NumTrampolines);
|
||||
}
|
||||
|
||||
std::error_code handleGetSymbolAddress(const std::string &Name) {
|
||||
TargetAddress Addr = SymbolLookup(Name);
|
||||
DEBUG(dbgs() << " Symbol '" << Name << "' = " << format("0x%016x", Addr)
|
||||
<< "\n");
|
||||
return call<GetSymbolAddressResponse>(Channel, Addr);
|
||||
}
|
||||
|
||||
std::error_code handleGetRemoteInfo() {
|
||||
std::string ProcessTriple = sys::getProcessTriple();
|
||||
uint32_t PointerSize = TargetT::PointerSize;
|
||||
uint32_t PageSize = sys::Process::getPageSize();
|
||||
uint32_t TrampolineSize = TargetT::TrampolineSize;
|
||||
uint32_t IndirectStubSize = TargetT::IndirectStubsInfo::StubSize;
|
||||
DEBUG(dbgs() << " Remote info:\n"
|
||||
<< " triple = '" << ProcessTriple << "'\n"
|
||||
<< " pointer size = " << PointerSize << "\n"
|
||||
<< " page size = " << PageSize << "\n"
|
||||
<< " trampoline size = " << TrampolineSize << "\n"
|
||||
<< " indirect stub size = " << IndirectStubSize << "\n");
|
||||
return call<GetRemoteInfoResponse>(Channel, ProcessTriple, PointerSize,
|
||||
PageSize, TrampolineSize,
|
||||
IndirectStubSize);
|
||||
}
|
||||
|
||||
std::error_code handleReadMem(TargetAddress RSrc, uint64_t Size) {
|
||||
char *Src = reinterpret_cast<char *>(static_cast<uintptr_t>(RSrc));
|
||||
|
||||
DEBUG(dbgs() << " Reading " << Size << " bytes from "
|
||||
<< static_cast<void *>(Src) << "\n");
|
||||
|
||||
if (auto EC = call<ReadMemResponse>(Channel))
|
||||
return EC;
|
||||
|
||||
if (auto EC = Channel.appendBytes(Src, Size))
|
||||
return EC;
|
||||
|
||||
return Channel.send();
|
||||
}
|
||||
|
||||
std::error_code handleReserveMem(ResourceIdMgr::ResourceId Id, uint64_t Size,
|
||||
uint32_t Align) {
|
||||
auto I = Allocators.find(Id);
|
||||
if (I == Allocators.end())
|
||||
return orcError(OrcErrorCode::RemoteAllocatorDoesNotExist);
|
||||
auto &Allocator = I->second;
|
||||
void *LocalAllocAddr = nullptr;
|
||||
if (auto EC = Allocator.allocate(LocalAllocAddr, Size, Align))
|
||||
return EC;
|
||||
|
||||
DEBUG(dbgs() << " Allocator " << Id << " reserved " << LocalAllocAddr
|
||||
<< " (" << Size << " bytes, alignment " << Align << ")\n");
|
||||
|
||||
TargetAddress AllocAddr =
|
||||
static_cast<TargetAddress>(reinterpret_cast<uintptr_t>(LocalAllocAddr));
|
||||
|
||||
return call<ReserveMemResponse>(Channel, AllocAddr);
|
||||
}
|
||||
|
||||
std::error_code handleSetProtections(ResourceIdMgr::ResourceId Id,
|
||||
TargetAddress Addr, uint32_t Flags) {
|
||||
auto I = Allocators.find(Id);
|
||||
if (I == Allocators.end())
|
||||
return orcError(OrcErrorCode::RemoteAllocatorDoesNotExist);
|
||||
auto &Allocator = I->second;
|
||||
void *LocalAddr = reinterpret_cast<void *>(static_cast<uintptr_t>(Addr));
|
||||
DEBUG(dbgs() << " Allocator " << Id << " set permissions on " << LocalAddr
|
||||
<< " to " << (Flags & sys::Memory::MF_READ ? 'R' : '-')
|
||||
<< (Flags & sys::Memory::MF_WRITE ? 'W' : '-')
|
||||
<< (Flags & sys::Memory::MF_EXEC ? 'X' : '-') << "\n");
|
||||
return Allocator.setProtections(LocalAddr, Flags);
|
||||
}
|
||||
|
||||
std::error_code handleWriteMem(TargetAddress RDst, uint64_t Size) {
|
||||
char *Dst = reinterpret_cast<char *>(static_cast<uintptr_t>(RDst));
|
||||
DEBUG(dbgs() << " Writing " << Size << " bytes to "
|
||||
<< format("0x%016x", RDst) << "\n");
|
||||
return Channel.readBytes(Dst, Size);
|
||||
}
|
||||
|
||||
std::error_code handleWritePtr(TargetAddress Addr, TargetAddress PtrVal) {
|
||||
DEBUG(dbgs() << " Writing pointer *" << format("0x%016x", Addr) << " = "
|
||||
<< format("0x%016x", PtrVal) << "\n");
|
||||
uintptr_t *Ptr =
|
||||
reinterpret_cast<uintptr_t *>(static_cast<uintptr_t>(Addr));
|
||||
*Ptr = static_cast<uintptr_t>(PtrVal);
|
||||
return std::error_code();
|
||||
}
|
||||
|
||||
ChannelT &Channel;
|
||||
SymbolLookupFtor SymbolLookup;
|
||||
std::map<ResourceIdMgr::ResourceId, Allocator> Allocators;
|
||||
typedef std::vector<typename TargetT::IndirectStubsInfo> ISBlockOwnerList;
|
||||
std::map<ResourceIdMgr::ResourceId, ISBlockOwnerList> IndirectStubsOwners;
|
||||
sys::OwningMemoryBlock ResolverBlock;
|
||||
std::vector<sys::OwningMemoryBlock> TrampolineBlocks;
|
||||
};
|
||||
|
||||
} // end namespace remote
|
||||
} // end namespace orc
|
||||
} // end namespace llvm
|
||||
|
||||
#undef DEBUG_TYPE
|
||||
|
||||
#endif
|
179
contrib/llvm/include/llvm/ExecutionEngine/Orc/RPCChannel.h
Normal file
179
contrib/llvm/include/llvm/ExecutionEngine/Orc/RPCChannel.h
Normal file
@ -0,0 +1,179 @@
|
||||
// -*- c++ -*-
|
||||
|
||||
#ifndef LLVM_EXECUTIONENGINE_ORC_RPCCHANNEL_H
|
||||
#define LLVM_EXECUTIONENGINE_ORC_RPCCHANNEL_H
|
||||
|
||||
#include "OrcError.h"
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/Support/Endian.h"
|
||||
|
||||
#include <system_error>
|
||||
|
||||
namespace llvm {
|
||||
namespace orc {
|
||||
namespace remote {
|
||||
|
||||
/// Interface for byte-streams to be used with RPC.
|
||||
class RPCChannel {
|
||||
public:
|
||||
virtual ~RPCChannel() {}
|
||||
|
||||
/// Read Size bytes from the stream into *Dst.
|
||||
virtual std::error_code readBytes(char *Dst, unsigned Size) = 0;
|
||||
|
||||
/// Read size bytes from *Src and append them to the stream.
|
||||
virtual std::error_code appendBytes(const char *Src, unsigned Size) = 0;
|
||||
|
||||
/// Flush the stream if possible.
|
||||
virtual std::error_code send() = 0;
|
||||
};
|
||||
|
||||
/// RPC channel serialization for a variadic list of arguments.
|
||||
template <typename T, typename... Ts>
|
||||
std::error_code serialize_seq(RPCChannel &C, const T &Arg, const Ts &... Args) {
|
||||
if (auto EC = serialize(C, Arg))
|
||||
return EC;
|
||||
return serialize_seq(C, Args...);
|
||||
}
|
||||
|
||||
/// RPC channel serialization for an (empty) variadic list of arguments.
|
||||
inline std::error_code serialize_seq(RPCChannel &C) {
|
||||
return std::error_code();
|
||||
}
|
||||
|
||||
/// RPC channel deserialization for a variadic list of arguments.
|
||||
template <typename T, typename... Ts>
|
||||
std::error_code deserialize_seq(RPCChannel &C, T &Arg, Ts &... Args) {
|
||||
if (auto EC = deserialize(C, Arg))
|
||||
return EC;
|
||||
return deserialize_seq(C, Args...);
|
||||
}
|
||||
|
||||
/// RPC channel serialization for an (empty) variadic list of arguments.
|
||||
inline std::error_code deserialize_seq(RPCChannel &C) {
|
||||
return std::error_code();
|
||||
}
|
||||
|
||||
/// RPC channel serialization for integer primitives.
|
||||
template <typename T>
|
||||
typename std::enable_if<
|
||||
std::is_same<T, uint64_t>::value || std::is_same<T, int64_t>::value ||
|
||||
std::is_same<T, uint32_t>::value || std::is_same<T, int32_t>::value ||
|
||||
std::is_same<T, uint16_t>::value || std::is_same<T, int16_t>::value ||
|
||||
std::is_same<T, uint8_t>::value || std::is_same<T, int8_t>::value,
|
||||
std::error_code>::type
|
||||
serialize(RPCChannel &C, T V) {
|
||||
support::endian::byte_swap<T, support::big>(V);
|
||||
return C.appendBytes(reinterpret_cast<const char *>(&V), sizeof(T));
|
||||
}
|
||||
|
||||
/// RPC channel deserialization for integer primitives.
|
||||
template <typename T>
|
||||
typename std::enable_if<
|
||||
std::is_same<T, uint64_t>::value || std::is_same<T, int64_t>::value ||
|
||||
std::is_same<T, uint32_t>::value || std::is_same<T, int32_t>::value ||
|
||||
std::is_same<T, uint16_t>::value || std::is_same<T, int16_t>::value ||
|
||||
std::is_same<T, uint8_t>::value || std::is_same<T, int8_t>::value,
|
||||
std::error_code>::type
|
||||
deserialize(RPCChannel &C, T &V) {
|
||||
if (auto EC = C.readBytes(reinterpret_cast<char *>(&V), sizeof(T)))
|
||||
return EC;
|
||||
support::endian::byte_swap<T, support::big>(V);
|
||||
return std::error_code();
|
||||
}
|
||||
|
||||
/// RPC channel serialization for enums.
|
||||
template <typename T>
|
||||
typename std::enable_if<std::is_enum<T>::value, std::error_code>::type
|
||||
serialize(RPCChannel &C, T V) {
|
||||
return serialize(C, static_cast<typename std::underlying_type<T>::type>(V));
|
||||
}
|
||||
|
||||
/// RPC channel deserialization for enums.
|
||||
template <typename T>
|
||||
typename std::enable_if<std::is_enum<T>::value, std::error_code>::type
|
||||
deserialize(RPCChannel &C, T &V) {
|
||||
typename std::underlying_type<T>::type Tmp;
|
||||
std::error_code EC = deserialize(C, Tmp);
|
||||
V = static_cast<T>(Tmp);
|
||||
return EC;
|
||||
}
|
||||
|
||||
/// RPC channel serialization for bools.
|
||||
inline std::error_code serialize(RPCChannel &C, bool V) {
|
||||
uint8_t VN = V ? 1 : 0;
|
||||
return C.appendBytes(reinterpret_cast<const char *>(&VN), 1);
|
||||
}
|
||||
|
||||
/// RPC channel deserialization for bools.
|
||||
inline std::error_code deserialize(RPCChannel &C, bool &V) {
|
||||
uint8_t VN = 0;
|
||||
if (auto EC = C.readBytes(reinterpret_cast<char *>(&VN), 1))
|
||||
return EC;
|
||||
|
||||
V = (VN != 0) ? true : false;
|
||||
return std::error_code();
|
||||
}
|
||||
|
||||
/// RPC channel serialization for StringRefs.
|
||||
/// Note: There is no corresponding deseralization for this, as StringRef
|
||||
/// doesn't own its memory and so can't hold the deserialized data.
|
||||
inline std::error_code serialize(RPCChannel &C, StringRef S) {
|
||||
if (auto EC = serialize(C, static_cast<uint64_t>(S.size())))
|
||||
return EC;
|
||||
return C.appendBytes((const char *)S.bytes_begin(), S.size());
|
||||
}
|
||||
|
||||
/// RPC channel serialization for std::strings.
|
||||
inline std::error_code serialize(RPCChannel &C, const std::string &S) {
|
||||
return serialize(C, StringRef(S));
|
||||
}
|
||||
|
||||
/// RPC channel deserialization for std::strings.
|
||||
inline std::error_code deserialize(RPCChannel &C, std::string &S) {
|
||||
uint64_t Count;
|
||||
if (auto EC = deserialize(C, Count))
|
||||
return EC;
|
||||
S.resize(Count);
|
||||
return C.readBytes(&S[0], Count);
|
||||
}
|
||||
|
||||
/// RPC channel serialization for ArrayRef<T>.
|
||||
template <typename T>
|
||||
std::error_code serialize(RPCChannel &C, const ArrayRef<T> &A) {
|
||||
if (auto EC = serialize(C, static_cast<uint64_t>(A.size())))
|
||||
return EC;
|
||||
|
||||
for (const auto &E : A)
|
||||
if (auto EC = serialize(C, E))
|
||||
return EC;
|
||||
|
||||
return std::error_code();
|
||||
}
|
||||
|
||||
/// RPC channel serialization for std::array<T>.
|
||||
template <typename T>
|
||||
std::error_code serialize(RPCChannel &C, const std::vector<T> &V) {
|
||||
return serialize(C, ArrayRef<T>(V));
|
||||
}
|
||||
|
||||
/// RPC channel deserialization for std::array<T>.
|
||||
template <typename T>
|
||||
std::error_code deserialize(RPCChannel &C, std::vector<T> &V) {
|
||||
uint64_t Count = 0;
|
||||
if (auto EC = deserialize(C, Count))
|
||||
return EC;
|
||||
|
||||
V.resize(Count);
|
||||
for (auto &E : V)
|
||||
if (auto EC = deserialize(C, E))
|
||||
return EC;
|
||||
|
||||
return std::error_code();
|
||||
}
|
||||
|
||||
} // end namespace remote
|
||||
} // end namespace orc
|
||||
} // end namespace llvm
|
||||
|
||||
#endif
|
266
contrib/llvm/include/llvm/ExecutionEngine/Orc/RPCUtils.h
Normal file
266
contrib/llvm/include/llvm/ExecutionEngine/Orc/RPCUtils.h
Normal file
@ -0,0 +1,266 @@
|
||||
//===----- RPCUTils.h - Basic tilities for building RPC APIs ----*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Basic utilities for building RPC APIs.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_EXECUTIONENGINE_ORC_RPCUTILS_H
|
||||
#define LLVM_EXECUTIONENGINE_ORC_RPCUTILS_H
|
||||
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
|
||||
namespace llvm {
|
||||
namespace orc {
|
||||
namespace remote {
|
||||
|
||||
// Base class containing utilities that require partial specialization.
|
||||
// These cannot be included in RPC, as template class members cannot be
|
||||
// partially specialized.
|
||||
class RPCBase {
|
||||
protected:
|
||||
template <typename ProcedureIdT, ProcedureIdT ProcId, typename... Ts>
|
||||
class ProcedureHelper {
|
||||
public:
|
||||
static const ProcedureIdT Id = ProcId;
|
||||
};
|
||||
|
||||
template <typename ChannelT, typename Proc> class CallHelper;
|
||||
|
||||
template <typename ChannelT, typename ProcedureIdT, ProcedureIdT ProcId,
|
||||
typename... ArgTs>
|
||||
class CallHelper<ChannelT, ProcedureHelper<ProcedureIdT, ProcId, ArgTs...>> {
|
||||
public:
|
||||
static std::error_code call(ChannelT &C, const ArgTs &... Args) {
|
||||
if (auto EC = serialize(C, ProcId))
|
||||
return EC;
|
||||
// If you see a compile-error on this line you're probably calling a
|
||||
// function with the wrong signature.
|
||||
return serialize_seq(C, Args...);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename ChannelT, typename Proc> class HandlerHelper;
|
||||
|
||||
template <typename ChannelT, typename ProcedureIdT, ProcedureIdT ProcId,
|
||||
typename... ArgTs>
|
||||
class HandlerHelper<ChannelT,
|
||||
ProcedureHelper<ProcedureIdT, ProcId, ArgTs...>> {
|
||||
public:
|
||||
template <typename HandlerT>
|
||||
static std::error_code handle(ChannelT &C, HandlerT Handler) {
|
||||
return readAndHandle(C, Handler, llvm::index_sequence_for<ArgTs...>());
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename HandlerT, size_t... Is>
|
||||
static std::error_code readAndHandle(ChannelT &C, HandlerT Handler,
|
||||
llvm::index_sequence<Is...> _) {
|
||||
std::tuple<ArgTs...> RPCArgs;
|
||||
if (auto EC = deserialize_seq(C, std::get<Is>(RPCArgs)...))
|
||||
return EC;
|
||||
return Handler(std::get<Is>(RPCArgs)...);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename ClassT, typename... ArgTs> class MemberFnWrapper {
|
||||
public:
|
||||
typedef std::error_code (ClassT::*MethodT)(ArgTs...);
|
||||
MemberFnWrapper(ClassT &Instance, MethodT Method)
|
||||
: Instance(Instance), Method(Method) {}
|
||||
std::error_code operator()(ArgTs &... Args) {
|
||||
return (Instance.*Method)(Args...);
|
||||
}
|
||||
|
||||
private:
|
||||
ClassT &Instance;
|
||||
MethodT Method;
|
||||
};
|
||||
|
||||
template <typename... ArgTs> class ReadArgs {
|
||||
public:
|
||||
std::error_code operator()() { return std::error_code(); }
|
||||
};
|
||||
|
||||
template <typename ArgT, typename... ArgTs>
|
||||
class ReadArgs<ArgT, ArgTs...> : public ReadArgs<ArgTs...> {
|
||||
public:
|
||||
ReadArgs(ArgT &Arg, ArgTs &... Args)
|
||||
: ReadArgs<ArgTs...>(Args...), Arg(Arg) {}
|
||||
|
||||
std::error_code operator()(ArgT &ArgVal, ArgTs &... ArgVals) {
|
||||
this->Arg = std::move(ArgVal);
|
||||
return ReadArgs<ArgTs...>::operator()(ArgVals...);
|
||||
}
|
||||
|
||||
private:
|
||||
ArgT &Arg;
|
||||
};
|
||||
};
|
||||
|
||||
/// Contains primitive utilities for defining, calling and handling calls to
|
||||
/// remote procedures. ChannelT is a bidirectional stream conforming to the
|
||||
/// RPCChannel interface (see RPCChannel.h), and ProcedureIdT is a procedure
|
||||
/// identifier type that must be serializable on ChannelT.
|
||||
///
|
||||
/// These utilities support the construction of very primitive RPC utilities.
|
||||
/// Their intent is to ensure correct serialization and deserialization of
|
||||
/// procedure arguments, and to keep the client and server's view of the API in
|
||||
/// sync.
|
||||
///
|
||||
/// These utilities do not support return values. These can be handled by
|
||||
/// declaring a corresponding '.*Response' procedure and expecting it after a
|
||||
/// call). They also do not support versioning: the client and server *must* be
|
||||
/// compiled with the same procedure definitions.
|
||||
///
|
||||
///
|
||||
///
|
||||
/// Overview (see comments individual types/methods for details):
|
||||
///
|
||||
/// Procedure<Id, Args...> :
|
||||
///
|
||||
/// associates a unique serializable id with an argument list.
|
||||
///
|
||||
///
|
||||
/// call<Proc>(Channel, Args...) :
|
||||
///
|
||||
/// Calls the remote procedure 'Proc' by serializing Proc's id followed by its
|
||||
/// arguments and sending the resulting bytes to 'Channel'.
|
||||
///
|
||||
///
|
||||
/// handle<Proc>(Channel, <functor matching std::error_code(Args...)> :
|
||||
///
|
||||
/// Handles a call to 'Proc' by deserializing its arguments and calling the
|
||||
/// given functor. This assumes that the id for 'Proc' has already been
|
||||
/// deserialized.
|
||||
///
|
||||
/// expect<Proc>(Channel, <functor matching std::error_code(Args...)> :
|
||||
///
|
||||
/// The same as 'handle', except that the procedure id should not have been
|
||||
/// read yet. Expect will deserialize the id and assert that it matches Proc's
|
||||
/// id. If it does not, and unexpected RPC call error is returned.
|
||||
|
||||
template <typename ChannelT, typename ProcedureIdT = uint32_t>
|
||||
class RPC : public RPCBase {
|
||||
public:
|
||||
/// Utility class for defining/referring to RPC procedures.
|
||||
///
|
||||
/// Typedefs of this utility are used when calling/handling remote procedures.
|
||||
///
|
||||
/// ProcId should be a unique value of ProcedureIdT (i.e. not used with any
|
||||
/// other Procedure typedef in the RPC API being defined.
|
||||
///
|
||||
/// the template argument Ts... gives the argument list for the remote
|
||||
/// procedure.
|
||||
///
|
||||
/// E.g.
|
||||
///
|
||||
/// typedef Procedure<0, bool> Proc1;
|
||||
/// typedef Procedure<1, std::string, std::vector<int>> Proc2;
|
||||
///
|
||||
/// if (auto EC = call<Proc1>(Channel, true))
|
||||
/// /* handle EC */;
|
||||
///
|
||||
/// if (auto EC = expect<Proc2>(Channel,
|
||||
/// [](std::string &S, std::vector<int> &V) {
|
||||
/// // Stuff.
|
||||
/// return std::error_code();
|
||||
/// })
|
||||
/// /* handle EC */;
|
||||
///
|
||||
template <ProcedureIdT ProcId, typename... Ts>
|
||||
using Procedure = ProcedureHelper<ProcedureIdT, ProcId, Ts...>;
|
||||
|
||||
/// Serialize Args... to channel C, but do not call C.send().
|
||||
///
|
||||
/// For buffered channels, this can be used to queue up several calls before
|
||||
/// flushing the channel.
|
||||
template <typename Proc, typename... ArgTs>
|
||||
static std::error_code appendCall(ChannelT &C, const ArgTs &... Args) {
|
||||
return CallHelper<ChannelT, Proc>::call(C, Args...);
|
||||
}
|
||||
|
||||
/// Serialize Args... to channel C and call C.send().
|
||||
template <typename Proc, typename... ArgTs>
|
||||
static std::error_code call(ChannelT &C, const ArgTs &... Args) {
|
||||
if (auto EC = appendCall<Proc>(C, Args...))
|
||||
return EC;
|
||||
return C.send();
|
||||
}
|
||||
|
||||
/// Deserialize and return an enum whose underlying type is ProcedureIdT.
|
||||
static std::error_code getNextProcId(ChannelT &C, ProcedureIdT &Id) {
|
||||
return deserialize(C, Id);
|
||||
}
|
||||
|
||||
/// Deserialize args for Proc from C and call Handler. The signature of
|
||||
/// handler must conform to 'std::error_code(Args...)' where Args... matches
|
||||
/// the arguments used in the Proc typedef.
|
||||
template <typename Proc, typename HandlerT>
|
||||
static std::error_code handle(ChannelT &C, HandlerT Handler) {
|
||||
return HandlerHelper<ChannelT, Proc>::handle(C, Handler);
|
||||
}
|
||||
|
||||
/// Helper version of 'handle' for calling member functions.
|
||||
template <typename Proc, typename ClassT, typename... ArgTs>
|
||||
static std::error_code
|
||||
handle(ChannelT &C, ClassT &Instance,
|
||||
std::error_code (ClassT::*HandlerMethod)(ArgTs...)) {
|
||||
return handle<Proc>(
|
||||
C, MemberFnWrapper<ClassT, ArgTs...>(Instance, HandlerMethod));
|
||||
}
|
||||
|
||||
/// Deserialize a ProcedureIdT from C and verify it matches the id for Proc.
|
||||
/// If the id does match, deserialize the arguments and call the handler
|
||||
/// (similarly to handle).
|
||||
/// If the id does not match, return an unexpect RPC call error and do not
|
||||
/// deserialize any further bytes.
|
||||
template <typename Proc, typename HandlerT>
|
||||
static std::error_code expect(ChannelT &C, HandlerT Handler) {
|
||||
ProcedureIdT ProcId;
|
||||
if (auto EC = getNextProcId(C, ProcId))
|
||||
return EC;
|
||||
if (ProcId != Proc::Id)
|
||||
return orcError(OrcErrorCode::UnexpectedRPCCall);
|
||||
return handle<Proc>(C, Handler);
|
||||
}
|
||||
|
||||
/// Helper version of expect for calling member functions.
|
||||
template <typename Proc, typename ClassT, typename... ArgTs>
|
||||
static std::error_code
|
||||
expect(ChannelT &C, ClassT &Instance,
|
||||
std::error_code (ClassT::*HandlerMethod)(ArgTs...)) {
|
||||
return expect<Proc>(
|
||||
C, MemberFnWrapper<ClassT, ArgTs...>(Instance, HandlerMethod));
|
||||
}
|
||||
|
||||
/// Helper for handling setter procedures - this method returns a functor that
|
||||
/// sets the variables referred to by Args... to values deserialized from the
|
||||
/// channel.
|
||||
/// E.g.
|
||||
///
|
||||
/// typedef Procedure<0, bool, int> Proc1;
|
||||
///
|
||||
/// ...
|
||||
/// bool B;
|
||||
/// int I;
|
||||
/// if (auto EC = expect<Proc1>(Channel, readArgs(B, I)))
|
||||
/// /* Handle Args */ ;
|
||||
///
|
||||
template <typename... ArgTs>
|
||||
static ReadArgs<ArgTs...> readArgs(ArgTs &... Args) {
|
||||
return ReadArgs<ArgTs...>(Args...);
|
||||
}
|
||||
};
|
||||
|
||||
} // end namespace remote
|
||||
} // end namespace orc
|
||||
} // end namespace llvm
|
||||
|
||||
#endif
|
@ -30,6 +30,10 @@ class ExecutionEngine;
|
||||
|
||||
class MCJITMemoryManager : public RuntimeDyld::MemoryManager {
|
||||
public:
|
||||
|
||||
// Don't hide the notifyObjectLoaded method from RuntimeDyld::MemoryManager.
|
||||
using RuntimeDyld::MemoryManager::notifyObjectLoaded;
|
||||
|
||||
/// This method is called after an object has been loaded into memory but
|
||||
/// before relocations are applied to the loaded sections. The object load
|
||||
/// may have been initiated by MCJIT to resolve an external symbol for another
|
||||
|
@ -95,7 +95,9 @@ class RuntimeDyld {
|
||||
|
||||
/// \brief Memory Management.
|
||||
class MemoryManager {
|
||||
friend class RuntimeDyld;
|
||||
public:
|
||||
MemoryManager() : FinalizationLocked(false) {}
|
||||
virtual ~MemoryManager() {}
|
||||
|
||||
/// Allocate a memory block of (at least) the given size suitable for
|
||||
@ -122,9 +124,11 @@ class RuntimeDyld {
|
||||
///
|
||||
/// Note that by default the callback is disabled. To enable it
|
||||
/// redefine the method needsToReserveAllocationSpace to return true.
|
||||
virtual void reserveAllocationSpace(uintptr_t CodeSize,
|
||||
uintptr_t DataSizeRO,
|
||||
uintptr_t DataSizeRW) {}
|
||||
virtual void reserveAllocationSpace(uintptr_t CodeSize, uint32_t CodeAlign,
|
||||
uintptr_t RODataSize,
|
||||
uint32_t RODataAlign,
|
||||
uintptr_t RWDataSize,
|
||||
uint32_t RWDataAlign) {}
|
||||
|
||||
/// Override to return true to enable the reserveAllocationSpace callback.
|
||||
virtual bool needsToReserveAllocationSpace() { return false; }
|
||||
@ -151,8 +155,23 @@ class RuntimeDyld {
|
||||
/// Returns true if an error occurred, false otherwise.
|
||||
virtual bool finalizeMemory(std::string *ErrMsg = nullptr) = 0;
|
||||
|
||||
/// This method is called after an object has been loaded into memory but
|
||||
/// before relocations are applied to the loaded sections.
|
||||
///
|
||||
/// Memory managers which are preparing code for execution in an external
|
||||
/// address space can use this call to remap the section addresses for the
|
||||
/// newly loaded object.
|
||||
///
|
||||
/// For clients that do not need access to an ExecutionEngine instance this
|
||||
/// method should be preferred to its cousin
|
||||
/// MCJITMemoryManager::notifyObjectLoaded as this method is compatible with
|
||||
/// ORC JIT stacks.
|
||||
virtual void notifyObjectLoaded(RuntimeDyld &RTDyld,
|
||||
const object::ObjectFile &Obj) {}
|
||||
|
||||
private:
|
||||
virtual void anchor();
|
||||
bool FinalizationLocked;
|
||||
};
|
||||
|
||||
/// \brief Symbol resolution.
|
||||
@ -241,6 +260,25 @@ class RuntimeDyld {
|
||||
this->ProcessAllSections = ProcessAllSections;
|
||||
}
|
||||
|
||||
/// Perform all actions needed to make the code owned by this RuntimeDyld
|
||||
/// instance executable:
|
||||
///
|
||||
/// 1) Apply relocations.
|
||||
/// 2) Register EH frames.
|
||||
/// 3) Update memory permissions*.
|
||||
///
|
||||
/// * Finalization is potentially recursive**, and the 3rd step will only be
|
||||
/// applied by the outermost call to finalize. This allows different
|
||||
/// RuntimeDyld instances to share a memory manager without the innermost
|
||||
/// finalization locking the memory and causing relocation fixup errors in
|
||||
/// outer instances.
|
||||
///
|
||||
/// ** Recursive finalization occurs when one RuntimeDyld instances needs the
|
||||
/// address of a symbol owned by some other instance in order to apply
|
||||
/// relocations.
|
||||
///
|
||||
void finalizeWithMemoryManagerLocking();
|
||||
|
||||
private:
|
||||
// RuntimeDyldImpl is the actual class. RuntimeDyld is just the public
|
||||
// interface.
|
||||
|
@ -189,4 +189,9 @@ class MergeRule<string F> {
|
||||
string MergeFunc = F;
|
||||
}
|
||||
|
||||
def : MergeRule<"setAND<LessPreciseFPMADAttr>">;
|
||||
def : MergeRule<"setAND<NoInfsFPMathAttr>">;
|
||||
def : MergeRule<"setAND<NoNansFPMathAttr>">;
|
||||
def : MergeRule<"setAND<UnsafeFPMathAttr>">;
|
||||
def : MergeRule<"setOR<NoImplicitFloatAttr>">;
|
||||
def : MergeRule<"adjustCallerSSPLevel">;
|
||||
|
@ -66,7 +66,8 @@ class Function : public GlobalObject, public ilist_node<Function> {
|
||||
* bit 2 : HasPrologueData
|
||||
* bit 3 : HasPersonalityFn
|
||||
* bits 4-13 : CallingConvention
|
||||
* bits 14-15 : [reserved]
|
||||
* bits 14 : HasGC
|
||||
* bits 15 : [reserved]
|
||||
*/
|
||||
|
||||
/// Bits from GlobalObject::GlobalObjectSubclassData.
|
||||
@ -220,9 +221,11 @@ class Function : public GlobalObject, public ilist_node<Function> {
|
||||
|
||||
/// hasGC/getGC/setGC/clearGC - The name of the garbage collection algorithm
|
||||
/// to use during code generation.
|
||||
bool hasGC() const;
|
||||
const char *getGC() const;
|
||||
void setGC(const char *Str);
|
||||
bool hasGC() const {
|
||||
return getSubclassDataFromValue() & (1<<14);
|
||||
}
|
||||
const std::string &getGC() const;
|
||||
void setGC(const std::string Str);
|
||||
void clearGC();
|
||||
|
||||
/// @brief adds the attribute to the list of attributes.
|
||||
|
@ -178,10 +178,10 @@ class IRBuilderBase {
|
||||
void clearFastMathFlags() { FMF.clear(); }
|
||||
|
||||
/// \brief Set the floating point math metadata to be used.
|
||||
void SetDefaultFPMathTag(MDNode *FPMathTag) { DefaultFPMathTag = FPMathTag; }
|
||||
void setDefaultFPMathTag(MDNode *FPMathTag) { DefaultFPMathTag = FPMathTag; }
|
||||
|
||||
/// \brief Set the fast-math flags to be used with generated fp-math operators
|
||||
void SetFastMathFlags(FastMathFlags NewFMF) { FMF = NewFMF; }
|
||||
void setFastMathFlags(FastMathFlags NewFMF) { FMF = NewFMF; }
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// RAII helpers.
|
||||
|
@ -575,7 +575,7 @@ def int_experimental_gc_statepoint : Intrinsic<[llvm_token_ty],
|
||||
|
||||
def int_experimental_gc_result : Intrinsic<[llvm_any_ty], [llvm_token_ty],
|
||||
[IntrReadMem]>;
|
||||
def int_experimental_gc_relocate : Intrinsic<[llvm_anyptr_ty],
|
||||
def int_experimental_gc_relocate : Intrinsic<[llvm_any_ty],
|
||||
[llvm_token_ty, llvm_i32_ty, llvm_i32_ty],
|
||||
[IntrReadMem]>;
|
||||
|
||||
|
@ -1507,6 +1507,60 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.".
|
||||
[llvm_v64i8_ty, llvm_v64i8_ty, llvm_v64i8_ty, llvm_i64_ty],
|
||||
[IntrNoMem]>;
|
||||
|
||||
def int_x86_avx512_mask_pshuf_d_128 :
|
||||
GCCBuiltin<"__builtin_ia32_pshufd128_mask">,
|
||||
Intrinsic<[llvm_v4i32_ty],
|
||||
[llvm_v4i32_ty, llvm_i16_ty, llvm_v4i32_ty, llvm_i8_ty],
|
||||
[IntrNoMem]>;
|
||||
|
||||
def int_x86_avx512_mask_pshuf_d_256 :
|
||||
GCCBuiltin<"__builtin_ia32_pshufd256_mask">,
|
||||
Intrinsic<[llvm_v8i32_ty],
|
||||
[llvm_v8i32_ty, llvm_i16_ty, llvm_v8i32_ty, llvm_i8_ty],
|
||||
[IntrNoMem]>;
|
||||
|
||||
def int_x86_avx512_mask_pshuf_d_512 :
|
||||
GCCBuiltin<"__builtin_ia32_pshufd512_mask">,
|
||||
Intrinsic<[llvm_v16i32_ty],
|
||||
[llvm_v16i32_ty, llvm_i16_ty, llvm_v16i32_ty, llvm_i8_ty],
|
||||
[IntrNoMem]>;
|
||||
|
||||
def int_x86_avx512_mask_pshufh_w_128 :
|
||||
GCCBuiltin<"__builtin_ia32_pshufhw128_mask">,
|
||||
Intrinsic<[llvm_v8i16_ty],
|
||||
[llvm_v8i16_ty, llvm_i8_ty, llvm_v8i16_ty, llvm_i8_ty],
|
||||
[IntrNoMem]>;
|
||||
|
||||
def int_x86_avx512_mask_pshufh_w_256 :
|
||||
GCCBuiltin<"__builtin_ia32_pshufhw256_mask">,
|
||||
Intrinsic<[llvm_v16i16_ty],
|
||||
[llvm_v16i16_ty, llvm_i8_ty, llvm_v16i16_ty, llvm_i16_ty],
|
||||
[IntrNoMem]>;
|
||||
|
||||
def int_x86_avx512_mask_pshufh_w_512 :
|
||||
GCCBuiltin<"__builtin_ia32_pshufhw512_mask">,
|
||||
Intrinsic<[llvm_v32i16_ty],
|
||||
[llvm_v32i16_ty, llvm_i8_ty, llvm_v32i16_ty, llvm_i32_ty],
|
||||
[IntrNoMem]>;
|
||||
|
||||
def int_x86_avx512_mask_pshufl_w_128 :
|
||||
GCCBuiltin<"__builtin_ia32_pshuflw128_mask">,
|
||||
Intrinsic<[llvm_v8i16_ty],
|
||||
[llvm_v8i16_ty, llvm_i8_ty, llvm_v8i16_ty, llvm_i8_ty],
|
||||
[IntrNoMem]>;
|
||||
|
||||
def int_x86_avx512_mask_pshufl_w_256 :
|
||||
GCCBuiltin<"__builtin_ia32_pshuflw256_mask">,
|
||||
Intrinsic<[llvm_v16i16_ty],
|
||||
[llvm_v16i16_ty, llvm_i8_ty, llvm_v16i16_ty, llvm_i16_ty],
|
||||
[IntrNoMem]>;
|
||||
|
||||
def int_x86_avx512_mask_pshufl_w_512 :
|
||||
GCCBuiltin<"__builtin_ia32_pshuflw512_mask">,
|
||||
Intrinsic<[llvm_v32i16_ty],
|
||||
[llvm_v32i16_ty, llvm_i8_ty, llvm_v32i16_ty, llvm_i32_ty],
|
||||
[IntrNoMem]>;
|
||||
|
||||
def int_x86_avx512_mask_shuf_f32x4_256 :
|
||||
GCCBuiltin<"__builtin_ia32_shuf_f32x4_256_mask">,
|
||||
Intrinsic<[llvm_v8f32_ty],
|
||||
@ -1836,25 +1890,69 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.".
|
||||
def int_x86_avx_maskload_ps_256 : GCCBuiltin<"__builtin_ia32_maskloadps256">,
|
||||
Intrinsic<[llvm_v8f32_ty], [llvm_ptr_ty, llvm_v8i32_ty],
|
||||
[IntrReadArgMem]>;
|
||||
def int_x86_avx512_mask_loadu_ps_512 : GCCBuiltin<"__builtin_ia32_loadups512_mask">,
|
||||
Intrinsic<[llvm_v16f32_ty], [llvm_ptr_ty, llvm_v16f32_ty, llvm_i16_ty],
|
||||
[IntrReadArgMem]>;
|
||||
def int_x86_avx512_mask_loadu_pd_512 : GCCBuiltin<"__builtin_ia32_loadupd512_mask">,
|
||||
Intrinsic<[llvm_v8f64_ty], [llvm_ptr_ty, llvm_v8f64_ty, llvm_i8_ty],
|
||||
[IntrReadArgMem]>;
|
||||
def int_x86_avx512_mask_load_ps_512 : GCCBuiltin<"__builtin_ia32_loadaps512_mask">,
|
||||
Intrinsic<[llvm_v16f32_ty], [llvm_ptr_ty, llvm_v16f32_ty, llvm_i16_ty],
|
||||
[IntrReadArgMem]>;
|
||||
def int_x86_avx512_mask_load_pd_512 : GCCBuiltin<"__builtin_ia32_loadapd512_mask">,
|
||||
Intrinsic<[llvm_v8f64_ty], [llvm_ptr_ty, llvm_v8f64_ty, llvm_i8_ty],
|
||||
[IntrReadArgMem]>;
|
||||
|
||||
def int_x86_avx512_mask_move_ss : GCCBuiltin<"__builtin_ia32_movss_mask">,
|
||||
Intrinsic<[llvm_v4f32_ty], [llvm_v4f32_ty, llvm_v4f32_ty, llvm_v4f32_ty, llvm_i8_ty],
|
||||
[IntrNoMem]>;
|
||||
def int_x86_avx512_mask_move_sd : GCCBuiltin<"__builtin_ia32_movsd_mask">,
|
||||
Intrinsic<[llvm_v2f64_ty], [llvm_v2f64_ty, llvm_v2f64_ty, llvm_v2f64_ty, llvm_i8_ty],
|
||||
[IntrNoMem]>;
|
||||
def int_x86_avx512_mask_loadu_ps_128 :
|
||||
GCCBuiltin<"__builtin_ia32_loadups128_mask">,
|
||||
Intrinsic<[llvm_v4f32_ty],
|
||||
[llvm_ptr_ty, llvm_v4f32_ty, llvm_i8_ty], [IntrReadArgMem]>;
|
||||
def int_x86_avx512_mask_loadu_ps_256 :
|
||||
GCCBuiltin<"__builtin_ia32_loadups256_mask">,
|
||||
Intrinsic<[llvm_v8f32_ty],
|
||||
[llvm_ptr_ty, llvm_v8f32_ty, llvm_i8_ty], [IntrReadArgMem]>;
|
||||
def int_x86_avx512_mask_loadu_ps_512 :
|
||||
GCCBuiltin<"__builtin_ia32_loadups512_mask">,
|
||||
Intrinsic<[llvm_v16f32_ty],
|
||||
[llvm_ptr_ty, llvm_v16f32_ty, llvm_i16_ty], [IntrReadArgMem]>;
|
||||
|
||||
def int_x86_avx512_mask_loadu_pd_128 :
|
||||
GCCBuiltin<"__builtin_ia32_loadupd128_mask">,
|
||||
Intrinsic<[llvm_v2f64_ty],
|
||||
[llvm_ptr_ty, llvm_v2f64_ty, llvm_i8_ty], [IntrReadArgMem]>;
|
||||
def int_x86_avx512_mask_loadu_pd_256 :
|
||||
GCCBuiltin<"__builtin_ia32_loadupd256_mask">,
|
||||
Intrinsic<[llvm_v4f64_ty],
|
||||
[llvm_ptr_ty, llvm_v4f64_ty, llvm_i8_ty], [IntrReadArgMem]>;
|
||||
def int_x86_avx512_mask_loadu_pd_512 :
|
||||
GCCBuiltin<"__builtin_ia32_loadupd512_mask">,
|
||||
Intrinsic<[llvm_v8f64_ty],
|
||||
[llvm_ptr_ty, llvm_v8f64_ty, llvm_i8_ty], [IntrReadArgMem]>;
|
||||
|
||||
def int_x86_avx512_mask_load_ps_128 :
|
||||
GCCBuiltin<"__builtin_ia32_loadaps128_mask">,
|
||||
Intrinsic<[llvm_v4f32_ty],
|
||||
[llvm_ptr_ty, llvm_v4f32_ty, llvm_i8_ty], [IntrReadArgMem]>;
|
||||
def int_x86_avx512_mask_load_ps_256 :
|
||||
GCCBuiltin<"__builtin_ia32_loadaps256_mask">,
|
||||
Intrinsic<[llvm_v8f32_ty],
|
||||
[llvm_ptr_ty, llvm_v8f32_ty, llvm_i8_ty], [IntrReadArgMem]>;
|
||||
def int_x86_avx512_mask_load_ps_512 :
|
||||
GCCBuiltin<"__builtin_ia32_loadaps512_mask">,
|
||||
Intrinsic<[llvm_v16f32_ty],
|
||||
[llvm_ptr_ty, llvm_v16f32_ty, llvm_i16_ty], [IntrReadArgMem]>;
|
||||
|
||||
def int_x86_avx512_mask_load_pd_128 :
|
||||
GCCBuiltin<"__builtin_ia32_loadapd128_mask">,
|
||||
Intrinsic<[llvm_v2f64_ty],
|
||||
[llvm_ptr_ty, llvm_v2f64_ty, llvm_i8_ty], [IntrReadArgMem]>;
|
||||
def int_x86_avx512_mask_load_pd_256 :
|
||||
GCCBuiltin<"__builtin_ia32_loadapd256_mask">,
|
||||
Intrinsic<[llvm_v4f64_ty],
|
||||
[llvm_ptr_ty, llvm_v4f64_ty, llvm_i8_ty], [IntrReadArgMem]>;
|
||||
def int_x86_avx512_mask_load_pd_512 :
|
||||
GCCBuiltin<"__builtin_ia32_loadapd512_mask">,
|
||||
Intrinsic<[llvm_v8f64_ty],
|
||||
[llvm_ptr_ty, llvm_v8f64_ty, llvm_i8_ty], [IntrReadArgMem]>;
|
||||
|
||||
def int_x86_avx512_mask_move_ss :
|
||||
GCCBuiltin<"__builtin_ia32_movss_mask">,
|
||||
Intrinsic<[llvm_v4f32_ty],
|
||||
[llvm_v4f32_ty, llvm_v4f32_ty, llvm_v4f32_ty, llvm_i8_ty],
|
||||
[IntrNoMem]>;
|
||||
def int_x86_avx512_mask_move_sd :
|
||||
GCCBuiltin<"__builtin_ia32_movsd_mask">,
|
||||
Intrinsic<[llvm_v2f64_ty],
|
||||
[llvm_v2f64_ty, llvm_v2f64_ty, llvm_v2f64_ty, llvm_i8_ty],
|
||||
[IntrNoMem]>;
|
||||
}
|
||||
|
||||
// Conditional store ops
|
||||
@ -2262,6 +2360,46 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.".
|
||||
Intrinsic<[llvm_v8i64_ty], [llvm_v8i64_ty,
|
||||
llvm_v2i64_ty, llvm_v8i64_ty, llvm_i8_ty], [IntrNoMem]>;
|
||||
|
||||
def int_x86_avx512_mask_psll_w_128 : GCCBuiltin<"__builtin_ia32_psllw128_mask">,
|
||||
Intrinsic<[llvm_v8i16_ty], [llvm_v8i16_ty,
|
||||
llvm_v8i16_ty, llvm_v8i16_ty, llvm_i8_ty], [IntrNoMem]>;
|
||||
def int_x86_avx512_mask_psll_w_256 : GCCBuiltin<"__builtin_ia32_psllw256_mask">,
|
||||
Intrinsic<[llvm_v16i16_ty], [llvm_v16i16_ty,
|
||||
llvm_v8i16_ty, llvm_v16i16_ty, llvm_i16_ty], [IntrNoMem]>;
|
||||
def int_x86_avx512_mask_psll_w_512 : GCCBuiltin<"__builtin_ia32_psllw512_mask">,
|
||||
Intrinsic<[llvm_v32i16_ty], [llvm_v32i16_ty,
|
||||
llvm_v8i16_ty, llvm_v32i16_ty, llvm_i32_ty], [IntrNoMem]>;
|
||||
def int_x86_avx512_mask_psll_wi_128 : GCCBuiltin<"__builtin_ia32_psllwi128_mask">,
|
||||
Intrinsic<[llvm_v8i16_ty], [llvm_v8i16_ty,
|
||||
llvm_i8_ty, llvm_v8i16_ty, llvm_i8_ty], [IntrNoMem]>;
|
||||
def int_x86_avx512_mask_psll_wi_256 : GCCBuiltin<"__builtin_ia32_psllwi256_mask">,
|
||||
Intrinsic<[llvm_v16i16_ty], [llvm_v16i16_ty,
|
||||
llvm_i8_ty, llvm_v16i16_ty, llvm_i16_ty], [IntrNoMem]>;
|
||||
def int_x86_avx512_mask_psll_wi_512 : GCCBuiltin<"__builtin_ia32_psllwi512_mask">,
|
||||
Intrinsic<[llvm_v32i16_ty], [llvm_v32i16_ty,
|
||||
llvm_i8_ty, llvm_v32i16_ty, llvm_i32_ty], [IntrNoMem]>;
|
||||
def int_x86_avx512_mask_psllv16_hi : GCCBuiltin<"__builtin_ia32_psllv16hi_mask">,
|
||||
Intrinsic<[llvm_v16i16_ty], [llvm_v16i16_ty,
|
||||
llvm_v16i16_ty, llvm_v16i16_ty, llvm_i16_ty], [IntrNoMem]>;
|
||||
def int_x86_avx512_mask_psllv2_di : GCCBuiltin<"__builtin_ia32_psllv2di_mask">,
|
||||
Intrinsic<[llvm_v2i64_ty], [llvm_v2i64_ty,
|
||||
llvm_v2i64_ty, llvm_v2i64_ty, llvm_i8_ty], [IntrNoMem]>;
|
||||
def int_x86_avx512_mask_psllv32hi : GCCBuiltin<"__builtin_ia32_psllv32hi_mask">,
|
||||
Intrinsic<[llvm_v32i16_ty], [llvm_v32i16_ty,
|
||||
llvm_v32i16_ty, llvm_v32i16_ty, llvm_i32_ty], [IntrNoMem]>;
|
||||
def int_x86_avx512_mask_psllv4_di : GCCBuiltin<"__builtin_ia32_psllv4di_mask">,
|
||||
Intrinsic<[llvm_v4i64_ty], [llvm_v4i64_ty,
|
||||
llvm_v4i64_ty, llvm_v4i64_ty, llvm_i8_ty], [IntrNoMem]>;
|
||||
def int_x86_avx512_mask_psllv4_si : GCCBuiltin<"__builtin_ia32_psllv4si_mask">,
|
||||
Intrinsic<[llvm_v4i32_ty], [llvm_v4i32_ty,
|
||||
llvm_v4i32_ty, llvm_v4i32_ty, llvm_i8_ty], [IntrNoMem]>;
|
||||
def int_x86_avx512_mask_psllv8_hi : GCCBuiltin<"__builtin_ia32_psllv8hi_mask">,
|
||||
Intrinsic<[llvm_v8i16_ty], [llvm_v8i16_ty,
|
||||
llvm_v8i16_ty, llvm_v8i16_ty, llvm_i8_ty], [IntrNoMem]>;
|
||||
def int_x86_avx512_mask_psllv8_si : GCCBuiltin<"__builtin_ia32_psllv8si_mask">,
|
||||
Intrinsic<[llvm_v8i32_ty], [llvm_v8i32_ty,
|
||||
llvm_v8i32_ty, llvm_v8i32_ty, llvm_i8_ty], [IntrNoMem]>;
|
||||
|
||||
def int_x86_avx512_mask_psra_d_128 : GCCBuiltin<"__builtin_ia32_psrad128_mask">,
|
||||
Intrinsic<[llvm_v4i32_ty], [llvm_v4i32_ty,
|
||||
llvm_v4i32_ty, llvm_v4i32_ty, llvm_i8_ty], [IntrNoMem]>;
|
||||
@ -2823,6 +2961,28 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.".
|
||||
Intrinsic<[llvm_v8i64_ty], [llvm_v8i64_ty,
|
||||
llvm_i8_ty, llvm_v8i64_ty, llvm_i8_ty], [IntrNoMem]>;
|
||||
|
||||
def int_x86_avx512_mask_psrav16_hi : GCCBuiltin<"__builtin_ia32_psrav16hi_mask">,
|
||||
Intrinsic<[llvm_v16i16_ty], [llvm_v16i16_ty,
|
||||
llvm_v16i16_ty, llvm_v16i16_ty, llvm_i16_ty], [IntrNoMem]>;
|
||||
def int_x86_avx512_mask_psrav32_hi : GCCBuiltin<"__builtin_ia32_psrav32hi_mask">,
|
||||
Intrinsic<[llvm_v32i16_ty], [llvm_v32i16_ty,
|
||||
llvm_v32i16_ty, llvm_v32i16_ty, llvm_i32_ty], [IntrNoMem]>;
|
||||
def int_x86_avx512_mask_psrav4_si : GCCBuiltin<"__builtin_ia32_psrav4si_mask">,
|
||||
Intrinsic<[llvm_v4i32_ty], [llvm_v4i32_ty,
|
||||
llvm_v4i32_ty, llvm_v4i32_ty, llvm_i8_ty], [IntrNoMem]>;
|
||||
def int_x86_avx512_mask_psrav8_hi : GCCBuiltin<"__builtin_ia32_psrav8hi_mask">,
|
||||
Intrinsic<[llvm_v8i16_ty], [llvm_v8i16_ty,
|
||||
llvm_v8i16_ty, llvm_v8i16_ty, llvm_i8_ty], [IntrNoMem]>;
|
||||
def int_x86_avx512_mask_psrav8_si : GCCBuiltin<"__builtin_ia32_psrav8si_mask">,
|
||||
Intrinsic<[llvm_v8i32_ty], [llvm_v8i32_ty,
|
||||
llvm_v8i32_ty, llvm_v8i32_ty, llvm_i8_ty], [IntrNoMem]>;
|
||||
def int_x86_avx512_mask_psrav_q_128 : GCCBuiltin<"__builtin_ia32_psravq128_mask">,
|
||||
Intrinsic<[llvm_v2i64_ty], [llvm_v2i64_ty,
|
||||
llvm_v2i64_ty, llvm_v2i64_ty, llvm_i8_ty], [IntrNoMem]>;
|
||||
def int_x86_avx512_mask_psrav_q_256 : GCCBuiltin<"__builtin_ia32_psravq256_mask">,
|
||||
Intrinsic<[llvm_v4i64_ty], [llvm_v4i64_ty,
|
||||
llvm_v4i64_ty, llvm_v4i64_ty, llvm_i8_ty], [IntrNoMem]>;
|
||||
|
||||
def int_x86_avx512_mask_psrlv16_hi : GCCBuiltin<"__builtin_ia32_psrlv16hi_mask">,
|
||||
Intrinsic<[llvm_v16i16_ty], [llvm_v16i16_ty,
|
||||
llvm_v16i16_ty, llvm_v16i16_ty, llvm_i16_ty], [IntrNoMem]>;
|
||||
@ -2844,6 +3004,83 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.".
|
||||
def int_x86_avx512_mask_psrlv8_si : GCCBuiltin<"__builtin_ia32_psrlv8si_mask">,
|
||||
Intrinsic<[llvm_v8i32_ty], [llvm_v8i32_ty,
|
||||
llvm_v8i32_ty, llvm_v8i32_ty, llvm_i8_ty], [IntrNoMem]>;
|
||||
|
||||
def int_x86_avx512_mask_prorv_d_128 : GCCBuiltin<"__builtin_ia32_prorvd128_mask">,
|
||||
Intrinsic<[llvm_v4i32_ty], [llvm_v4i32_ty,
|
||||
llvm_v4i32_ty, llvm_v4i32_ty, llvm_i8_ty], [IntrNoMem]>;
|
||||
def int_x86_avx512_mask_prorv_d_256 : GCCBuiltin<"__builtin_ia32_prorvd256_mask">,
|
||||
Intrinsic<[llvm_v8i32_ty], [llvm_v8i32_ty,
|
||||
llvm_v8i32_ty, llvm_v8i32_ty, llvm_i8_ty], [IntrNoMem]>;
|
||||
def int_x86_avx512_mask_prorv_d_512 : GCCBuiltin<"__builtin_ia32_prorvd512_mask">,
|
||||
Intrinsic<[llvm_v16i32_ty], [llvm_v16i32_ty,
|
||||
llvm_v16i32_ty, llvm_v16i32_ty, llvm_i16_ty], [IntrNoMem]>;
|
||||
def int_x86_avx512_mask_prorv_q_128 : GCCBuiltin<"__builtin_ia32_prorvq128_mask">,
|
||||
Intrinsic<[llvm_v2i64_ty], [llvm_v2i64_ty,
|
||||
llvm_v2i64_ty, llvm_v2i64_ty, llvm_i8_ty], [IntrNoMem]>;
|
||||
def int_x86_avx512_mask_prorv_q_256 : GCCBuiltin<"__builtin_ia32_prorvq256_mask">,
|
||||
Intrinsic<[llvm_v4i64_ty], [llvm_v4i64_ty,
|
||||
llvm_v4i64_ty, llvm_v4i64_ty, llvm_i8_ty], [IntrNoMem]>;
|
||||
def int_x86_avx512_mask_prorv_q_512 : GCCBuiltin<"__builtin_ia32_prorvq512_mask">,
|
||||
Intrinsic<[llvm_v8i64_ty], [llvm_v8i64_ty,
|
||||
llvm_v8i64_ty, llvm_v8i64_ty, llvm_i8_ty], [IntrNoMem]>;
|
||||
|
||||
def int_x86_avx512_mask_prol_d_128 : GCCBuiltin<"__builtin_ia32_prold128_mask">,
|
||||
Intrinsic<[llvm_v4i32_ty] , [llvm_v4i32_ty,
|
||||
llvm_i8_ty, llvm_v4i32_ty, llvm_i8_ty], [IntrNoMem]>;
|
||||
def int_x86_avx512_mask_prol_d_256 : GCCBuiltin<"__builtin_ia32_prold256_mask">,
|
||||
Intrinsic<[llvm_v8i32_ty] , [llvm_v8i32_ty,
|
||||
llvm_i8_ty, llvm_v8i32_ty, llvm_i8_ty], [IntrNoMem]>;
|
||||
def int_x86_avx512_mask_prol_d_512 : GCCBuiltin<"__builtin_ia32_prold512_mask">,
|
||||
Intrinsic<[llvm_v16i32_ty] , [llvm_v16i32_ty,
|
||||
llvm_i8_ty, llvm_v16i32_ty, llvm_i16_ty], [IntrNoMem]>;
|
||||
def int_x86_avx512_mask_prol_q_128 : GCCBuiltin<"__builtin_ia32_prolq128_mask">,
|
||||
Intrinsic<[llvm_v2i64_ty] , [llvm_v2i64_ty,
|
||||
llvm_i8_ty, llvm_v2i64_ty, llvm_i8_ty], [IntrNoMem]>;
|
||||
def int_x86_avx512_mask_prol_q_256 : GCCBuiltin<"__builtin_ia32_prolq256_mask">,
|
||||
Intrinsic<[llvm_v4i64_ty] , [llvm_v4i64_ty,
|
||||
llvm_i8_ty, llvm_v4i64_ty, llvm_i8_ty], [IntrNoMem]>;
|
||||
def int_x86_avx512_mask_prol_q_512 : GCCBuiltin<"__builtin_ia32_prolq512_mask">,
|
||||
Intrinsic<[llvm_v8i64_ty] , [llvm_v8i64_ty,
|
||||
llvm_i8_ty, llvm_v8i64_ty, llvm_i8_ty], [IntrNoMem]>;
|
||||
|
||||
|
||||
def int_x86_avx512_mask_prolv_d_128 : GCCBuiltin<"__builtin_ia32_prolvd128_mask">,
|
||||
Intrinsic<[llvm_v4i32_ty], [llvm_v4i32_ty,
|
||||
llvm_v4i32_ty, llvm_v4i32_ty, llvm_i8_ty], [IntrNoMem]>;
|
||||
def int_x86_avx512_mask_prolv_d_256 : GCCBuiltin<"__builtin_ia32_prolvd256_mask">,
|
||||
Intrinsic<[llvm_v8i32_ty], [llvm_v8i32_ty,
|
||||
llvm_v8i32_ty, llvm_v8i32_ty, llvm_i8_ty], [IntrNoMem]>;
|
||||
def int_x86_avx512_mask_prolv_d_512 : GCCBuiltin<"__builtin_ia32_prolvd512_mask">,
|
||||
Intrinsic<[llvm_v16i32_ty], [llvm_v16i32_ty,
|
||||
llvm_v16i32_ty, llvm_v16i32_ty, llvm_i16_ty], [IntrNoMem]>;
|
||||
def int_x86_avx512_mask_prolv_q_128 : GCCBuiltin<"__builtin_ia32_prolvq128_mask">,
|
||||
Intrinsic<[llvm_v2i64_ty], [llvm_v2i64_ty,
|
||||
llvm_v2i64_ty, llvm_v2i64_ty, llvm_i8_ty], [IntrNoMem]>;
|
||||
def int_x86_avx512_mask_prolv_q_256 : GCCBuiltin<"__builtin_ia32_prolvq256_mask">,
|
||||
Intrinsic<[llvm_v4i64_ty], [llvm_v4i64_ty,
|
||||
llvm_v4i64_ty, llvm_v4i64_ty, llvm_i8_ty], [IntrNoMem]>;
|
||||
def int_x86_avx512_mask_prolv_q_512 : GCCBuiltin<"__builtin_ia32_prolvq512_mask">,
|
||||
Intrinsic<[llvm_v8i64_ty], [llvm_v8i64_ty,
|
||||
llvm_v8i64_ty, llvm_v8i64_ty, llvm_i8_ty], [IntrNoMem]>;
|
||||
def int_x86_avx512_mask_pror_d_128 : GCCBuiltin<"__builtin_ia32_prord128_mask">,
|
||||
Intrinsic<[llvm_v4i32_ty], [llvm_v4i32_ty,
|
||||
llvm_i8_ty, llvm_v4i32_ty, llvm_i8_ty], [IntrNoMem]>;
|
||||
def int_x86_avx512_mask_pror_d_256 : GCCBuiltin<"__builtin_ia32_prord256_mask">,
|
||||
Intrinsic<[llvm_v8i32_ty], [llvm_v8i32_ty,
|
||||
llvm_i8_ty, llvm_v8i32_ty, llvm_i8_ty], [IntrNoMem]>;
|
||||
def int_x86_avx512_mask_pror_d_512 : GCCBuiltin<"__builtin_ia32_prord512_mask">,
|
||||
Intrinsic<[llvm_v16i32_ty], [llvm_v16i32_ty,
|
||||
llvm_i8_ty, llvm_v16i32_ty, llvm_i16_ty], [IntrNoMem]>;
|
||||
def int_x86_avx512_mask_pror_q_128 : GCCBuiltin<"__builtin_ia32_prorq128_mask">,
|
||||
Intrinsic<[llvm_v2i64_ty], [llvm_v2i64_ty,
|
||||
llvm_i8_ty, llvm_v2i64_ty, llvm_i8_ty], [IntrNoMem]>;
|
||||
def int_x86_avx512_mask_pror_q_256 : GCCBuiltin<"__builtin_ia32_prorq256_mask">,
|
||||
Intrinsic<[llvm_v4i64_ty], [llvm_v4i64_ty,
|
||||
llvm_i8_ty, llvm_v4i64_ty, llvm_i8_ty], [IntrNoMem]>;
|
||||
def int_x86_avx512_mask_pror_q_512 : GCCBuiltin<"__builtin_ia32_prorq512_mask">,
|
||||
Intrinsic<[llvm_v8i64_ty], [llvm_v8i64_ty,
|
||||
llvm_i8_ty, llvm_v8i64_ty, llvm_i8_ty], [IntrNoMem]>;
|
||||
|
||||
}
|
||||
|
||||
// Gather ops
|
||||
@ -4208,6 +4445,61 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.".
|
||||
def int_x86_avx512_kortestc_w : GCCBuiltin<"__builtin_ia32_kortestchi">,
|
||||
Intrinsic<[llvm_i32_ty], [llvm_i16_ty, llvm_i16_ty],
|
||||
[IntrNoMem]>;
|
||||
|
||||
def int_x86_avx512_mask_pmovsxb_d_128 : GCCBuiltin<"__builtin_ia32_pmovsxbd128_mask">,
|
||||
Intrinsic<[llvm_v4i32_ty], [llvm_v16i8_ty,
|
||||
llvm_v4i32_ty, llvm_i8_ty], [IntrNoMem]>;
|
||||
def int_x86_avx512_mask_pmovsxb_d_256 : GCCBuiltin<"__builtin_ia32_pmovsxbd256_mask">,
|
||||
Intrinsic<[llvm_v8i32_ty], [llvm_v16i8_ty,
|
||||
llvm_v8i32_ty, llvm_i8_ty], [IntrNoMem]>;
|
||||
def int_x86_avx512_mask_pmovsxb_d_512 : GCCBuiltin<"__builtin_ia32_pmovsxbd512_mask">,
|
||||
Intrinsic<[llvm_v16i32_ty], [llvm_v16i8_ty,
|
||||
llvm_v16i32_ty, llvm_i16_ty], [IntrNoMem]>;
|
||||
def int_x86_avx512_mask_pmovsxb_q_128 : GCCBuiltin<"__builtin_ia32_pmovsxbq128_mask">,
|
||||
Intrinsic<[llvm_v2i64_ty], [llvm_v16i8_ty,
|
||||
llvm_v2i64_ty, llvm_i8_ty], [IntrNoMem]>;
|
||||
def int_x86_avx512_mask_pmovsxb_q_256 : GCCBuiltin<"__builtin_ia32_pmovsxbq256_mask">,
|
||||
Intrinsic<[llvm_v4i64_ty], [llvm_v16i8_ty,
|
||||
llvm_v4i64_ty, llvm_i8_ty], [IntrNoMem]>;
|
||||
def int_x86_avx512_mask_pmovsxb_q_512 : GCCBuiltin<"__builtin_ia32_pmovsxbq512_mask">,
|
||||
Intrinsic<[llvm_v8i64_ty], [llvm_v16i8_ty,
|
||||
llvm_v8i64_ty, llvm_i8_ty], [IntrNoMem]>;
|
||||
def int_x86_avx512_mask_pmovsxb_w_128 : GCCBuiltin<"__builtin_ia32_pmovsxbw128_mask">,
|
||||
Intrinsic<[llvm_v8i16_ty], [llvm_v16i8_ty,
|
||||
llvm_v8i16_ty, llvm_i8_ty], [IntrNoMem]>;
|
||||
def int_x86_avx512_mask_pmovsxb_w_256 : GCCBuiltin<"__builtin_ia32_pmovsxbw256_mask">,
|
||||
Intrinsic<[llvm_v16i16_ty], [llvm_v16i8_ty,
|
||||
llvm_v16i16_ty, llvm_i16_ty], [IntrNoMem]>;
|
||||
def int_x86_avx512_mask_pmovsxb_w_512 : GCCBuiltin<"__builtin_ia32_pmovsxbw512_mask">,
|
||||
Intrinsic<[llvm_v32i16_ty], [llvm_v32i8_ty,
|
||||
llvm_v32i16_ty, llvm_i32_ty], [IntrNoMem]>;
|
||||
def int_x86_avx512_mask_pmovsxd_q_128 : GCCBuiltin<"__builtin_ia32_pmovsxdq128_mask">,
|
||||
Intrinsic<[llvm_v2i64_ty], [llvm_v4i32_ty,
|
||||
llvm_v2i64_ty, llvm_i8_ty], [IntrNoMem]>;
|
||||
def int_x86_avx512_mask_pmovsxd_q_256 : GCCBuiltin<"__builtin_ia32_pmovsxdq256_mask">,
|
||||
Intrinsic<[llvm_v4i64_ty], [llvm_v4i32_ty,
|
||||
llvm_v4i64_ty, llvm_i8_ty], [IntrNoMem]>;
|
||||
def int_x86_avx512_mask_pmovsxd_q_512 : GCCBuiltin<"__builtin_ia32_pmovsxdq512_mask">,
|
||||
Intrinsic<[llvm_v8i64_ty], [llvm_v8i32_ty,
|
||||
llvm_v8i64_ty, llvm_i8_ty], [IntrNoMem]>;
|
||||
def int_x86_avx512_mask_pmovsxw_d_128 : GCCBuiltin<"__builtin_ia32_pmovsxwd128_mask">,
|
||||
Intrinsic<[llvm_v4i32_ty], [llvm_v8i16_ty,
|
||||
llvm_v4i32_ty, llvm_i8_ty], [IntrNoMem]>;
|
||||
def int_x86_avx512_mask_pmovsxw_d_256 : GCCBuiltin<"__builtin_ia32_pmovsxwd256_mask">,
|
||||
Intrinsic<[llvm_v8i32_ty], [llvm_v8i16_ty,
|
||||
llvm_v8i32_ty, llvm_i8_ty], [IntrNoMem]>;
|
||||
def int_x86_avx512_mask_pmovsxw_d_512 : GCCBuiltin<"__builtin_ia32_pmovsxwd512_mask">,
|
||||
Intrinsic<[llvm_v16i32_ty], [llvm_v16i16_ty,
|
||||
llvm_v16i32_ty, llvm_i16_ty], [IntrNoMem]>;
|
||||
def int_x86_avx512_mask_pmovsxw_q_128 : GCCBuiltin<"__builtin_ia32_pmovsxwq128_mask">,
|
||||
Intrinsic<[llvm_v2i64_ty], [llvm_v8i16_ty,
|
||||
llvm_v2i64_ty, llvm_i8_ty], [IntrNoMem]>;
|
||||
def int_x86_avx512_mask_pmovsxw_q_256 : GCCBuiltin<"__builtin_ia32_pmovsxwq256_mask">,
|
||||
Intrinsic<[llvm_v4i64_ty], [llvm_v8i16_ty,
|
||||
llvm_v4i64_ty, llvm_i8_ty], [IntrNoMem]>;
|
||||
def int_x86_avx512_mask_pmovsxw_q_512 : GCCBuiltin<"__builtin_ia32_pmovsxwq512_mask">,
|
||||
Intrinsic<[llvm_v8i64_ty], [llvm_v8i16_ty,
|
||||
llvm_v8i64_ty, llvm_i8_ty], [IntrNoMem]>;
|
||||
}
|
||||
|
||||
// Conversion ops
|
||||
@ -5319,6 +5611,62 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.".
|
||||
def int_x86_avx512_pmovzxdq : GCCBuiltin<"__builtin_ia32_pmovzxdq512">,
|
||||
Intrinsic<[llvm_v8i64_ty], [llvm_v8i32_ty],
|
||||
[IntrNoMem]>;
|
||||
|
||||
def int_x86_avx512_mask_pmovzxb_d_128 : GCCBuiltin<"__builtin_ia32_pmovzxbd128_mask">,
|
||||
Intrinsic<[llvm_v4i32_ty], [llvm_v16i8_ty,
|
||||
llvm_v4i32_ty, llvm_i8_ty], [IntrNoMem]>;
|
||||
def int_x86_avx512_mask_pmovzxb_d_256 : GCCBuiltin<"__builtin_ia32_pmovzxbd256_mask">,
|
||||
Intrinsic<[llvm_v8i32_ty], [llvm_v16i8_ty,
|
||||
llvm_v8i32_ty, llvm_i8_ty], [IntrNoMem]>;
|
||||
def int_x86_avx512_mask_pmovzxb_d_512 : GCCBuiltin<"__builtin_ia32_pmovzxbd512_mask">,
|
||||
Intrinsic<[llvm_v16i32_ty], [llvm_v16i8_ty,
|
||||
llvm_v16i32_ty, llvm_i16_ty], [IntrNoMem]>;
|
||||
def int_x86_avx512_mask_pmovzxb_q_128 : GCCBuiltin<"__builtin_ia32_pmovzxbq128_mask">,
|
||||
Intrinsic<[llvm_v2i64_ty], [llvm_v16i8_ty,
|
||||
llvm_v2i64_ty, llvm_i8_ty], [IntrNoMem]>;
|
||||
def int_x86_avx512_mask_pmovzxb_q_256 : GCCBuiltin<"__builtin_ia32_pmovzxbq256_mask">,
|
||||
Intrinsic<[llvm_v4i64_ty], [llvm_v16i8_ty,
|
||||
llvm_v4i64_ty, llvm_i8_ty], [IntrNoMem]>;
|
||||
def int_x86_avx512_mask_pmovzxb_q_512 : GCCBuiltin<"__builtin_ia32_pmovzxbq512_mask">,
|
||||
Intrinsic<[llvm_v8i64_ty], [llvm_v16i8_ty,
|
||||
llvm_v8i64_ty, llvm_i8_ty], [IntrNoMem]>;
|
||||
def int_x86_avx512_mask_pmovzxb_w_128 : GCCBuiltin<"__builtin_ia32_pmovzxbw128_mask">,
|
||||
Intrinsic<[llvm_v8i16_ty], [llvm_v16i8_ty,
|
||||
llvm_v8i16_ty, llvm_i8_ty], [IntrNoMem]>;
|
||||
def int_x86_avx512_mask_pmovzxb_w_256 : GCCBuiltin<"__builtin_ia32_pmovzxbw256_mask">,
|
||||
Intrinsic<[llvm_v16i16_ty], [llvm_v16i8_ty,
|
||||
llvm_v16i16_ty, llvm_i16_ty], [IntrNoMem]>;
|
||||
def int_x86_avx512_mask_pmovzxb_w_512 : GCCBuiltin<"__builtin_ia32_pmovzxbw512_mask">,
|
||||
Intrinsic<[llvm_v32i16_ty], [llvm_v32i8_ty,
|
||||
llvm_v32i16_ty, llvm_i32_ty], [IntrNoMem]>;
|
||||
def int_x86_avx512_mask_pmovzxd_q_128 : GCCBuiltin<"__builtin_ia32_pmovzxdq128_mask">,
|
||||
Intrinsic<[llvm_v2i64_ty], [llvm_v4i32_ty,
|
||||
llvm_v2i64_ty, llvm_i8_ty], [IntrNoMem]>;
|
||||
def int_x86_avx512_mask_pmovzxd_q_256 : GCCBuiltin<"__builtin_ia32_pmovzxdq256_mask">,
|
||||
Intrinsic<[llvm_v4i64_ty], [llvm_v4i32_ty,
|
||||
llvm_v4i64_ty, llvm_i8_ty], [IntrNoMem]>;
|
||||
def int_x86_avx512_mask_pmovzxd_q_512 : GCCBuiltin<"__builtin_ia32_pmovzxdq512_mask">,
|
||||
Intrinsic<[llvm_v8i64_ty], [llvm_v8i32_ty,
|
||||
llvm_v8i64_ty, llvm_i8_ty], [IntrNoMem]>;
|
||||
def int_x86_avx512_mask_pmovzxw_d_128 : GCCBuiltin<"__builtin_ia32_pmovzxwd128_mask">,
|
||||
Intrinsic<[llvm_v4i32_ty], [llvm_v8i16_ty,
|
||||
llvm_v4i32_ty, llvm_i8_ty], [IntrNoMem]>;
|
||||
def int_x86_avx512_mask_pmovzxw_d_256 : GCCBuiltin<"__builtin_ia32_pmovzxwd256_mask">,
|
||||
Intrinsic<[llvm_v8i32_ty], [llvm_v8i16_ty,
|
||||
llvm_v8i32_ty, llvm_i8_ty], [IntrNoMem]>;
|
||||
def int_x86_avx512_mask_pmovzxw_d_512 : GCCBuiltin<"__builtin_ia32_pmovzxwd512_mask">,
|
||||
Intrinsic<[llvm_v16i32_ty], [llvm_v16i16_ty,
|
||||
llvm_v16i32_ty, llvm_i16_ty], [IntrNoMem]>;
|
||||
def int_x86_avx512_mask_pmovzxw_q_128 : GCCBuiltin<"__builtin_ia32_pmovzxwq128_mask">,
|
||||
Intrinsic<[llvm_v2i64_ty], [llvm_v8i16_ty,
|
||||
llvm_v2i64_ty, llvm_i8_ty], [IntrNoMem]>;
|
||||
def int_x86_avx512_mask_pmovzxw_q_256 : GCCBuiltin<"__builtin_ia32_pmovzxwq256_mask">,
|
||||
Intrinsic<[llvm_v4i64_ty], [llvm_v8i16_ty,
|
||||
llvm_v4i64_ty, llvm_i8_ty], [IntrNoMem]>;
|
||||
def int_x86_avx512_mask_pmovzxw_q_512 : GCCBuiltin<"__builtin_ia32_pmovzxwq512_mask">,
|
||||
Intrinsic<[llvm_v8i64_ty], [llvm_v8i16_ty,
|
||||
llvm_v8i64_ty, llvm_i8_ty], [IntrNoMem]>;
|
||||
|
||||
}
|
||||
//Bitwise Ops
|
||||
let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.".
|
||||
|
@ -93,6 +93,17 @@ class LLVMContext {
|
||||
/// tag registered with an LLVMContext has an unique ID.
|
||||
uint32_t getOperandBundleTagID(StringRef Tag) const;
|
||||
|
||||
|
||||
/// Define the GC for a function
|
||||
void setGC(const Function &Fn, std::string GCName);
|
||||
|
||||
/// Return the GC for a function
|
||||
const std::string &getGC(const Function &Fn);
|
||||
|
||||
/// Remove the GC for a function
|
||||
void deleteGC(const Function &Fn);
|
||||
|
||||
|
||||
typedef void (*InlineAsmDiagHandlerTy)(const SMDiagnostic&, void *Context,
|
||||
unsigned LocCookie);
|
||||
|
||||
|
@ -915,11 +915,21 @@ class MDNode : public Metadata {
|
||||
/// \brief Resolve cycles.
|
||||
///
|
||||
/// Once all forward declarations have been resolved, force cycles to be
|
||||
/// resolved. If \p AllowTemps is true, then any temporary metadata
|
||||
/// is ignored, otherwise it asserts when encountering temporary metadata.
|
||||
/// resolved. This interface is used when there are no more temporaries,
|
||||
/// and thus unresolved nodes are part of cycles and no longer need RAUW
|
||||
/// support.
|
||||
///
|
||||
/// \pre No operands (or operands' operands, etc.) have \a isTemporary().
|
||||
void resolveCycles(bool AllowTemps = false);
|
||||
void resolveCycles() { resolveRecursivelyImpl(/* AllowTemps */ false); }
|
||||
|
||||
/// \brief Resolve cycles while ignoring temporaries.
|
||||
///
|
||||
/// This drops RAUW support for any temporaries, which can no longer
|
||||
/// be uniqued.
|
||||
///
|
||||
void resolveNonTemporaries() {
|
||||
resolveRecursivelyImpl(/* AllowTemps */ true);
|
||||
}
|
||||
|
||||
/// \brief Replace a temporary node with a permanent one.
|
||||
///
|
||||
@ -977,6 +987,11 @@ class MDNode : public Metadata {
|
||||
void decrementUnresolvedOperandCount();
|
||||
unsigned countUnresolvedOperands();
|
||||
|
||||
/// Resolve cycles recursively. If \p AllowTemps is true, then any temporary
|
||||
/// metadata is ignored, otherwise it asserts when encountering temporary
|
||||
/// metadata.
|
||||
void resolveRecursivelyImpl(bool AllowTemps);
|
||||
|
||||
/// \brief Mutate this to be "uniqued".
|
||||
///
|
||||
/// Mutate this so that \a isUniqued().
|
||||
|
@ -132,7 +132,6 @@ void initializeEarlyCSELegacyPassPass(PassRegistry &);
|
||||
void initializeEliminateAvailableExternallyPass(PassRegistry&);
|
||||
void initializeExpandISelPseudosPass(PassRegistry&);
|
||||
void initializeForceFunctionAttrsLegacyPassPass(PassRegistry&);
|
||||
void initializeFunctionAttrsPass(PassRegistry&);
|
||||
void initializeGCMachineCodeAnalysisPass(PassRegistry&);
|
||||
void initializeGCModuleInfoPass(PassRegistry&);
|
||||
void initializeGVNPass(PassRegistry&);
|
||||
@ -227,6 +226,7 @@ void initializePostDomOnlyViewerPass(PassRegistry&);
|
||||
void initializePostDomPrinterPass(PassRegistry&);
|
||||
void initializePostDomViewerPass(PassRegistry&);
|
||||
void initializePostDominatorTreePass(PassRegistry&);
|
||||
void initializePostOrderFunctionAttrsPass(PassRegistry&);
|
||||
void initializePostRASchedulerPass(PassRegistry&);
|
||||
void initializePostMachineSchedulerPass(PassRegistry&);
|
||||
void initializePrintFunctionPassWrapperPass(PassRegistry&);
|
||||
@ -242,6 +242,7 @@ void initializeRegionOnlyPrinterPass(PassRegistry&);
|
||||
void initializeRegionOnlyViewerPass(PassRegistry&);
|
||||
void initializeRegionPrinterPass(PassRegistry&);
|
||||
void initializeRegionViewerPass(PassRegistry&);
|
||||
void initializeReversePostOrderFunctionAttrsPass(PassRegistry&);
|
||||
void initializeRewriteStatepointsForGCPass(PassRegistry&);
|
||||
void initializeSafeStackPass(PassRegistry&);
|
||||
void initializeSCCPPass(PassRegistry&);
|
||||
|
@ -157,7 +157,8 @@ namespace {
|
||||
(void) llvm::createPostDomTree();
|
||||
(void) llvm::createInstructionNamerPass();
|
||||
(void) llvm::createMetaRenamerPass();
|
||||
(void) llvm::createFunctionAttrsPass();
|
||||
(void) llvm::createPostOrderFunctionAttrsPass();
|
||||
(void) llvm::createReversePostOrderFunctionAttrsPass();
|
||||
(void) llvm::createMergeFunctionsPass();
|
||||
(void) llvm::createPrintModulePass(*(llvm::raw_ostream*)nullptr);
|
||||
(void) llvm::createPrintFunctionPass(*(llvm::raw_ostream*)nullptr);
|
||||
|
@ -67,10 +67,9 @@ class Linker {
|
||||
DenseMap<unsigned, MDNode *> *ValIDToTempMDMap);
|
||||
};
|
||||
|
||||
/// Create a new module with exported local functions renamed and promoted
|
||||
/// for ThinLTO.
|
||||
std::unique_ptr<Module> renameModuleForThinLTO(std::unique_ptr<Module> M,
|
||||
const FunctionInfoIndex *Index);
|
||||
/// Perform in-place global value handling on the given Module for
|
||||
/// exported local functions renamed and promoted for ThinLTO.
|
||||
bool renameModuleForThinLTO(Module &M, const FunctionInfoIndex *Index);
|
||||
|
||||
} // End llvm namespace
|
||||
|
||||
|
@ -290,6 +290,9 @@ class MCSymbolRefExpr : public MCExpr {
|
||||
VK_Hexagon_LD_PLT,
|
||||
VK_Hexagon_IE,
|
||||
VK_Hexagon_IE_GOT,
|
||||
|
||||
VK_WebAssembly_FUNCTION, // Function table index, rather than virtual addr
|
||||
|
||||
VK_TPREL,
|
||||
VK_DTPREL
|
||||
};
|
||||
|
@ -92,6 +92,7 @@ class MCObjectFileInfo {
|
||||
MCSection *DwarfLocSection;
|
||||
MCSection *DwarfARangesSection;
|
||||
MCSection *DwarfRangesSection;
|
||||
MCSection *DwarfMacinfoSection;
|
||||
// The pubnames section is no longer generated by default. The generation
|
||||
// can be enabled by a compiler flag.
|
||||
MCSection *DwarfPubNamesSection;
|
||||
@ -245,6 +246,7 @@ class MCObjectFileInfo {
|
||||
MCSection *getDwarfLocSection() const { return DwarfLocSection; }
|
||||
MCSection *getDwarfARangesSection() const { return DwarfARangesSection; }
|
||||
MCSection *getDwarfRangesSection() const { return DwarfRangesSection; }
|
||||
MCSection *getDwarfMacinfoSection() const { return DwarfMacinfoSection; }
|
||||
|
||||
// DWARF5 Experimental Debug Info Sections
|
||||
MCSection *getDwarfAccelNamesSection() const {
|
||||
|
@ -131,6 +131,10 @@ class ARMTargetStreamer : public MCTargetStreamer {
|
||||
|
||||
void finish() override;
|
||||
|
||||
/// Reset any state between object emissions, i.e. the equivalent of
|
||||
/// MCStreamer's reset method.
|
||||
virtual void reset();
|
||||
|
||||
/// Callback used to implement the ldr= pseudo.
|
||||
/// Add a new entry to the constant pool for the current section and return an
|
||||
/// MCExpr that can be used to refer to the constant pool location.
|
||||
|
@ -858,6 +858,9 @@ class ExportDirectoryEntryRef {
|
||||
std::error_code getExportRVA(uint32_t &Result) const;
|
||||
std::error_code getSymbolName(StringRef &Result) const;
|
||||
|
||||
std::error_code isForwarder(bool &Result) const;
|
||||
std::error_code getForwardTo(StringRef &Result) const;
|
||||
|
||||
private:
|
||||
const export_directory_table_entry *ExportTable;
|
||||
uint32_t Index;
|
||||
|
@ -842,6 +842,8 @@ StringRef ELFObjectFile<ELFT>::getFileFormatName() const {
|
||||
case ELF::EM_SPARC:
|
||||
case ELF::EM_SPARC32PLUS:
|
||||
return "ELF32-sparc";
|
||||
case ELF::EM_WEBASSEMBLY:
|
||||
return "ELF32-wasm";
|
||||
default:
|
||||
return "ELF32-unknown";
|
||||
}
|
||||
@ -861,6 +863,8 @@ StringRef ELFObjectFile<ELFT>::getFileFormatName() const {
|
||||
return "ELF64-sparc";
|
||||
case ELF::EM_MIPS:
|
||||
return "ELF64-mips";
|
||||
case ELF::EM_WEBASSEMBLY:
|
||||
return "ELF64-wasm";
|
||||
default:
|
||||
return "ELF64-unknown";
|
||||
}
|
||||
@ -908,6 +912,12 @@ unsigned ELFObjectFile<ELFT>::getArch() const {
|
||||
return IsLittleEndian ? Triple::sparcel : Triple::sparc;
|
||||
case ELF::EM_SPARCV9:
|
||||
return Triple::sparcv9;
|
||||
case ELF::EM_WEBASSEMBLY:
|
||||
switch (EF.getHeader()->e_ident[ELF::EI_CLASS]) {
|
||||
case ELF::ELFCLASS32: return Triple::wasm32;
|
||||
case ELF::ELFCLASS64: return Triple::wasm64;
|
||||
default: return Triple::UnknownArch;
|
||||
}
|
||||
|
||||
default:
|
||||
return Triple::UnknownArch;
|
||||
|
@ -369,6 +369,10 @@ class BasicBlockPass : public Pass {
|
||||
/// @brief This is the storage for the -time-passes option.
|
||||
extern bool TimePassesIsEnabled;
|
||||
|
||||
/// isFunctionInPrintList - returns true if a function should be printed via
|
||||
// debugging options like -print-after-all/-print-before-all.
|
||||
// @brief Tells if the function IR should be printed by PrinterPass.
|
||||
extern bool isFunctionInPrintList(StringRef FunctionName);
|
||||
} // End llvm namespace
|
||||
|
||||
// Include support files that contain important APIs commonly used by Passes,
|
||||
|
@ -20,12 +20,33 @@
|
||||
#include "llvm/ADT/Hashing.h"
|
||||
#include "llvm/ADT/Triple.h"
|
||||
#include "llvm/ADT/iterator.h"
|
||||
#include "llvm/ProfileData/InstrProf.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/Endian.h"
|
||||
#include "llvm/Support/ErrorOr.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include <system_error>
|
||||
#include <tuple>
|
||||
|
||||
namespace llvm {
|
||||
namespace coverage {
|
||||
enum class coveragemap_error {
|
||||
success = 0,
|
||||
eof,
|
||||
no_data_found,
|
||||
unsupported_version,
|
||||
truncated,
|
||||
malformed
|
||||
};
|
||||
} // end of coverage namespace.
|
||||
}
|
||||
|
||||
namespace std {
|
||||
template <>
|
||||
struct is_error_code_enum<llvm::coverage::coveragemap_error> : std::true_type {
|
||||
};
|
||||
}
|
||||
|
||||
namespace llvm {
|
||||
class IndexedInstrProfReader;
|
||||
namespace coverage {
|
||||
@ -35,8 +56,6 @@ class CoverageMappingReader;
|
||||
class CoverageMapping;
|
||||
struct CounterExpressions;
|
||||
|
||||
enum CoverageMappingVersion { CoverageMappingVersion1 };
|
||||
|
||||
/// \brief A Counter is an abstract value that describes how to compute the
|
||||
/// execution count for a region of code using the collected profile count data.
|
||||
struct Counter {
|
||||
@ -454,6 +473,76 @@ class CoverageMapping {
|
||||
CoverageData getCoverageForExpansion(const ExpansionRecord &Expansion);
|
||||
};
|
||||
|
||||
const std::error_category &coveragemap_category();
|
||||
|
||||
inline std::error_code make_error_code(coveragemap_error E) {
|
||||
return std::error_code(static_cast<int>(E), coveragemap_category());
|
||||
}
|
||||
|
||||
// Profile coverage map has the following layout:
|
||||
// [CoverageMapFileHeader]
|
||||
// [ArrayStart]
|
||||
// [CovMapFunctionRecord]
|
||||
// [CovMapFunctionRecord]
|
||||
// ...
|
||||
// [ArrayEnd]
|
||||
// [Encoded Region Mapping Data]
|
||||
LLVM_PACKED_START
|
||||
template <class IntPtrT> struct CovMapFunctionRecord {
|
||||
#define COVMAP_FUNC_RECORD(Type, LLVMType, Name, Init) Type Name;
|
||||
#include "llvm/ProfileData/InstrProfData.inc"
|
||||
|
||||
// Return the structural hash associated with the function.
|
||||
template <support::endianness Endian> uint64_t getFuncHash() const {
|
||||
return support::endian::byte_swap<uint64_t, Endian>(FuncHash);
|
||||
}
|
||||
// Return the coverage map data size for the funciton.
|
||||
template <support::endianness Endian> uint32_t getDataSize() const {
|
||||
return support::endian::byte_swap<uint32_t, Endian>(DataSize);
|
||||
}
|
||||
// Return function lookup key. The value is consider opaque.
|
||||
template <support::endianness Endian> IntPtrT getFuncNameRef() const {
|
||||
return support::endian::byte_swap<IntPtrT, Endian>(NamePtr);
|
||||
}
|
||||
// Return the PGO name of the function */
|
||||
template <support::endianness Endian>
|
||||
std::error_code getFuncName(InstrProfSymtab &ProfileNames,
|
||||
StringRef &FuncName) const {
|
||||
IntPtrT NameRef = getFuncNameRef<Endian>();
|
||||
uint32_t NameS = support::endian::byte_swap<uint32_t, Endian>(NameSize);
|
||||
FuncName = ProfileNames.getFuncName(NameRef, NameS);
|
||||
if (NameS && FuncName.empty())
|
||||
return coveragemap_error::malformed;
|
||||
return std::error_code();
|
||||
}
|
||||
};
|
||||
// Per module coverage mapping data header, i.e. CoverageMapFileHeader
|
||||
// documented above.
|
||||
struct CovMapHeader {
|
||||
#define COVMAP_HEADER(Type, LLVMType, Name, Init) Type Name;
|
||||
#include "llvm/ProfileData/InstrProfData.inc"
|
||||
template <support::endianness Endian> uint32_t getNRecords() const {
|
||||
return support::endian::byte_swap<uint32_t, Endian>(NRecords);
|
||||
}
|
||||
template <support::endianness Endian> uint32_t getFilenamesSize() const {
|
||||
return support::endian::byte_swap<uint32_t, Endian>(FilenamesSize);
|
||||
}
|
||||
template <support::endianness Endian> uint32_t getCoverageSize() const {
|
||||
return support::endian::byte_swap<uint32_t, Endian>(CoverageSize);
|
||||
}
|
||||
template <support::endianness Endian> uint32_t getVersion() const {
|
||||
return support::endian::byte_swap<uint32_t, Endian>(Version);
|
||||
}
|
||||
};
|
||||
|
||||
LLVM_PACKED_END
|
||||
|
||||
enum CoverageMappingVersion {
|
||||
CoverageMappingVersion1 = 0,
|
||||
// The current versin is Version1
|
||||
CoverageMappingCurrentVersion = INSTR_PROF_COVMAP_VERSION
|
||||
};
|
||||
|
||||
} // end namespace coverage
|
||||
|
||||
/// \brief Provide DenseMapInfo for CounterExpression
|
||||
@ -484,26 +573,6 @@ template<> struct DenseMapInfo<coverage::CounterExpression> {
|
||||
}
|
||||
};
|
||||
|
||||
const std::error_category &coveragemap_category();
|
||||
|
||||
enum class coveragemap_error {
|
||||
success = 0,
|
||||
eof,
|
||||
no_data_found,
|
||||
unsupported_version,
|
||||
truncated,
|
||||
malformed
|
||||
};
|
||||
|
||||
inline std::error_code make_error_code(coveragemap_error E) {
|
||||
return std::error_code(static_cast<int>(E), coveragemap_category());
|
||||
}
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
namespace std {
|
||||
template <>
|
||||
struct is_error_code_enum<llvm::coveragemap_error> : std::true_type {};
|
||||
}
|
||||
|
||||
#endif // LLVM_PROFILEDATA_COVERAGEMAPPING_H_
|
||||
|
@ -30,7 +30,6 @@
|
||||
#include <system_error>
|
||||
#include <vector>
|
||||
|
||||
#define INSTR_PROF_INDEX_VERSION 3
|
||||
namespace llvm {
|
||||
|
||||
class Function;
|
||||
@ -66,7 +65,8 @@ inline StringRef getInstrProfValueProfFuncName() {
|
||||
/// Return the name of the section containing function coverage mapping
|
||||
/// data.
|
||||
inline StringRef getInstrProfCoverageSectionName(bool AddSegment) {
|
||||
return AddSegment ? "__DATA,__llvm_covmap" : "__llvm_covmap";
|
||||
return AddSegment ? "__DATA," INSTR_PROF_COVMAP_SECT_NAME_STR
|
||||
: INSTR_PROF_COVMAP_SECT_NAME_STR;
|
||||
}
|
||||
|
||||
/// Return the name prefix of variables containing instrumented function names.
|
||||
@ -89,6 +89,12 @@ inline StringRef getCoverageMappingVarName() {
|
||||
return "__llvm_coverage_mapping";
|
||||
}
|
||||
|
||||
/// Return the name of the internal variable recording the array
|
||||
/// of PGO name vars referenced by the coverage mapping, The owning
|
||||
/// functions of those names are not emitted by FE (e.g, unused inline
|
||||
/// functions.)
|
||||
inline StringRef getCoverageNamesVarName() { return "__llvm_coverage_names"; }
|
||||
|
||||
/// Return the name of function that registers all the per-function control
|
||||
/// data at program startup time by calling __llvm_register_function. This
|
||||
/// function has internal linkage and is called by __llvm_profile_init
|
||||
@ -349,11 +355,14 @@ struct InstrProfValueSiteRecord {
|
||||
return left.Value < right.Value;
|
||||
});
|
||||
}
|
||||
/// Sort ValueData Descending by Count
|
||||
inline void sortByCount();
|
||||
|
||||
/// Merge data from another InstrProfValueSiteRecord
|
||||
/// Optionally scale merged counts by \p Weight.
|
||||
instrprof_error mergeValueData(InstrProfValueSiteRecord &Input,
|
||||
uint64_t Weight = 1);
|
||||
instrprof_error merge(InstrProfValueSiteRecord &Input, uint64_t Weight = 1);
|
||||
/// Scale up value profile data counts.
|
||||
instrprof_error scale(uint64_t Weight);
|
||||
};
|
||||
|
||||
/// Profiling information for a single function.
|
||||
@ -396,6 +405,19 @@ struct InstrProfRecord {
|
||||
/// Optionally scale merged counts by \p Weight.
|
||||
instrprof_error merge(InstrProfRecord &Other, uint64_t Weight = 1);
|
||||
|
||||
/// Scale up profile counts (including value profile data) by
|
||||
/// \p Weight.
|
||||
instrprof_error scale(uint64_t Weight);
|
||||
|
||||
/// Sort value profile data (per site) by count.
|
||||
void sortValueData() {
|
||||
for (uint32_t Kind = IPVK_First; Kind <= IPVK_Last; ++Kind) {
|
||||
std::vector<InstrProfValueSiteRecord> &SiteRecords =
|
||||
getValueSitesForKind(Kind);
|
||||
for (auto &SR : SiteRecords)
|
||||
SR.sortByCount();
|
||||
}
|
||||
}
|
||||
/// Clear value data entries
|
||||
void clearValueData() {
|
||||
for (uint32_t Kind = IPVK_First; Kind <= IPVK_Last; ++Kind)
|
||||
@ -430,6 +452,8 @@ struct InstrProfRecord {
|
||||
// Scale merged value counts by \p Weight.
|
||||
instrprof_error mergeValueProfData(uint32_t ValueKind, InstrProfRecord &Src,
|
||||
uint64_t Weight);
|
||||
// Scale up value profile data count.
|
||||
instrprof_error scaleValueProfData(uint32_t ValueKind, uint64_t Weight);
|
||||
};
|
||||
|
||||
uint32_t InstrProfRecord::getNumValueKinds() const {
|
||||
@ -497,11 +521,22 @@ inline support::endianness getHostEndianness() {
|
||||
#define INSTR_PROF_VALUE_PROF_DATA
|
||||
#include "llvm/ProfileData/InstrProfData.inc"
|
||||
|
||||
/*
|
||||
* Initialize the record for runtime value profile data.
|
||||
* Return 0 if the initialization is successful, otherwise
|
||||
* return 1.
|
||||
*/
|
||||
void InstrProfValueSiteRecord::sortByCount() {
|
||||
ValueData.sort(
|
||||
[](const InstrProfValueData &left, const InstrProfValueData &right) {
|
||||
return left.Count > right.Count;
|
||||
});
|
||||
// Now truncate
|
||||
size_t max_s = INSTR_PROF_MAX_NUM_VAL_PER_SITE;
|
||||
if (ValueData.size() > max_s)
|
||||
ValueData.resize(max_s);
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize the record for runtime value profile data.
|
||||
* Return 0 if the initialization is successful, otherwise
|
||||
* return 1.
|
||||
*/
|
||||
int initializeValueProfRuntimeRecord(ValueProfRuntimeRecord *RuntimeRecord,
|
||||
const uint16_t *NumValueSites,
|
||||
ValueProfNode **Nodes);
|
||||
@ -597,31 +632,6 @@ struct Header {
|
||||
|
||||
} // end namespace RawInstrProf
|
||||
|
||||
namespace coverage {
|
||||
|
||||
// Profile coverage map has the following layout:
|
||||
// [CoverageMapFileHeader]
|
||||
// [ArrayStart]
|
||||
// [CovMapFunctionRecord]
|
||||
// [CovMapFunctionRecord]
|
||||
// ...
|
||||
// [ArrayEnd]
|
||||
// [Encoded Region Mapping Data]
|
||||
LLVM_PACKED_START
|
||||
template <class IntPtrT> struct CovMapFunctionRecord {
|
||||
#define COVMAP_FUNC_RECORD(Type, LLVMType, Name, Init) Type Name;
|
||||
#include "llvm/ProfileData/InstrProfData.inc"
|
||||
};
|
||||
// Per module coverage mapping data header, i.e. CoverageMapFileHeader
|
||||
// documented above.
|
||||
struct CovMapHeader {
|
||||
#define COVMAP_HEADER(Type, LLVMType, Name, Init) Type Name;
|
||||
#include "llvm/ProfileData/InstrProfData.inc"
|
||||
};
|
||||
|
||||
LLVM_PACKED_END
|
||||
}
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
namespace std {
|
||||
|
@ -28,7 +28,7 @@
|
||||
*
|
||||
* Examples of how the template is used to instantiate structure definition:
|
||||
* 1. To declare a structure:
|
||||
*
|
||||
*
|
||||
* struct ProfData {
|
||||
* #define INSTR_PROF_DATA(Type, LLVMType, Name, Initializer) \
|
||||
* Type Name;
|
||||
@ -155,7 +155,7 @@ VALUE_PROF_KIND(IPVK_Last, IPVK_IndirectCallTarget)
|
||||
#endif
|
||||
COVMAP_FUNC_RECORD(const IntPtrT, llvm::Type::getInt8PtrTy(Ctx), \
|
||||
NamePtr, llvm::ConstantExpr::getBitCast(NamePtr, \
|
||||
llvm::Type::getInt8PtrTy(Ctx)))
|
||||
llvm::Type::getInt8PtrTy(Ctx)))
|
||||
COVMAP_FUNC_RECORD(const uint32_t, llvm::Type::getInt32Ty(Ctx), NameSize, \
|
||||
llvm::ConstantInt::get(llvm::Type::getInt32Ty(Ctx),\
|
||||
NameValue.size()))
|
||||
@ -182,7 +182,7 @@ COVMAP_HEADER(uint32_t, Int32Ty, FilenamesSize, \
|
||||
COVMAP_HEADER(uint32_t, Int32Ty, CoverageSize, \
|
||||
llvm::ConstantInt::get(Int32Ty, CoverageMappingSize))
|
||||
COVMAP_HEADER(uint32_t, Int32Ty, Version, \
|
||||
llvm::ConstantInt::get(Int32Ty, CoverageMappingVersion1))
|
||||
llvm::ConstantInt::get(Int32Ty, CoverageMappingCurrentVersion))
|
||||
#undef COVMAP_HEADER
|
||||
/* COVMAP_HEADER end. */
|
||||
|
||||
@ -190,7 +190,8 @@ COVMAP_HEADER(uint32_t, Int32Ty, Version, \
|
||||
#ifdef INSTR_PROF_VALUE_PROF_DATA
|
||||
#define INSTR_PROF_DATA_DEFINED
|
||||
|
||||
/*!
|
||||
#define INSTR_PROF_MAX_NUM_VAL_PER_SITE 255
|
||||
/*!
|
||||
* This is the header of the data structure that defines the on-disk
|
||||
* layout of the value profile data of a particular kind for one function.
|
||||
*/
|
||||
@ -202,7 +203,7 @@ typedef struct ValueProfRecord {
|
||||
* otherwise the record for this kind won't be emitted.
|
||||
*/
|
||||
uint32_t NumValueSites;
|
||||
/*
|
||||
/*
|
||||
* The first element of the array that stores the number of profiled
|
||||
* values for each value site. The size of the array is NumValueSites.
|
||||
* Since NumValueSites is greater than zero, there is at least one
|
||||
@ -226,7 +227,7 @@ typedef struct ValueProfRecord {
|
||||
* \brief Return the number of value sites.
|
||||
*/
|
||||
uint32_t getNumValueSites() const { return NumValueSites; }
|
||||
/*!
|
||||
/*!
|
||||
* \brief Read data from this record and save it to Record.
|
||||
*/
|
||||
void deserializeTo(InstrProfRecord &Record,
|
||||
@ -247,10 +248,10 @@ typedef struct ValueProfRecord {
|
||||
typedef struct ValueProfData {
|
||||
/*
|
||||
* Total size in bytes including this field. It must be a multiple
|
||||
* of sizeof(uint64_t).
|
||||
* of sizeof(uint64_t).
|
||||
*/
|
||||
uint32_t TotalSize;
|
||||
/*
|
||||
/*
|
||||
*The number of value profile kinds that has value profile data.
|
||||
* In this implementation, a value profile kind is considered to
|
||||
* have profile data if the number of value profile sites for the
|
||||
@ -260,7 +261,7 @@ typedef struct ValueProfData {
|
||||
*/
|
||||
uint32_t NumValueKinds;
|
||||
|
||||
/*
|
||||
/*
|
||||
* Following are a sequence of variable length records. The prefix/header
|
||||
* of each record is defined by ValueProfRecord type. The number of
|
||||
* records is NumValueKinds.
|
||||
@ -314,7 +315,7 @@ typedef struct ValueProfData {
|
||||
#endif
|
||||
} ValueProfData;
|
||||
|
||||
/*
|
||||
/*
|
||||
* The closure is designed to abstact away two types of value profile data:
|
||||
* - InstrProfRecord which is the primary data structure used to
|
||||
* represent profile data in host tools (reader, writer, and profile-use)
|
||||
@ -335,7 +336,7 @@ typedef struct ValueProfRecordClosure {
|
||||
uint32_t (*GetNumValueData)(const void *Record, uint32_t VKind);
|
||||
uint32_t (*GetNumValueDataForSite)(const void *R, uint32_t VK, uint32_t S);
|
||||
|
||||
/*
|
||||
/*
|
||||
* After extracting the value profile data from the value profile record,
|
||||
* this method is used to map the in-memory value to on-disk value. If
|
||||
* the method is null, value will be written out untranslated.
|
||||
@ -346,7 +347,7 @@ typedef struct ValueProfRecordClosure {
|
||||
ValueProfData *(*AllocValueProfData)(size_t TotalSizeInBytes);
|
||||
} ValueProfRecordClosure;
|
||||
|
||||
/*
|
||||
/*
|
||||
* A wrapper struct that represents value profile runtime data.
|
||||
* Like InstrProfRecord class which is used by profiling host tools,
|
||||
* ValueProfRuntimeRecord also implements the abstract intefaces defined in
|
||||
@ -384,7 +385,7 @@ serializeValueProfDataFromRT(const ValueProfRuntimeRecord *Record,
|
||||
uint32_t getNumValueKindsRT(const void *R);
|
||||
|
||||
#undef INSTR_PROF_VALUE_PROF_DATA
|
||||
#endif /* INSTR_PROF_VALUE_PROF_DATA */
|
||||
#endif /* INSTR_PROF_VALUE_PROF_DATA */
|
||||
|
||||
|
||||
#ifdef INSTR_PROF_COMMON_API_IMPL
|
||||
@ -412,7 +413,7 @@ uint32_t getValueProfRecordHeaderSize(uint32_t NumValueSites) {
|
||||
return Size;
|
||||
}
|
||||
|
||||
/*!
|
||||
/*!
|
||||
* \brief Return the total size of the value profile record including the
|
||||
* header and the value data.
|
||||
*/
|
||||
@ -432,7 +433,7 @@ InstrProfValueData *getValueProfRecordValueData(ValueProfRecord *This) {
|
||||
This->NumValueSites));
|
||||
}
|
||||
|
||||
/*!
|
||||
/*!
|
||||
* \brief Return the total number of value data for \c This record.
|
||||
*/
|
||||
INSTR_PROF_INLINE
|
||||
@ -444,7 +445,7 @@ uint32_t getValueProfRecordNumValueData(ValueProfRecord *This) {
|
||||
return NumValueData;
|
||||
}
|
||||
|
||||
/*!
|
||||
/*!
|
||||
* \brief Use this method to advance to the next \c This \c ValueProfRecord.
|
||||
*/
|
||||
INSTR_PROF_INLINE
|
||||
@ -465,7 +466,7 @@ ValueProfRecord *getFirstValueProfRecord(ValueProfData *This) {
|
||||
|
||||
/* Closure based interfaces. */
|
||||
|
||||
/*!
|
||||
/*!
|
||||
* Return the total size in bytes of the on-disk value profile data
|
||||
* given the data stored in Record.
|
||||
*/
|
||||
@ -535,7 +536,7 @@ ValueProfData *serializeValueProfDataFrom(ValueProfRecordClosure *Closure,
|
||||
return VPD;
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* The value profiler runtime library stores the value profile data
|
||||
* for a given function in \c NumValueSites and \c Nodes structures.
|
||||
* \c ValueProfRuntimeRecord class is used to encapsulate the runtime
|
||||
@ -639,7 +640,7 @@ static ValueProfRecordClosure RTRecordClosure = {0,
|
||||
getValueForSiteRT,
|
||||
allocValueProfDataRT};
|
||||
|
||||
/*
|
||||
/*
|
||||
* Return the size of ValueProfData structure to store data
|
||||
* recorded in the runtime record.
|
||||
*/
|
||||
@ -648,7 +649,7 @@ uint32_t getValueProfDataSizeRT(const ValueProfRuntimeRecord *Record) {
|
||||
return getValueProfDataSize(&RTRecordClosure);
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* Return a ValueProfData instance that stores the data collected
|
||||
* from runtime. If \c DstData is provided by the caller, the value
|
||||
* profile data will be store in *DstData and DstData is returned,
|
||||
@ -696,18 +697,31 @@ serializeValueProfDataFromRT(const ValueProfRuntimeRecord *Record,
|
||||
|
||||
/* Raw profile format version. */
|
||||
#define INSTR_PROF_RAW_VERSION 2
|
||||
#define INSTR_PROF_INDEX_VERSION 3
|
||||
#define INSTR_PROF_COVMAP_VERSION 0
|
||||
|
||||
/* Profile version is always of type uint_64_t. Reserve the upper 8 bits in the
|
||||
* version for other variants of profile. We set the lowest bit of the upper 8
|
||||
* bits (i.e. bit 56) to 1 to indicate if this is an IR-level instrumentaiton
|
||||
* generated profile, and 0 if this is a Clang FE generated profile.
|
||||
*/
|
||||
#define VARIANT_MASKS_ALL 0xff00000000000000ULL
|
||||
#define GET_VERSION(V) ((V) & ~VARIANT_MASKS_ALL)
|
||||
|
||||
/* Runtime section names and name strings. */
|
||||
#define INSTR_PROF_DATA_SECT_NAME __llvm_prf_data
|
||||
#define INSTR_PROF_NAME_SECT_NAME __llvm_prf_names
|
||||
#define INSTR_PROF_CNTS_SECT_NAME __llvm_prf_cnts
|
||||
#define INSTR_PROF_COVMAP_SECT_NAME __llvm_covmap
|
||||
|
||||
#define INSTR_PROF_DATA_SECT_NAME_STR \
|
||||
INSTR_PROF_QUOTE(INSTR_PROF_DATA_SECT_NAME)
|
||||
#define INSTR_PROF_NAME_SECT_NAME_STR \
|
||||
INSTR_PROF_QUOTE(INSTR_PROF_NAME_SECT_NAME)
|
||||
#define INSTR_PROF_CNTS_SECT_NAME_STR \
|
||||
INSTR_PROF_QUOTE(INSTR_PROF_CNTS_SECT_NAME)
|
||||
#define INSTR_PROF_DATA_SECT_NAME_STR \
|
||||
INSTR_PROF_QUOTE(INSTR_PROF_DATA_SECT_NAME)
|
||||
#define INSTR_PROF_NAME_SECT_NAME_STR \
|
||||
INSTR_PROF_QUOTE(INSTR_PROF_NAME_SECT_NAME)
|
||||
#define INSTR_PROF_CNTS_SECT_NAME_STR \
|
||||
INSTR_PROF_QUOTE(INSTR_PROF_CNTS_SECT_NAME)
|
||||
#define INSTR_PROF_COVMAP_SECT_NAME_STR \
|
||||
INSTR_PROF_QUOTE(INSTR_PROF_COVMAP_SECT_NAME)
|
||||
|
||||
/* Macros to define start/stop section symbol for a given
|
||||
* section on Linux. For instance
|
||||
@ -751,4 +765,3 @@ typedef struct ValueProfNode {
|
||||
#else
|
||||
#undef INSTR_PROF_DATA_DEFINED
|
||||
#endif
|
||||
|
||||
|
@ -140,16 +140,9 @@ class SampleRecord {
|
||||
/// around unsigned integers.
|
||||
sampleprof_error addSamples(uint64_t S, uint64_t Weight = 1) {
|
||||
bool Overflowed;
|
||||
if (Weight > 1) {
|
||||
S = SaturatingMultiply(S, Weight, &Overflowed);
|
||||
if (Overflowed)
|
||||
return sampleprof_error::counter_overflow;
|
||||
}
|
||||
NumSamples = SaturatingAdd(NumSamples, S, &Overflowed);
|
||||
if (Overflowed)
|
||||
return sampleprof_error::counter_overflow;
|
||||
|
||||
return sampleprof_error::success;
|
||||
NumSamples = SaturatingMultiplyAdd(S, Weight, NumSamples, &Overflowed);
|
||||
return Overflowed ? sampleprof_error::counter_overflow
|
||||
: sampleprof_error::success;
|
||||
}
|
||||
|
||||
/// Add called function \p F with samples \p S.
|
||||
@ -161,16 +154,10 @@ class SampleRecord {
|
||||
uint64_t Weight = 1) {
|
||||
uint64_t &TargetSamples = CallTargets[F];
|
||||
bool Overflowed;
|
||||
if (Weight > 1) {
|
||||
S = SaturatingMultiply(S, Weight, &Overflowed);
|
||||
if (Overflowed)
|
||||
return sampleprof_error::counter_overflow;
|
||||
}
|
||||
TargetSamples = SaturatingAdd(TargetSamples, S, &Overflowed);
|
||||
if (Overflowed)
|
||||
return sampleprof_error::counter_overflow;
|
||||
|
||||
return sampleprof_error::success;
|
||||
TargetSamples =
|
||||
SaturatingMultiplyAdd(S, Weight, TargetSamples, &Overflowed);
|
||||
return Overflowed ? sampleprof_error::counter_overflow
|
||||
: sampleprof_error::success;
|
||||
}
|
||||
|
||||
/// Return true if this sample record contains function calls.
|
||||
@ -215,29 +202,17 @@ class FunctionSamples {
|
||||
void dump() const;
|
||||
sampleprof_error addTotalSamples(uint64_t Num, uint64_t Weight = 1) {
|
||||
bool Overflowed;
|
||||
if (Weight > 1) {
|
||||
Num = SaturatingMultiply(Num, Weight, &Overflowed);
|
||||
if (Overflowed)
|
||||
return sampleprof_error::counter_overflow;
|
||||
}
|
||||
TotalSamples = SaturatingAdd(TotalSamples, Num, &Overflowed);
|
||||
if (Overflowed)
|
||||
return sampleprof_error::counter_overflow;
|
||||
|
||||
return sampleprof_error::success;
|
||||
TotalSamples =
|
||||
SaturatingMultiplyAdd(Num, Weight, TotalSamples, &Overflowed);
|
||||
return Overflowed ? sampleprof_error::counter_overflow
|
||||
: sampleprof_error::success;
|
||||
}
|
||||
sampleprof_error addHeadSamples(uint64_t Num, uint64_t Weight = 1) {
|
||||
bool Overflowed;
|
||||
if (Weight > 1) {
|
||||
Num = SaturatingMultiply(Num, Weight, &Overflowed);
|
||||
if (Overflowed)
|
||||
return sampleprof_error::counter_overflow;
|
||||
}
|
||||
TotalHeadSamples = SaturatingAdd(TotalHeadSamples, Num, &Overflowed);
|
||||
if (Overflowed)
|
||||
return sampleprof_error::counter_overflow;
|
||||
|
||||
return sampleprof_error::success;
|
||||
TotalHeadSamples =
|
||||
SaturatingMultiplyAdd(Num, Weight, TotalHeadSamples, &Overflowed);
|
||||
return Overflowed ? sampleprof_error::counter_overflow
|
||||
: sampleprof_error::success;
|
||||
}
|
||||
sampleprof_error addBodySamples(uint32_t LineOffset, uint32_t Discriminator,
|
||||
uint64_t Num, uint64_t Weight = 1) {
|
||||
|
@ -187,6 +187,7 @@ class BumpPtrAllocatorImpl
|
||||
/// \brief Deallocate all but the current slab and reset the current pointer
|
||||
/// to the beginning of it, freeing all memory allocated so far.
|
||||
void Reset() {
|
||||
// Deallocate all but the first slab, and deallocate all custom-sized slabs.
|
||||
DeallocateCustomSizedSlabs();
|
||||
CustomSizedSlabs.clear();
|
||||
|
||||
@ -198,7 +199,7 @@ class BumpPtrAllocatorImpl
|
||||
CurPtr = (char *)Slabs.front();
|
||||
End = CurPtr + SlabSize;
|
||||
|
||||
// Deallocate all but the first slab, and deallocate all custom-sized slabs.
|
||||
__asan_poison_memory_region(*Slabs.begin(), computeSlabSize(0));
|
||||
DeallocateSlabs(std::next(Slabs.begin()), Slabs.end());
|
||||
Slabs.erase(std::next(Slabs.begin()), Slabs.end());
|
||||
}
|
||||
|
@ -656,6 +656,15 @@ namespace COFF {
|
||||
}
|
||||
};
|
||||
|
||||
enum CodeViewLine : unsigned {
|
||||
CVL_LineNumberStartBits = 24,
|
||||
CVL_LineNumberEndDeltaBits = 7,
|
||||
CVL_LineNumberEndDeltaMask = (1U << CVL_LineNumberEndDeltaBits) - 1,
|
||||
CVL_MaxLineNumber = (1U << CVL_LineNumberStartBits) - 1,
|
||||
CVL_IsStatement = 1U << 31,
|
||||
CVL_MaxColumnNumber = UINT16_MAX,
|
||||
};
|
||||
|
||||
enum CodeViewIdentifiers {
|
||||
DEBUG_LINE_TABLES_HAVE_COLUMN_RECORDS = 0x1,
|
||||
DEBUG_SECTION_MAGIC = 0x4,
|
||||
|
@ -309,7 +309,12 @@ enum {
|
||||
EM_COOL = 217, // iCelero CoolEngine
|
||||
EM_NORC = 218, // Nanoradio Optimized RISC
|
||||
EM_CSR_KALIMBA = 219, // CSR Kalimba architecture family
|
||||
EM_AMDGPU = 224 // AMD GPU architecture
|
||||
EM_AMDGPU = 224, // AMD GPU architecture
|
||||
|
||||
// A request has been made to the maintainer of the official registry for
|
||||
// such numbers for an official value for WebAssembly. As soon as one is
|
||||
// allocated, this enum will be updated to use it.
|
||||
EM_WEBASSEMBLY = 0x4157, // WebAssembly architecture
|
||||
};
|
||||
|
||||
// Object file classes.
|
||||
@ -594,6 +599,11 @@ enum {
|
||||
#include "ELFRelocs/Sparc.def"
|
||||
};
|
||||
|
||||
// ELF Relocation types for WebAssembly
|
||||
enum {
|
||||
#include "ELFRelocs/WebAssembly.def"
|
||||
};
|
||||
|
||||
#undef ELF_RELOC
|
||||
|
||||
// Section header.
|
||||
@ -1024,7 +1034,10 @@ enum {
|
||||
PT_AMDGPU_HSA_LOAD_GLOBAL_PROGRAM = 0x60000000,
|
||||
PT_AMDGPU_HSA_LOAD_GLOBAL_AGENT = 0x60000001,
|
||||
PT_AMDGPU_HSA_LOAD_READONLY_AGENT = 0x60000002,
|
||||
PT_AMDGPU_HSA_LOAD_CODE_AGENT = 0x60000003
|
||||
PT_AMDGPU_HSA_LOAD_CODE_AGENT = 0x60000003,
|
||||
|
||||
// WebAssembly program header types.
|
||||
PT_WEBASSEMBLY_FUNCTIONS = PT_LOPROC + 0, // Function definitions.
|
||||
};
|
||||
|
||||
// Segment flag bits.
|
||||
|
@ -0,0 +1,8 @@
|
||||
|
||||
#ifndef ELF_RELOC
|
||||
#error "ELF_RELOC must be defined"
|
||||
#endif
|
||||
|
||||
ELF_RELOC(R_WEBASSEMBLY_NONE, 0)
|
||||
ELF_RELOC(R_WEBASSEMBLY_DATA, 1)
|
||||
ELF_RELOC(R_WEBASSEMBLY_FUNCTION, 2)
|
@ -724,25 +724,17 @@ template <class NodeT> class DominatorTreeBase : public DominatorBase<NodeT> {
|
||||
if (!this->IsPostDominators) {
|
||||
// Initialize root
|
||||
NodeT *entry = TraitsTy::getEntryNode(&F);
|
||||
this->Roots.push_back(entry);
|
||||
this->IDoms[entry] = nullptr;
|
||||
this->DomTreeNodes[entry] = nullptr;
|
||||
addRoot(entry);
|
||||
|
||||
Calculate<FT, NodeT *>(*this, F);
|
||||
} else {
|
||||
// Initialize the roots list
|
||||
for (typename TraitsTy::nodes_iterator I = TraitsTy::nodes_begin(&F),
|
||||
E = TraitsTy::nodes_end(&F);
|
||||
I != E; ++I) {
|
||||
I != E; ++I)
|
||||
if (TraitsTy::child_begin(&*I) == TraitsTy::child_end(&*I))
|
||||
addRoot(&*I);
|
||||
|
||||
// Prepopulate maps so that we don't get iterator invalidation issues
|
||||
// later.
|
||||
this->IDoms[&*I] = nullptr;
|
||||
this->DomTreeNodes[&*I] = nullptr;
|
||||
}
|
||||
|
||||
Calculate<FT, Inverse<NodeT *>>(*this, F);
|
||||
}
|
||||
}
|
||||
|
@ -717,6 +717,25 @@ SaturatingMultiply(T X, T Y, bool *ResultOverflowed = nullptr) {
|
||||
return Z;
|
||||
}
|
||||
|
||||
/// \brief Multiply two unsigned integers, X and Y, and add the unsigned
|
||||
/// integer, A to the product. Clamp the result to the maximum representable
|
||||
/// value of T on overflow. ResultOverflowed indicates if the result is larger
|
||||
/// than the maximum representable value of type T.
|
||||
/// Note that this is purely a convenience function as there is no distinction
|
||||
/// where overflow occurred in a 'fused' multiply-add for unsigned numbers.
|
||||
template <typename T>
|
||||
typename std::enable_if<std::is_unsigned<T>::value, T>::type
|
||||
SaturatingMultiplyAdd(T X, T Y, T A, bool *ResultOverflowed = nullptr) {
|
||||
bool Dummy;
|
||||
bool &Overflowed = ResultOverflowed ? *ResultOverflowed : Dummy;
|
||||
|
||||
T Product = SaturatingMultiply(X, Y, &Overflowed);
|
||||
if (Overflowed)
|
||||
return Product;
|
||||
|
||||
return SaturatingAdd(A, Product, &Overflowed);
|
||||
}
|
||||
|
||||
extern const float huge_valf;
|
||||
} // End llvm namespace
|
||||
|
||||
|
@ -183,12 +183,20 @@ ModulePass *createBlockExtractorPass();
|
||||
ModulePass *createStripDeadPrototypesPass();
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// createFunctionAttrsPass - This pass discovers functions that do not access
|
||||
/// memory, or only read memory, and gives them the readnone/readonly attribute.
|
||||
/// It also discovers function arguments that are not captured by the function
|
||||
/// and marks them with the nocapture attribute.
|
||||
/// createPostOrderFunctionAttrsPass - This pass walks SCCs of the call graph
|
||||
/// in post-order to deduce and propagate function attributes. It can discover
|
||||
/// functions that do not access memory, or only read memory, and give them the
|
||||
/// readnone/readonly attribute. It also discovers function arguments that are
|
||||
/// not captured by the function and marks them with the nocapture attribute.
|
||||
///
|
||||
Pass *createFunctionAttrsPass();
|
||||
Pass *createPostOrderFunctionAttrsPass();
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// createReversePostOrderFunctionAttrsPass - This pass walks SCCs of the call
|
||||
/// graph in RPO to deduce and propagate function attributes. Currently it
|
||||
/// only handles synthesizing norecurse attributes.
|
||||
///
|
||||
Pass *createReversePostOrderFunctionAttrsPass();
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// createMergeFunctionsPass - This pass discovers identical functions and
|
||||
|
@ -147,42 +147,12 @@ void CloneFunctionInto(Function *NewFunc, const Function *OldFunc,
|
||||
ValueMapTypeRemapper *TypeMapper = nullptr,
|
||||
ValueMaterializer *Materializer = nullptr);
|
||||
|
||||
/// A helper class used with CloneAndPruneIntoFromInst to change the default
|
||||
/// behavior while instructions are being cloned.
|
||||
class CloningDirector {
|
||||
public:
|
||||
/// This enumeration describes the way CloneAndPruneIntoFromInst should
|
||||
/// proceed after the CloningDirector has examined an instruction.
|
||||
enum CloningAction {
|
||||
///< Continue cloning the instruction (default behavior).
|
||||
CloneInstruction,
|
||||
///< Skip this instruction but continue cloning the current basic block.
|
||||
SkipInstruction,
|
||||
///< Skip this instruction and stop cloning the current basic block.
|
||||
StopCloningBB,
|
||||
///< Don't clone the terminator but clone the current block's successors.
|
||||
CloneSuccessors
|
||||
};
|
||||
|
||||
virtual ~CloningDirector() {}
|
||||
|
||||
/// Subclasses must override this function to customize cloning behavior.
|
||||
virtual CloningAction handleInstruction(ValueToValueMapTy &VMap,
|
||||
const Instruction *Inst,
|
||||
BasicBlock *NewBB) = 0;
|
||||
|
||||
virtual ValueMapTypeRemapper *getTypeRemapper() { return nullptr; }
|
||||
virtual ValueMaterializer *getValueMaterializer() { return nullptr; }
|
||||
};
|
||||
|
||||
void CloneAndPruneIntoFromInst(Function *NewFunc, const Function *OldFunc,
|
||||
const Instruction *StartingInst,
|
||||
ValueToValueMapTy &VMap, bool ModuleLevelChanges,
|
||||
SmallVectorImpl<ReturnInst*> &Returns,
|
||||
const char *NameSuffix = "",
|
||||
ClonedCodeInfo *CodeInfo = nullptr,
|
||||
CloningDirector *Director = nullptr);
|
||||
|
||||
SmallVectorImpl<ReturnInst *> &Returns,
|
||||
const char *NameSuffix = "",
|
||||
ClonedCodeInfo *CodeInfo = nullptr);
|
||||
|
||||
/// CloneAndPruneFunctionInto - This works exactly like CloneFunctionInto,
|
||||
/// except that it does some simple constant prop and DCE on the fly. The
|
||||
|
@ -42,6 +42,7 @@ class TargetLibraryInfo;
|
||||
class TargetTransformInfo;
|
||||
class DIBuilder;
|
||||
class DominatorTree;
|
||||
class LazyValueInfo;
|
||||
|
||||
template<typename T> class SmallVectorImpl;
|
||||
|
||||
@ -303,7 +304,7 @@ void removeUnwindEdge(BasicBlock *BB);
|
||||
/// \brief Remove all blocks that can not be reached from the function's entry.
|
||||
///
|
||||
/// Returns true if any basic block was removed.
|
||||
bool removeUnreachableBlocks(Function &F);
|
||||
bool removeUnreachableBlocks(Function &F, LazyValueInfo *LVI = nullptr);
|
||||
|
||||
/// \brief Combine the metadata of two instructions so that K can replace J
|
||||
///
|
||||
|
@ -207,6 +207,7 @@ module LLVM_Utils {
|
||||
textual header "Support/ELFRelocs/Sparc.def"
|
||||
textual header "Support/ELFRelocs/SystemZ.def"
|
||||
textual header "Support/ELFRelocs/x86_64.def"
|
||||
textual header "Support/ELFRelocs/WebAssembly.def"
|
||||
}
|
||||
|
||||
// This part of the module is usable from both C and C++ code.
|
||||
|
@ -586,8 +586,13 @@ FunctionModRefBehavior BasicAAResult::getModRefBehavior(const Function *F) {
|
||||
return FunctionModRefBehavior(AAResultBase::getModRefBehavior(F) & Min);
|
||||
}
|
||||
|
||||
ModRefInfo BasicAAResult::getArgModRefInfo(ImmutableCallSite CS,
|
||||
unsigned ArgIdx) {
|
||||
/// Returns true if this is a writeonly (i.e Mod only) parameter. Currently,
|
||||
/// we don't have a writeonly attribute, so this only knows about builtin
|
||||
/// intrinsics and target library functions. We could consider adding a
|
||||
/// writeonly attribute in the future and moving all of these facts to either
|
||||
/// Intrinsics.td or InferFunctionAttr.cpp
|
||||
static bool isWriteOnlyParam(ImmutableCallSite CS, unsigned ArgIdx,
|
||||
const TargetLibraryInfo &TLI) {
|
||||
if (const IntrinsicInst *II = dyn_cast<IntrinsicInst>(CS.getInstruction()))
|
||||
switch (II->getIntrinsicID()) {
|
||||
default:
|
||||
@ -597,9 +602,9 @@ ModRefInfo BasicAAResult::getArgModRefInfo(ImmutableCallSite CS,
|
||||
case Intrinsic::memmove:
|
||||
// We don't currently have a writeonly attribute. All other properties
|
||||
// of these intrinsics are nicely described via attributes in
|
||||
// Intrinsics.td and handled generically below.
|
||||
// Intrinsics.td and handled generically.
|
||||
if (ArgIdx == 0)
|
||||
return MRI_Mod;
|
||||
return true;
|
||||
}
|
||||
|
||||
// We can bound the aliasing properties of memset_pattern16 just as we can
|
||||
@ -609,7 +614,22 @@ ModRefInfo BasicAAResult::getArgModRefInfo(ImmutableCallSite CS,
|
||||
// handled via InferFunctionAttr.
|
||||
if (CS.getCalledFunction() && isMemsetPattern16(CS.getCalledFunction(), TLI))
|
||||
if (ArgIdx == 0)
|
||||
return MRI_Mod;
|
||||
return true;
|
||||
|
||||
// TODO: memset_pattern4, memset_pattern8
|
||||
// TODO: _chk variants
|
||||
// TODO: strcmp, strcpy
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
ModRefInfo BasicAAResult::getArgModRefInfo(ImmutableCallSite CS,
|
||||
unsigned ArgIdx) {
|
||||
|
||||
// Emulate the missing writeonly attribute by checking for known builtin
|
||||
// intrinsics and target library functions.
|
||||
if (isWriteOnlyParam(CS, ArgIdx, TLI))
|
||||
return MRI_Mod;
|
||||
|
||||
if (CS.paramHasAttr(ArgIdx + 1, Attribute::ReadOnly))
|
||||
return MRI_Ref;
|
||||
|
@ -612,9 +612,10 @@ namespace {
|
||||
bool runOnSCC(CallGraphSCC &SCC) override {
|
||||
Out << Banner;
|
||||
for (CallGraphNode *CGN : SCC) {
|
||||
if (CGN->getFunction())
|
||||
CGN->getFunction()->print(Out);
|
||||
else
|
||||
if (CGN->getFunction()) {
|
||||
if (isFunctionInPrintList(CGN->getFunction()->getName()))
|
||||
CGN->getFunction()->print(Out);
|
||||
} else
|
||||
Out << "\nPrinting <null> Function\n";
|
||||
}
|
||||
return false;
|
||||
|
@ -358,21 +358,6 @@ bool GlobalsAAResult::AnalyzeUsesOfPointer(Value *V,
|
||||
if (CS.isArgOperand(&U) && isFreeCall(I, &TLI)) {
|
||||
if (Writers)
|
||||
Writers->insert(CS->getParent()->getParent());
|
||||
} else if (CS.doesNotCapture(CS.getDataOperandNo(&U))) {
|
||||
Function *ParentF = CS->getParent()->getParent();
|
||||
// A nocapture argument may be read from or written to, but does not
|
||||
// escape unless the call can somehow recurse.
|
||||
//
|
||||
// nocapture "indicates that the callee does not make any copies of
|
||||
// the pointer that outlive itself". Therefore if we directly or
|
||||
// indirectly recurse, we must treat the pointer as escaping.
|
||||
if (FunctionToSCCMap[ParentF] ==
|
||||
FunctionToSCCMap[CS.getCalledFunction()])
|
||||
return true;
|
||||
if (Readers)
|
||||
Readers->insert(ParentF);
|
||||
if (Writers)
|
||||
Writers->insert(ParentF);
|
||||
} else {
|
||||
return true; // Argument of an unknown call.
|
||||
}
|
||||
|
@ -70,7 +70,7 @@ static Value *SimplifyOrInst(Value *, Value *, const Query &, unsigned);
|
||||
static Value *SimplifyXorInst(Value *, Value *, const Query &, unsigned);
|
||||
static Value *SimplifyTruncInst(Value *, Type *, const Query &, unsigned);
|
||||
|
||||
/// getFalse - For a boolean type, or a vector of boolean type, return false, or
|
||||
/// For a boolean type, or a vector of boolean type, return false, or
|
||||
/// a vector with every element false, as appropriate for the type.
|
||||
static Constant *getFalse(Type *Ty) {
|
||||
assert(Ty->getScalarType()->isIntegerTy(1) &&
|
||||
@ -78,7 +78,7 @@ static Constant *getFalse(Type *Ty) {
|
||||
return Constant::getNullValue(Ty);
|
||||
}
|
||||
|
||||
/// getTrue - For a boolean type, or a vector of boolean type, return true, or
|
||||
/// For a boolean type, or a vector of boolean type, return true, or
|
||||
/// a vector with every element true, as appropriate for the type.
|
||||
static Constant *getTrue(Type *Ty) {
|
||||
assert(Ty->getScalarType()->isIntegerTy(1) &&
|
||||
@ -100,7 +100,7 @@ static bool isSameCompare(Value *V, CmpInst::Predicate Pred, Value *LHS,
|
||||
CRHS == LHS;
|
||||
}
|
||||
|
||||
/// ValueDominatesPHI - Does the given value dominate the specified phi node?
|
||||
/// Does the given value dominate the specified phi node?
|
||||
static bool ValueDominatesPHI(Value *V, PHINode *P, const DominatorTree *DT) {
|
||||
Instruction *I = dyn_cast<Instruction>(V);
|
||||
if (!I)
|
||||
@ -131,8 +131,8 @@ static bool ValueDominatesPHI(Value *V, PHINode *P, const DominatorTree *DT) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/// ExpandBinOp - Simplify "A op (B op' C)" by distributing op over op', turning
|
||||
/// it into "(A op B) op' (A op C)". Here "op" is given by Opcode and "op'" is
|
||||
/// Simplify "A op (B op' C)" by distributing op over op', turning it into
|
||||
/// "(A op B) op' (A op C)". Here "op" is given by Opcode and "op'" is
|
||||
/// given by OpcodeToExpand, while "A" corresponds to LHS and "B op' C" to RHS.
|
||||
/// Also performs the transform "(A op' B) op C" -> "(A op C) op' (B op C)".
|
||||
/// Returns the simplified value, or null if no simplification was performed.
|
||||
@ -193,8 +193,8 @@ static Value *ExpandBinOp(unsigned Opcode, Value *LHS, Value *RHS,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/// SimplifyAssociativeBinOp - Generic simplifications for associative binary
|
||||
/// operations. Returns the simpler value, or null if none was found.
|
||||
/// Generic simplifications for associative binary operations.
|
||||
/// Returns the simpler value, or null if none was found.
|
||||
static Value *SimplifyAssociativeBinOp(unsigned Opc, Value *LHS, Value *RHS,
|
||||
const Query &Q, unsigned MaxRecurse) {
|
||||
Instruction::BinaryOps Opcode = (Instruction::BinaryOps)Opc;
|
||||
@ -290,10 +290,10 @@ static Value *SimplifyAssociativeBinOp(unsigned Opc, Value *LHS, Value *RHS,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/// ThreadBinOpOverSelect - In the case of a binary operation with a select
|
||||
/// instruction as an operand, try to simplify the binop by seeing whether
|
||||
/// evaluating it on both branches of the select results in the same value.
|
||||
/// Returns the common value if so, otherwise returns null.
|
||||
/// In the case of a binary operation with a select instruction as an operand,
|
||||
/// try to simplify the binop by seeing whether evaluating it on both branches
|
||||
/// of the select results in the same value. Returns the common value if so,
|
||||
/// otherwise returns null.
|
||||
static Value *ThreadBinOpOverSelect(unsigned Opcode, Value *LHS, Value *RHS,
|
||||
const Query &Q, unsigned MaxRecurse) {
|
||||
// Recursion is always used, so bail out at once if we already hit the limit.
|
||||
@ -362,10 +362,9 @@ static Value *ThreadBinOpOverSelect(unsigned Opcode, Value *LHS, Value *RHS,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/// ThreadCmpOverSelect - In the case of a comparison with a select instruction,
|
||||
/// try to simplify the comparison by seeing whether both branches of the select
|
||||
/// result in the same value. Returns the common value if so, otherwise returns
|
||||
/// null.
|
||||
/// In the case of a comparison with a select instruction, try to simplify the
|
||||
/// comparison by seeing whether both branches of the select result in the same
|
||||
/// value. Returns the common value if so, otherwise returns null.
|
||||
static Value *ThreadCmpOverSelect(CmpInst::Predicate Pred, Value *LHS,
|
||||
Value *RHS, const Query &Q,
|
||||
unsigned MaxRecurse) {
|
||||
@ -444,10 +443,10 @@ static Value *ThreadCmpOverSelect(CmpInst::Predicate Pred, Value *LHS,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/// ThreadBinOpOverPHI - In the case of a binary operation with an operand that
|
||||
/// is a PHI instruction, try to simplify the binop by seeing whether evaluating
|
||||
/// it on the incoming phi values yields the same result for every value. If so
|
||||
/// returns the common value, otherwise returns null.
|
||||
/// In the case of a binary operation with an operand that is a PHI instruction,
|
||||
/// try to simplify the binop by seeing whether evaluating it on the incoming
|
||||
/// phi values yields the same result for every value. If so returns the common
|
||||
/// value, otherwise returns null.
|
||||
static Value *ThreadBinOpOverPHI(unsigned Opcode, Value *LHS, Value *RHS,
|
||||
const Query &Q, unsigned MaxRecurse) {
|
||||
// Recursion is always used, so bail out at once if we already hit the limit.
|
||||
@ -486,10 +485,10 @@ static Value *ThreadBinOpOverPHI(unsigned Opcode, Value *LHS, Value *RHS,
|
||||
return CommonValue;
|
||||
}
|
||||
|
||||
/// ThreadCmpOverPHI - In the case of a comparison with a PHI instruction, try
|
||||
/// try to simplify the comparison by seeing whether comparing with all of the
|
||||
/// incoming phi values yields the same result every time. If so returns the
|
||||
/// common result, otherwise returns null.
|
||||
/// In the case of a comparison with a PHI instruction, try to simplify the
|
||||
/// comparison by seeing whether comparing with all of the incoming phi values
|
||||
/// yields the same result every time. If so returns the common result,
|
||||
/// otherwise returns null.
|
||||
static Value *ThreadCmpOverPHI(CmpInst::Predicate Pred, Value *LHS, Value *RHS,
|
||||
const Query &Q, unsigned MaxRecurse) {
|
||||
// Recursion is always used, so bail out at once if we already hit the limit.
|
||||
@ -524,8 +523,8 @@ static Value *ThreadCmpOverPHI(CmpInst::Predicate Pred, Value *LHS, Value *RHS,
|
||||
return CommonValue;
|
||||
}
|
||||
|
||||
/// SimplifyAddInst - Given operands for an Add, see if we can
|
||||
/// fold the result. If not, this returns null.
|
||||
/// Given operands for an Add, see if we can fold the result.
|
||||
/// If not, this returns null.
|
||||
static Value *SimplifyAddInst(Value *Op0, Value *Op1, bool isNSW, bool isNUW,
|
||||
const Query &Q, unsigned MaxRecurse) {
|
||||
if (Constant *CLHS = dyn_cast<Constant>(Op0)) {
|
||||
@ -656,8 +655,8 @@ static Constant *computePointerDifference(const DataLayout &DL, Value *LHS,
|
||||
return ConstantExpr::getSub(LHSOffset, RHSOffset);
|
||||
}
|
||||
|
||||
/// SimplifySubInst - Given operands for a Sub, see if we can
|
||||
/// fold the result. If not, this returns null.
|
||||
/// Given operands for a Sub, see if we can fold the result.
|
||||
/// If not, this returns null.
|
||||
static Value *SimplifySubInst(Value *Op0, Value *Op1, bool isNSW, bool isNUW,
|
||||
const Query &Q, unsigned MaxRecurse) {
|
||||
if (Constant *CLHS = dyn_cast<Constant>(Op0))
|
||||
@ -889,8 +888,8 @@ static Value *SimplifyFMulInst(Value *Op0, Value *Op1,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/// SimplifyMulInst - Given operands for a Mul, see if we can
|
||||
/// fold the result. If not, this returns null.
|
||||
/// Given operands for a Mul, see if we can fold the result.
|
||||
/// If not, this returns null.
|
||||
static Value *SimplifyMulInst(Value *Op0, Value *Op1, const Query &Q,
|
||||
unsigned MaxRecurse) {
|
||||
if (Constant *CLHS = dyn_cast<Constant>(Op0)) {
|
||||
@ -989,8 +988,8 @@ Value *llvm::SimplifyMulInst(Value *Op0, Value *Op1, const DataLayout &DL,
|
||||
RecursionLimit);
|
||||
}
|
||||
|
||||
/// SimplifyDiv - Given operands for an SDiv or UDiv, see if we can
|
||||
/// fold the result. If not, this returns null.
|
||||
/// Given operands for an SDiv or UDiv, see if we can fold the result.
|
||||
/// If not, this returns null.
|
||||
static Value *SimplifyDiv(Instruction::BinaryOps Opcode, Value *Op0, Value *Op1,
|
||||
const Query &Q, unsigned MaxRecurse) {
|
||||
if (Constant *C0 = dyn_cast<Constant>(Op0)) {
|
||||
@ -1075,8 +1074,8 @@ static Value *SimplifyDiv(Instruction::BinaryOps Opcode, Value *Op0, Value *Op1,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/// SimplifySDivInst - Given operands for an SDiv, see if we can
|
||||
/// fold the result. If not, this returns null.
|
||||
/// Given operands for an SDiv, see if we can fold the result.
|
||||
/// If not, this returns null.
|
||||
static Value *SimplifySDivInst(Value *Op0, Value *Op1, const Query &Q,
|
||||
unsigned MaxRecurse) {
|
||||
if (Value *V = SimplifyDiv(Instruction::SDiv, Op0, Op1, Q, MaxRecurse))
|
||||
@ -1093,8 +1092,8 @@ Value *llvm::SimplifySDivInst(Value *Op0, Value *Op1, const DataLayout &DL,
|
||||
RecursionLimit);
|
||||
}
|
||||
|
||||
/// SimplifyUDivInst - Given operands for a UDiv, see if we can
|
||||
/// fold the result. If not, this returns null.
|
||||
/// Given operands for a UDiv, see if we can fold the result.
|
||||
/// If not, this returns null.
|
||||
static Value *SimplifyUDivInst(Value *Op0, Value *Op1, const Query &Q,
|
||||
unsigned MaxRecurse) {
|
||||
if (Value *V = SimplifyDiv(Instruction::UDiv, Op0, Op1, Q, MaxRecurse))
|
||||
@ -1154,8 +1153,8 @@ Value *llvm::SimplifyFDivInst(Value *Op0, Value *Op1, FastMathFlags FMF,
|
||||
RecursionLimit);
|
||||
}
|
||||
|
||||
/// SimplifyRem - Given operands for an SRem or URem, see if we can
|
||||
/// fold the result. If not, this returns null.
|
||||
/// Given operands for an SRem or URem, see if we can fold the result.
|
||||
/// If not, this returns null.
|
||||
static Value *SimplifyRem(Instruction::BinaryOps Opcode, Value *Op0, Value *Op1,
|
||||
const Query &Q, unsigned MaxRecurse) {
|
||||
if (Constant *C0 = dyn_cast<Constant>(Op0)) {
|
||||
@ -1215,8 +1214,8 @@ static Value *SimplifyRem(Instruction::BinaryOps Opcode, Value *Op0, Value *Op1,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/// SimplifySRemInst - Given operands for an SRem, see if we can
|
||||
/// fold the result. If not, this returns null.
|
||||
/// Given operands for an SRem, see if we can fold the result.
|
||||
/// If not, this returns null.
|
||||
static Value *SimplifySRemInst(Value *Op0, Value *Op1, const Query &Q,
|
||||
unsigned MaxRecurse) {
|
||||
if (Value *V = SimplifyRem(Instruction::SRem, Op0, Op1, Q, MaxRecurse))
|
||||
@ -1233,8 +1232,8 @@ Value *llvm::SimplifySRemInst(Value *Op0, Value *Op1, const DataLayout &DL,
|
||||
RecursionLimit);
|
||||
}
|
||||
|
||||
/// SimplifyURemInst - Given operands for a URem, see if we can
|
||||
/// fold the result. If not, this returns null.
|
||||
/// Given operands for a URem, see if we can fold the result.
|
||||
/// If not, this returns null.
|
||||
static Value *SimplifyURemInst(Value *Op0, Value *Op1, const Query &Q,
|
||||
unsigned MaxRecurse) {
|
||||
if (Value *V = SimplifyRem(Instruction::URem, Op0, Op1, Q, MaxRecurse))
|
||||
@ -1279,7 +1278,7 @@ Value *llvm::SimplifyFRemInst(Value *Op0, Value *Op1, FastMathFlags FMF,
|
||||
RecursionLimit);
|
||||
}
|
||||
|
||||
/// isUndefShift - Returns true if a shift by \c Amount always yields undef.
|
||||
/// Returns true if a shift by \c Amount always yields undef.
|
||||
static bool isUndefShift(Value *Amount) {
|
||||
Constant *C = dyn_cast<Constant>(Amount);
|
||||
if (!C)
|
||||
@ -1306,8 +1305,8 @@ static bool isUndefShift(Value *Amount) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/// SimplifyShift - Given operands for an Shl, LShr or AShr, see if we can
|
||||
/// fold the result. If not, this returns null.
|
||||
/// Given operands for an Shl, LShr or AShr, see if we can fold the result.
|
||||
/// If not, this returns null.
|
||||
static Value *SimplifyShift(unsigned Opcode, Value *Op0, Value *Op1,
|
||||
const Query &Q, unsigned MaxRecurse) {
|
||||
if (Constant *C0 = dyn_cast<Constant>(Op0)) {
|
||||
@ -1375,8 +1374,8 @@ static Value *SimplifyRightShift(unsigned Opcode, Value *Op0, Value *Op1,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/// SimplifyShlInst - Given operands for an Shl, see if we can
|
||||
/// fold the result. If not, this returns null.
|
||||
/// Given operands for an Shl, see if we can fold the result.
|
||||
/// If not, this returns null.
|
||||
static Value *SimplifyShlInst(Value *Op0, Value *Op1, bool isNSW, bool isNUW,
|
||||
const Query &Q, unsigned MaxRecurse) {
|
||||
if (Value *V = SimplifyShift(Instruction::Shl, Op0, Op1, Q, MaxRecurse))
|
||||
@ -1402,8 +1401,8 @@ Value *llvm::SimplifyShlInst(Value *Op0, Value *Op1, bool isNSW, bool isNUW,
|
||||
RecursionLimit);
|
||||
}
|
||||
|
||||
/// SimplifyLShrInst - Given operands for an LShr, see if we can
|
||||
/// fold the result. If not, this returns null.
|
||||
/// Given operands for an LShr, see if we can fold the result.
|
||||
/// If not, this returns null.
|
||||
static Value *SimplifyLShrInst(Value *Op0, Value *Op1, bool isExact,
|
||||
const Query &Q, unsigned MaxRecurse) {
|
||||
if (Value *V = SimplifyRightShift(Instruction::LShr, Op0, Op1, isExact, Q,
|
||||
@ -1427,8 +1426,8 @@ Value *llvm::SimplifyLShrInst(Value *Op0, Value *Op1, bool isExact,
|
||||
RecursionLimit);
|
||||
}
|
||||
|
||||
/// SimplifyAShrInst - Given operands for an AShr, see if we can
|
||||
/// fold the result. If not, this returns null.
|
||||
/// Given operands for an AShr, see if we can fold the result.
|
||||
/// If not, this returns null.
|
||||
static Value *SimplifyAShrInst(Value *Op0, Value *Op1, bool isExact,
|
||||
const Query &Q, unsigned MaxRecurse) {
|
||||
if (Value *V = SimplifyRightShift(Instruction::AShr, Op0, Op1, isExact, Q,
|
||||
@ -1502,8 +1501,8 @@ static Value *simplifyUnsignedRangeCheck(ICmpInst *ZeroICmp,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Simplify (and (icmp ...) (icmp ...)) to true when we can tell that the range
|
||||
// of possible values cannot be satisfied.
|
||||
/// Simplify (and (icmp ...) (icmp ...)) to true when we can tell that the range
|
||||
/// of possible values cannot be satisfied.
|
||||
static Value *SimplifyAndOfICmps(ICmpInst *Op0, ICmpInst *Op1) {
|
||||
ICmpInst::Predicate Pred0, Pred1;
|
||||
ConstantInt *CI1, *CI2;
|
||||
@ -1554,8 +1553,8 @@ static Value *SimplifyAndOfICmps(ICmpInst *Op0, ICmpInst *Op1) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/// SimplifyAndInst - Given operands for an And, see if we can
|
||||
/// fold the result. If not, this returns null.
|
||||
/// Given operands for an And, see if we can fold the result.
|
||||
/// If not, this returns null.
|
||||
static Value *SimplifyAndInst(Value *Op0, Value *Op1, const Query &Q,
|
||||
unsigned MaxRecurse) {
|
||||
if (Constant *CLHS = dyn_cast<Constant>(Op0)) {
|
||||
@ -1661,8 +1660,8 @@ Value *llvm::SimplifyAndInst(Value *Op0, Value *Op1, const DataLayout &DL,
|
||||
RecursionLimit);
|
||||
}
|
||||
|
||||
// Simplify (or (icmp ...) (icmp ...)) to true when we can tell that the union
|
||||
// contains all possible values.
|
||||
/// Simplify (or (icmp ...) (icmp ...)) to true when we can tell that the union
|
||||
/// contains all possible values.
|
||||
static Value *SimplifyOrOfICmps(ICmpInst *Op0, ICmpInst *Op1) {
|
||||
ICmpInst::Predicate Pred0, Pred1;
|
||||
ConstantInt *CI1, *CI2;
|
||||
@ -1713,8 +1712,8 @@ static Value *SimplifyOrOfICmps(ICmpInst *Op0, ICmpInst *Op1) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/// SimplifyOrInst - Given operands for an Or, see if we can
|
||||
/// fold the result. If not, this returns null.
|
||||
/// Given operands for an Or, see if we can fold the result.
|
||||
/// If not, this returns null.
|
||||
static Value *SimplifyOrInst(Value *Op0, Value *Op1, const Query &Q,
|
||||
unsigned MaxRecurse) {
|
||||
if (Constant *CLHS = dyn_cast<Constant>(Op0)) {
|
||||
@ -1849,8 +1848,8 @@ Value *llvm::SimplifyOrInst(Value *Op0, Value *Op1, const DataLayout &DL,
|
||||
RecursionLimit);
|
||||
}
|
||||
|
||||
/// SimplifyXorInst - Given operands for a Xor, see if we can
|
||||
/// fold the result. If not, this returns null.
|
||||
/// Given operands for a Xor, see if we can fold the result.
|
||||
/// If not, this returns null.
|
||||
static Value *SimplifyXorInst(Value *Op0, Value *Op1, const Query &Q,
|
||||
unsigned MaxRecurse) {
|
||||
if (Constant *CLHS = dyn_cast<Constant>(Op0)) {
|
||||
@ -1910,9 +1909,9 @@ static Type *GetCompareTy(Value *Op) {
|
||||
return CmpInst::makeCmpResultType(Op->getType());
|
||||
}
|
||||
|
||||
/// ExtractEquivalentCondition - Rummage around inside V looking for something
|
||||
/// equivalent to the comparison "LHS Pred RHS". Return such a value if found,
|
||||
/// otherwise return null. Helper function for analyzing max/min idioms.
|
||||
/// Rummage around inside V looking for something equivalent to the comparison
|
||||
/// "LHS Pred RHS". Return such a value if found, otherwise return null.
|
||||
/// Helper function for analyzing max/min idioms.
|
||||
static Value *ExtractEquivalentCondition(Value *V, CmpInst::Predicate Pred,
|
||||
Value *LHS, Value *RHS) {
|
||||
SelectInst *SI = dyn_cast<SelectInst>(V);
|
||||
@ -2100,21 +2099,17 @@ static Constant *computePointerICmp(const DataLayout &DL,
|
||||
// that might be resolve lazily to symbols in another dynamically-loaded
|
||||
// library (and, thus, could be malloc'ed by the implementation).
|
||||
auto IsAllocDisjoint = [](SmallVectorImpl<Value *> &Objects) {
|
||||
return std::all_of(Objects.begin(), Objects.end(),
|
||||
[](Value *V){
|
||||
if (const AllocaInst *AI = dyn_cast<AllocaInst>(V))
|
||||
return AI->getParent() && AI->getParent()->getParent() &&
|
||||
AI->isStaticAlloca();
|
||||
if (const GlobalValue *GV = dyn_cast<GlobalValue>(V))
|
||||
return (GV->hasLocalLinkage() ||
|
||||
GV->hasHiddenVisibility() ||
|
||||
GV->hasProtectedVisibility() ||
|
||||
GV->hasUnnamedAddr()) &&
|
||||
!GV->isThreadLocal();
|
||||
if (const Argument *A = dyn_cast<Argument>(V))
|
||||
return A->hasByValAttr();
|
||||
return false;
|
||||
});
|
||||
return std::all_of(Objects.begin(), Objects.end(), [](Value *V) {
|
||||
if (const AllocaInst *AI = dyn_cast<AllocaInst>(V))
|
||||
return AI->getParent() && AI->getFunction() && AI->isStaticAlloca();
|
||||
if (const GlobalValue *GV = dyn_cast<GlobalValue>(V))
|
||||
return (GV->hasLocalLinkage() || GV->hasHiddenVisibility() ||
|
||||
GV->hasProtectedVisibility() || GV->hasUnnamedAddr()) &&
|
||||
!GV->isThreadLocal();
|
||||
if (const Argument *A = dyn_cast<Argument>(V))
|
||||
return A->hasByValAttr();
|
||||
return false;
|
||||
});
|
||||
};
|
||||
|
||||
if ((IsNAC(LHSUObjs) && IsAllocDisjoint(RHSUObjs)) ||
|
||||
@ -2127,8 +2122,8 @@ static Constant *computePointerICmp(const DataLayout &DL,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/// SimplifyICmpInst - Given operands for an ICmpInst, see if we can
|
||||
/// fold the result. If not, this returns null.
|
||||
/// Given operands for an ICmpInst, see if we can fold the result.
|
||||
/// If not, this returns null.
|
||||
static Value *SimplifyICmpInst(unsigned Predicate, Value *LHS, Value *RHS,
|
||||
const Query &Q, unsigned MaxRecurse) {
|
||||
CmpInst::Predicate Pred = (CmpInst::Predicate)Predicate;
|
||||
@ -3102,8 +3097,8 @@ Value *llvm::SimplifyICmpInst(unsigned Predicate, Value *LHS, Value *RHS,
|
||||
RecursionLimit);
|
||||
}
|
||||
|
||||
/// SimplifyFCmpInst - Given operands for an FCmpInst, see if we can
|
||||
/// fold the result. If not, this returns null.
|
||||
/// Given operands for an FCmpInst, see if we can fold the result.
|
||||
/// If not, this returns null.
|
||||
static Value *SimplifyFCmpInst(unsigned Predicate, Value *LHS, Value *RHS,
|
||||
FastMathFlags FMF, const Query &Q,
|
||||
unsigned MaxRecurse) {
|
||||
@ -3227,8 +3222,7 @@ Value *llvm::SimplifyFCmpInst(unsigned Predicate, Value *LHS, Value *RHS,
|
||||
Query(DL, TLI, DT, AC, CxtI), RecursionLimit);
|
||||
}
|
||||
|
||||
/// SimplifyWithOpReplaced - See if V simplifies when its operand Op is
|
||||
/// replaced with RepOp.
|
||||
/// See if V simplifies when its operand Op is replaced with RepOp.
|
||||
static const Value *SimplifyWithOpReplaced(Value *V, Value *Op, Value *RepOp,
|
||||
const Query &Q,
|
||||
unsigned MaxRecurse) {
|
||||
@ -3311,8 +3305,8 @@ static const Value *SimplifyWithOpReplaced(Value *V, Value *Op, Value *RepOp,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/// SimplifySelectInst - Given operands for a SelectInst, see if we can fold
|
||||
/// the result. If not, this returns null.
|
||||
/// Given operands for a SelectInst, see if we can fold the result.
|
||||
/// If not, this returns null.
|
||||
static Value *SimplifySelectInst(Value *CondVal, Value *TrueVal,
|
||||
Value *FalseVal, const Query &Q,
|
||||
unsigned MaxRecurse) {
|
||||
@ -3449,8 +3443,8 @@ Value *llvm::SimplifySelectInst(Value *Cond, Value *TrueVal, Value *FalseVal,
|
||||
Query(DL, TLI, DT, AC, CxtI), RecursionLimit);
|
||||
}
|
||||
|
||||
/// SimplifyGEPInst - Given operands for an GetElementPtrInst, see if we can
|
||||
/// fold the result. If not, this returns null.
|
||||
/// Given operands for an GetElementPtrInst, see if we can fold the result.
|
||||
/// If not, this returns null.
|
||||
static Value *SimplifyGEPInst(Type *SrcTy, ArrayRef<Value *> Ops,
|
||||
const Query &Q, unsigned) {
|
||||
// The type of the GEP pointer operand.
|
||||
@ -3542,8 +3536,8 @@ Value *llvm::SimplifyGEPInst(ArrayRef<Value *> Ops, const DataLayout &DL,
|
||||
Ops, Query(DL, TLI, DT, AC, CxtI), RecursionLimit);
|
||||
}
|
||||
|
||||
/// SimplifyInsertValueInst - Given operands for an InsertValueInst, see if we
|
||||
/// can fold the result. If not, this returns null.
|
||||
/// Given operands for an InsertValueInst, see if we can fold the result.
|
||||
/// If not, this returns null.
|
||||
static Value *SimplifyInsertValueInst(Value *Agg, Value *Val,
|
||||
ArrayRef<unsigned> Idxs, const Query &Q,
|
||||
unsigned) {
|
||||
@ -3579,8 +3573,8 @@ Value *llvm::SimplifyInsertValueInst(
|
||||
RecursionLimit);
|
||||
}
|
||||
|
||||
/// SimplifyExtractValueInst - Given operands for an ExtractValueInst, see if we
|
||||
/// can fold the result. If not, this returns null.
|
||||
/// Given operands for an ExtractValueInst, see if we can fold the result.
|
||||
/// If not, this returns null.
|
||||
static Value *SimplifyExtractValueInst(Value *Agg, ArrayRef<unsigned> Idxs,
|
||||
const Query &, unsigned) {
|
||||
if (auto *CAgg = dyn_cast<Constant>(Agg))
|
||||
@ -3614,8 +3608,8 @@ Value *llvm::SimplifyExtractValueInst(Value *Agg, ArrayRef<unsigned> Idxs,
|
||||
RecursionLimit);
|
||||
}
|
||||
|
||||
/// SimplifyExtractElementInst - Given operands for an ExtractElementInst, see if we
|
||||
/// can fold the result. If not, this returns null.
|
||||
/// Given operands for an ExtractElementInst, see if we can fold the result.
|
||||
/// If not, this returns null.
|
||||
static Value *SimplifyExtractElementInst(Value *Vec, Value *Idx, const Query &,
|
||||
unsigned) {
|
||||
if (auto *CVec = dyn_cast<Constant>(Vec)) {
|
||||
@ -3646,7 +3640,7 @@ Value *llvm::SimplifyExtractElementInst(
|
||||
RecursionLimit);
|
||||
}
|
||||
|
||||
/// SimplifyPHINode - See if we can fold the given phi. If not, returns null.
|
||||
/// See if we can fold the given phi. If not, returns null.
|
||||
static Value *SimplifyPHINode(PHINode *PN, const Query &Q) {
|
||||
// If all of the PHI's incoming values are the same then replace the PHI node
|
||||
// with the common value.
|
||||
@ -3696,8 +3690,8 @@ Value *llvm::SimplifyTruncInst(Value *Op, Type *Ty, const DataLayout &DL,
|
||||
|
||||
//=== Helper functions for higher up the class hierarchy.
|
||||
|
||||
/// SimplifyBinOp - Given operands for a BinaryOperator, see if we can
|
||||
/// fold the result. If not, this returns null.
|
||||
/// Given operands for a BinaryOperator, see if we can fold the result.
|
||||
/// If not, this returns null.
|
||||
static Value *SimplifyBinOp(unsigned Opcode, Value *LHS, Value *RHS,
|
||||
const Query &Q, unsigned MaxRecurse) {
|
||||
switch (Opcode) {
|
||||
@ -3763,8 +3757,8 @@ static Value *SimplifyBinOp(unsigned Opcode, Value *LHS, Value *RHS,
|
||||
}
|
||||
}
|
||||
|
||||
/// SimplifyFPBinOp - Given operands for a BinaryOperator, see if we can
|
||||
/// fold the result. If not, this returns null.
|
||||
/// Given operands for a BinaryOperator, see if we can fold the result.
|
||||
/// If not, this returns null.
|
||||
/// In contrast to SimplifyBinOp, try to use FastMathFlag when folding the
|
||||
/// result. In case we don't need FastMathFlags, simply fall to SimplifyBinOp.
|
||||
static Value *SimplifyFPBinOp(unsigned Opcode, Value *LHS, Value *RHS,
|
||||
@ -3799,8 +3793,7 @@ Value *llvm::SimplifyFPBinOp(unsigned Opcode, Value *LHS, Value *RHS,
|
||||
RecursionLimit);
|
||||
}
|
||||
|
||||
/// SimplifyCmpInst - Given operands for a CmpInst, see if we can
|
||||
/// fold the result.
|
||||
/// Given operands for a CmpInst, see if we can fold the result.
|
||||
static Value *SimplifyCmpInst(unsigned Predicate, Value *LHS, Value *RHS,
|
||||
const Query &Q, unsigned MaxRecurse) {
|
||||
if (CmpInst::isIntPredicate((CmpInst::Predicate)Predicate))
|
||||
@ -3938,8 +3931,8 @@ Value *llvm::SimplifyCall(Value *V, ArrayRef<Value *> Args,
|
||||
Query(DL, TLI, DT, AC, CxtI), RecursionLimit);
|
||||
}
|
||||
|
||||
/// SimplifyInstruction - See if we can compute a simplified version of this
|
||||
/// instruction. If not, this returns null.
|
||||
/// See if we can compute a simplified version of this instruction.
|
||||
/// If not, this returns null.
|
||||
Value *llvm::SimplifyInstruction(Instruction *I, const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI,
|
||||
const DominatorTree *DT, AssumptionCache *AC) {
|
||||
|
@ -845,6 +845,7 @@ int llvm::isStridedPtr(PredicatedScalarEvolution &PSE, Value *Ptr,
|
||||
if (Lp != AR->getLoop()) {
|
||||
DEBUG(dbgs() << "LAA: Bad stride - Not striding over innermost loop " <<
|
||||
*Ptr << " SCEV: " << *PtrScev << "\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// The address calculation must not wrap. Otherwise, a dependence could be
|
||||
|
@ -637,8 +637,10 @@ LoopInfo::LoopInfo(const DominatorTreeBase<BasicBlock> &DomTree) {
|
||||
analyze(DomTree);
|
||||
}
|
||||
|
||||
void LoopInfo::updateUnloop(Loop *Unloop) {
|
||||
Unloop->markUnlooped();
|
||||
void LoopInfo::markAsRemoved(Loop *Unloop) {
|
||||
assert(!Unloop->isInvalid() && "Loop has already been removed");
|
||||
Unloop->invalidate();
|
||||
RemovedLoops.push_back(Unloop);
|
||||
|
||||
// First handle the special case of no parent loop to simplify the algorithm.
|
||||
if (!Unloop->getParentLoop()) {
|
||||
|
@ -42,7 +42,11 @@ class PrintLoopPassWrapper : public LoopPass {
|
||||
}
|
||||
|
||||
bool runOnLoop(Loop *L, LPPassManager &) override {
|
||||
P.run(*L);
|
||||
auto BBI = find_if(L->blocks().begin(), L->blocks().end(),
|
||||
[](BasicBlock *BB) { return BB; });
|
||||
if (BBI != L->blocks().end() &&
|
||||
isFunctionInPrintList((*BBI)->getParent()->getName()))
|
||||
P.run(*L);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
@ -174,8 +178,9 @@ bool LPPassManager::runOnFunction(Function &F) {
|
||||
|
||||
// Walk Loops
|
||||
while (!LQ.empty()) {
|
||||
|
||||
bool LoopWasDeleted = false;
|
||||
CurrentLoop = LQ.back();
|
||||
|
||||
// Run all passes on the current Loop.
|
||||
for (unsigned Index = 0; Index < getNumContainedPasses(); ++Index) {
|
||||
LoopPass *P = getContainedPass(Index);
|
||||
@ -192,15 +197,15 @@ bool LPPassManager::runOnFunction(Function &F) {
|
||||
|
||||
Changed |= P->runOnLoop(CurrentLoop, *this);
|
||||
}
|
||||
LoopWasDeleted = CurrentLoop->isInvalid();
|
||||
|
||||
if (Changed)
|
||||
dumpPassInfo(P, MODIFICATION_MSG, ON_LOOP_MSG,
|
||||
CurrentLoop->isUnloop()
|
||||
? "<deleted>"
|
||||
: CurrentLoop->getHeader()->getName());
|
||||
LoopWasDeleted ? "<deleted>"
|
||||
: CurrentLoop->getHeader()->getName());
|
||||
dumpPreservedSet(P);
|
||||
|
||||
if (CurrentLoop->isUnloop()) {
|
||||
if (LoopWasDeleted) {
|
||||
// Notify passes that the loop is being deleted.
|
||||
deleteSimpleAnalysisLoop(CurrentLoop);
|
||||
} else {
|
||||
@ -222,12 +227,11 @@ bool LPPassManager::runOnFunction(Function &F) {
|
||||
|
||||
removeNotPreservedAnalysis(P);
|
||||
recordAvailableAnalysis(P);
|
||||
removeDeadPasses(P, CurrentLoop->isUnloop()
|
||||
? "<deleted>"
|
||||
: CurrentLoop->getHeader()->getName(),
|
||||
removeDeadPasses(P, LoopWasDeleted ? "<deleted>"
|
||||
: CurrentLoop->getHeader()->getName(),
|
||||
ON_LOOP_MSG);
|
||||
|
||||
if (CurrentLoop->isUnloop())
|
||||
if (LoopWasDeleted)
|
||||
// Do not run other passes on this loop.
|
||||
break;
|
||||
}
|
||||
@ -235,12 +239,11 @@ bool LPPassManager::runOnFunction(Function &F) {
|
||||
// If the loop was deleted, release all the loop passes. This frees up
|
||||
// some memory, and avoids trouble with the pass manager trying to call
|
||||
// verifyAnalysis on them.
|
||||
if (CurrentLoop->isUnloop()) {
|
||||
if (LoopWasDeleted) {
|
||||
for (unsigned Index = 0; Index < getNumContainedPasses(); ++Index) {
|
||||
Pass *P = getContainedPass(Index);
|
||||
freePass(P, "<deleted>", ON_LOOP_MSG);
|
||||
}
|
||||
delete CurrentLoop;
|
||||
}
|
||||
|
||||
// Pop the loop from queue after running all passes.
|
||||
|
@ -26,7 +26,7 @@
|
||||
// ... = load %ptr2, !alias.scope !{ !scope1, !scope2 }, !noalias !{ !scope1 }
|
||||
//
|
||||
// When evaluating an aliasing query, if one of the instructions is associated
|
||||
// has a set of noalias scopes in some domain that is superset of the alias
|
||||
// has a set of noalias scopes in some domain that is a superset of the alias
|
||||
// scopes in that domain of some other instruction, then the two memory
|
||||
// accesses are assumed not to alias.
|
||||
//
|
||||
|
@ -70,7 +70,7 @@
|
||||
// A a;
|
||||
// } B;
|
||||
//
|
||||
// For an acess to B.a.s, we attach !5 (a path tag node) to the load/store
|
||||
// For an access to B.a.s, we attach !5 (a path tag node) to the load/store
|
||||
// instruction. The base type is !4 (struct B), the access type is !2 (scalar
|
||||
// type short) and the offset is 4.
|
||||
//
|
||||
|
@ -2556,6 +2556,9 @@ bool llvm::CannotBeOrderedLessThanZero(const Value *V, unsigned Depth) {
|
||||
|
||||
switch (I->getOpcode()) {
|
||||
default: break;
|
||||
// Unsigned integers are always nonnegative.
|
||||
case Instruction::UIToFP:
|
||||
return true;
|
||||
case Instruction::FMul:
|
||||
// x*x is always non-negative or a NaN.
|
||||
if (I->getOperand(0) == I->getOperand(1))
|
||||
@ -2566,6 +2569,9 @@ bool llvm::CannotBeOrderedLessThanZero(const Value *V, unsigned Depth) {
|
||||
case Instruction::FRem:
|
||||
return CannotBeOrderedLessThanZero(I->getOperand(0), Depth+1) &&
|
||||
CannotBeOrderedLessThanZero(I->getOperand(1), Depth+1);
|
||||
case Instruction::Select:
|
||||
return CannotBeOrderedLessThanZero(I->getOperand(1), Depth+1) &&
|
||||
CannotBeOrderedLessThanZero(I->getOperand(2), Depth+1);
|
||||
case Instruction::FPExt:
|
||||
case Instruction::FPTrunc:
|
||||
// Widening/narrowing never change sign.
|
||||
@ -2574,6 +2580,12 @@ bool llvm::CannotBeOrderedLessThanZero(const Value *V, unsigned Depth) {
|
||||
if (const IntrinsicInst *II = dyn_cast<IntrinsicInst>(I))
|
||||
switch (II->getIntrinsicID()) {
|
||||
default: break;
|
||||
case Intrinsic::maxnum:
|
||||
return CannotBeOrderedLessThanZero(I->getOperand(0), Depth+1) ||
|
||||
CannotBeOrderedLessThanZero(I->getOperand(1), Depth+1);
|
||||
case Intrinsic::minnum:
|
||||
return CannotBeOrderedLessThanZero(I->getOperand(0), Depth+1) &&
|
||||
CannotBeOrderedLessThanZero(I->getOperand(1), Depth+1);
|
||||
case Intrinsic::exp:
|
||||
case Intrinsic::exp2:
|
||||
case Intrinsic::fabs:
|
||||
|
@ -2654,8 +2654,6 @@ std::error_code BitcodeReader::parseConstants() {
|
||||
return error("Invalid record");
|
||||
|
||||
Type *EltTy = cast<SequentialType>(CurTy)->getElementType();
|
||||
unsigned Size = Record.size();
|
||||
|
||||
if (EltTy->isIntegerTy(8)) {
|
||||
SmallVector<uint8_t, 16> Elts(Record.begin(), Record.end());
|
||||
if (isa<VectorType>(CurTy))
|
||||
@ -2680,21 +2678,24 @@ std::error_code BitcodeReader::parseConstants() {
|
||||
V = ConstantDataVector::get(Context, Elts);
|
||||
else
|
||||
V = ConstantDataArray::get(Context, Elts);
|
||||
} else if (EltTy->isHalfTy()) {
|
||||
SmallVector<uint16_t, 16> Elts(Record.begin(), Record.end());
|
||||
if (isa<VectorType>(CurTy))
|
||||
V = ConstantDataVector::getFP(Context, Elts);
|
||||
else
|
||||
V = ConstantDataArray::getFP(Context, Elts);
|
||||
} else if (EltTy->isFloatTy()) {
|
||||
SmallVector<float, 16> Elts(Size);
|
||||
std::transform(Record.begin(), Record.end(), Elts.begin(), BitsToFloat);
|
||||
SmallVector<uint32_t, 16> Elts(Record.begin(), Record.end());
|
||||
if (isa<VectorType>(CurTy))
|
||||
V = ConstantDataVector::get(Context, Elts);
|
||||
V = ConstantDataVector::getFP(Context, Elts);
|
||||
else
|
||||
V = ConstantDataArray::get(Context, Elts);
|
||||
V = ConstantDataArray::getFP(Context, Elts);
|
||||
} else if (EltTy->isDoubleTy()) {
|
||||
SmallVector<double, 16> Elts(Size);
|
||||
std::transform(Record.begin(), Record.end(), Elts.begin(),
|
||||
BitsToDouble);
|
||||
SmallVector<uint64_t, 16> Elts(Record.begin(), Record.end());
|
||||
if (isa<VectorType>(CurTy))
|
||||
V = ConstantDataVector::get(Context, Elts);
|
||||
V = ConstantDataVector::getFP(Context, Elts);
|
||||
else
|
||||
V = ConstantDataArray::get(Context, Elts);
|
||||
V = ConstantDataArray::getFP(Context, Elts);
|
||||
} else {
|
||||
return error("Invalid type for value");
|
||||
}
|
||||
|
@ -1630,19 +1630,10 @@ static void WriteConstants(unsigned FirstVal, unsigned LastVal,
|
||||
if (isa<IntegerType>(EltTy)) {
|
||||
for (unsigned i = 0, e = CDS->getNumElements(); i != e; ++i)
|
||||
Record.push_back(CDS->getElementAsInteger(i));
|
||||
} else if (EltTy->isFloatTy()) {
|
||||
for (unsigned i = 0, e = CDS->getNumElements(); i != e; ++i) {
|
||||
union { float F; uint32_t I; };
|
||||
F = CDS->getElementAsFloat(i);
|
||||
Record.push_back(I);
|
||||
}
|
||||
} else {
|
||||
assert(EltTy->isDoubleTy() && "Unknown ConstantData element type");
|
||||
for (unsigned i = 0, e = CDS->getNumElements(); i != e; ++i) {
|
||||
union { double F; uint64_t I; };
|
||||
F = CDS->getElementAsDouble(i);
|
||||
Record.push_back(I);
|
||||
}
|
||||
for (unsigned i = 0, e = CDS->getNumElements(); i != e; ++i)
|
||||
Record.push_back(
|
||||
CDS->getElementAsAPFloat(i).bitcastToAPInt().getLimitedValue());
|
||||
}
|
||||
} else if (isa<ConstantArray>(C) || isa<ConstantStruct>(C) ||
|
||||
isa<ConstantVector>(C)) {
|
||||
|
@ -192,22 +192,26 @@ bool AsmPrinter::doInitialization(Module &M) {
|
||||
// use the directive, where it would need the same conditionalization
|
||||
// anyway.
|
||||
Triple TT(getTargetTriple());
|
||||
if (TT.isOSDarwin()) {
|
||||
// If there is a version specified, Major will be non-zero.
|
||||
if (TT.isOSDarwin() && TT.getOSMajorVersion() != 0) {
|
||||
unsigned Major, Minor, Update;
|
||||
TT.getOSVersion(Major, Minor, Update);
|
||||
// If there is a version specified, Major will be non-zero.
|
||||
if (Major) {
|
||||
MCVersionMinType VersionType;
|
||||
if (TT.isWatchOS())
|
||||
VersionType = MCVM_WatchOSVersionMin;
|
||||
else if (TT.isTvOS())
|
||||
VersionType = MCVM_TvOSVersionMin;
|
||||
else if (TT.isMacOSX())
|
||||
VersionType = MCVM_OSXVersionMin;
|
||||
else
|
||||
VersionType = MCVM_IOSVersionMin;
|
||||
OutStreamer->EmitVersionMin(VersionType, Major, Minor, Update);
|
||||
MCVersionMinType VersionType;
|
||||
if (TT.isWatchOS()) {
|
||||
VersionType = MCVM_WatchOSVersionMin;
|
||||
TT.getWatchOSVersion(Major, Minor, Update);
|
||||
} else if (TT.isTvOS()) {
|
||||
VersionType = MCVM_TvOSVersionMin;
|
||||
TT.getiOSVersion(Major, Minor, Update);
|
||||
} else if (TT.isMacOSX()) {
|
||||
VersionType = MCVM_OSXVersionMin;
|
||||
if (!TT.getMacOSXVersion(Major, Minor, Update))
|
||||
Major = 0;
|
||||
} else {
|
||||
VersionType = MCVM_IOSVersionMin;
|
||||
TT.getiOSVersion(Major, Minor, Update);
|
||||
}
|
||||
if (Major != 0)
|
||||
OutStreamer->EmitVersionMin(VersionType, Major, Minor, Update);
|
||||
}
|
||||
|
||||
// Allow the target to emit any magic that it wants at the start of the file.
|
||||
|
@ -31,6 +31,39 @@
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
using namespace llvm;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// EmittingAsmStreamer Implementation
|
||||
//===----------------------------------------------------------------------===//
|
||||
unsigned EmittingAsmStreamer::emitULEB128(uint64_t Value, const char *Desc,
|
||||
unsigned PadTo) {
|
||||
AP->EmitULEB128(Value, Desc, PadTo);
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned EmittingAsmStreamer::emitInt8(unsigned char Value) {
|
||||
AP->EmitInt8(Value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned EmittingAsmStreamer::emitBytes(StringRef Data) {
|
||||
AP->OutStreamer->EmitBytes(Data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// SizeReporterAsmStreamer Implementation
|
||||
//===----------------------------------------------------------------------===//
|
||||
unsigned SizeReporterAsmStreamer::emitULEB128(uint64_t Value, const char *Desc,
|
||||
unsigned PadTo) {
|
||||
return getULEB128Size(Value);
|
||||
}
|
||||
|
||||
unsigned SizeReporterAsmStreamer::emitInt8(unsigned char Value) { return 1; }
|
||||
|
||||
unsigned SizeReporterAsmStreamer::emitBytes(StringRef Data) {
|
||||
return Data.size();
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// DIEAbbrevData Implementation
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -561,6 +561,8 @@ void DwarfDebug::finalizeModuleInfo() {
|
||||
// Collect info for variables that were optimized out.
|
||||
collectDeadVariables();
|
||||
|
||||
unsigned MacroOffset = 0;
|
||||
std::unique_ptr<AsmStreamerBase> AS(new SizeReporterAsmStreamer(Asm));
|
||||
// Handle anything that needs to be done on a per-unit basis after
|
||||
// all other generation.
|
||||
for (const auto &P : CUMap) {
|
||||
@ -613,6 +615,15 @@ void DwarfDebug::finalizeModuleInfo() {
|
||||
U.setBaseAddress(TheCU.getRanges().front().getStart());
|
||||
U.attachRangesOrLowHighPC(U.getUnitDie(), TheCU.takeRanges());
|
||||
}
|
||||
|
||||
auto *CUNode = cast<DICompileUnit>(P.first);
|
||||
if (CUNode->getMacros()) {
|
||||
// Compile Unit has macros, emit "DW_AT_macro_info" attribute.
|
||||
U.addUInt(U.getUnitDie(), dwarf::DW_AT_macro_info,
|
||||
dwarf::DW_FORM_sec_offset, MacroOffset);
|
||||
// Update macro section offset
|
||||
MacroOffset += handleMacroNodes(AS.get(), CUNode->getMacros(), U);
|
||||
}
|
||||
}
|
||||
|
||||
// Compute DIE offsets and sizes.
|
||||
@ -656,6 +667,9 @@ void DwarfDebug::endModule() {
|
||||
// Emit info into a debug ranges section.
|
||||
emitDebugRanges();
|
||||
|
||||
// Emit info into a debug macinfo section.
|
||||
emitDebugMacinfo();
|
||||
|
||||
if (useSplitDwarf()) {
|
||||
emitDebugStrDWO();
|
||||
emitDebugInfoDWO();
|
||||
@ -1833,6 +1847,70 @@ void DwarfDebug::emitDebugRanges() {
|
||||
}
|
||||
}
|
||||
|
||||
unsigned DwarfDebug::handleMacroNodes(AsmStreamerBase *AS,
|
||||
DIMacroNodeArray Nodes,
|
||||
DwarfCompileUnit &U) {
|
||||
unsigned Size = 0;
|
||||
for (auto *MN : Nodes) {
|
||||
if (auto *M = dyn_cast<DIMacro>(MN))
|
||||
Size += emitMacro(AS, *M);
|
||||
else if (auto *F = dyn_cast<DIMacroFile>(MN))
|
||||
Size += emitMacroFile(AS, *F, U);
|
||||
else
|
||||
llvm_unreachable("Unexpected DI type!");
|
||||
}
|
||||
return Size;
|
||||
}
|
||||
|
||||
unsigned DwarfDebug::emitMacro(AsmStreamerBase *AS, DIMacro &M) {
|
||||
int Size = 0;
|
||||
Size += AS->emitULEB128(M.getMacinfoType());
|
||||
Size += AS->emitULEB128(M.getLine());
|
||||
StringRef Name = M.getName();
|
||||
StringRef Value = M.getValue();
|
||||
Size += AS->emitBytes(Name);
|
||||
if (!Value.empty()) {
|
||||
// There should be one space between macro name and macro value.
|
||||
Size += AS->emitInt8(' ');
|
||||
Size += AS->emitBytes(Value);
|
||||
}
|
||||
Size += AS->emitInt8('\0');
|
||||
return Size;
|
||||
}
|
||||
|
||||
unsigned DwarfDebug::emitMacroFile(AsmStreamerBase *AS, DIMacroFile &F,
|
||||
DwarfCompileUnit &U) {
|
||||
int Size = 0;
|
||||
assert(F.getMacinfoType() == dwarf::DW_MACINFO_start_file);
|
||||
Size += AS->emitULEB128(dwarf::DW_MACINFO_start_file);
|
||||
Size += AS->emitULEB128(F.getLine());
|
||||
DIFile *File = F.getFile();
|
||||
unsigned FID =
|
||||
U.getOrCreateSourceID(File->getFilename(), File->getDirectory());
|
||||
Size += AS->emitULEB128(FID);
|
||||
Size += handleMacroNodes(AS, F.getElements(), U);
|
||||
Size += AS->emitULEB128(dwarf::DW_MACINFO_end_file);
|
||||
return Size;
|
||||
}
|
||||
|
||||
// Emit visible names into a debug macinfo section.
|
||||
void DwarfDebug::emitDebugMacinfo() {
|
||||
if (MCSection *Macinfo = Asm->getObjFileLowering().getDwarfMacinfoSection()) {
|
||||
// Start the dwarf macinfo section.
|
||||
Asm->OutStreamer->SwitchSection(Macinfo);
|
||||
}
|
||||
std::unique_ptr<AsmStreamerBase> AS(new EmittingAsmStreamer(Asm));
|
||||
for (const auto &P : CUMap) {
|
||||
auto &TheCU = *P.second;
|
||||
auto *SkCU = TheCU.getSkeleton();
|
||||
DwarfCompileUnit &U = SkCU ? *SkCU : TheCU;
|
||||
auto *CUNode = cast<DICompileUnit>(P.first);
|
||||
handleMacroNodes(AS.get(), CUNode->getMacros(), U);
|
||||
}
|
||||
Asm->OutStreamer->AddComment("End Of Macro List Mark");
|
||||
Asm->EmitInt8(0);
|
||||
}
|
||||
|
||||
// DWARF5 Experimental Separate Dwarf emitters.
|
||||
|
||||
void DwarfDebug::initSkeletonUnit(const DwarfUnit &U, DIE &Die,
|
||||
|
@ -400,18 +400,26 @@ class DwarfDebug : public AsmPrinterHandler {
|
||||
/// Emit visible names into a debug str section.
|
||||
void emitDebugStr();
|
||||
|
||||
/// Emit visible names into a debug loc section.
|
||||
/// Emit variable locations into a debug loc section.
|
||||
void emitDebugLoc();
|
||||
|
||||
/// Emit visible names into a debug loc dwo section.
|
||||
/// Emit variable locations into a debug loc dwo section.
|
||||
void emitDebugLocDWO();
|
||||
|
||||
/// Emit visible names into a debug aranges section.
|
||||
/// Emit address ranges into a debug aranges section.
|
||||
void emitDebugARanges();
|
||||
|
||||
/// Emit visible names into a debug ranges section.
|
||||
/// Emit address ranges into a debug ranges section.
|
||||
void emitDebugRanges();
|
||||
|
||||
/// Emit macros into a debug macinfo section.
|
||||
void emitDebugMacinfo();
|
||||
unsigned emitMacro(AsmStreamerBase *AS, DIMacro &M);
|
||||
unsigned emitMacroFile(AsmStreamerBase *AS, DIMacroFile &F,
|
||||
DwarfCompileUnit &U);
|
||||
unsigned handleMacroNodes(AsmStreamerBase *AS, DIMacroNodeArray Nodes,
|
||||
DwarfCompileUnit &U);
|
||||
|
||||
/// DWARF 5 Experimental Split Dwarf Emitters
|
||||
|
||||
/// Initialize common features of skeleton units.
|
||||
|
@ -82,13 +82,24 @@ void WinCodeViewLineTables::maybeRecordLocation(DebugLoc DL,
|
||||
const MDNode *Scope = DL.getScope();
|
||||
if (!Scope)
|
||||
return;
|
||||
unsigned LineNumber = DL.getLine();
|
||||
// Skip this line if it is longer than the maximum we can record.
|
||||
if (LineNumber > COFF::CVL_MaxLineNumber)
|
||||
return;
|
||||
|
||||
unsigned ColumnNumber = DL.getCol();
|
||||
// Truncate the column number if it is longer than the maximum we can record.
|
||||
if (ColumnNumber > COFF::CVL_MaxColumnNumber)
|
||||
ColumnNumber = 0;
|
||||
|
||||
StringRef Filename = getFullFilepath(Scope);
|
||||
|
||||
// Skip this instruction if it has the same file:line as the previous one.
|
||||
assert(CurFn);
|
||||
if (!CurFn->Instrs.empty()) {
|
||||
const InstrInfoTy &LastInstr = InstrInfo[CurFn->Instrs.back()];
|
||||
if (LastInstr.Filename == Filename && LastInstr.LineNumber == DL.getLine())
|
||||
if (LastInstr.Filename == Filename && LastInstr.LineNumber == LineNumber &&
|
||||
LastInstr.ColumnNumber == ColumnNumber)
|
||||
return;
|
||||
}
|
||||
FileNameRegistry.add(Filename);
|
||||
@ -96,7 +107,7 @@ void WinCodeViewLineTables::maybeRecordLocation(DebugLoc DL,
|
||||
MCSymbol *MCL = Asm->MMI->getContext().createTempSymbol();
|
||||
Asm->OutStreamer->EmitLabel(MCL);
|
||||
CurFn->Instrs.push_back(MCL);
|
||||
InstrInfo[MCL] = InstrInfoTy(Filename, DL.getLine(), DL.getCol());
|
||||
InstrInfo[MCL] = InstrInfoTy(Filename, LineNumber, ColumnNumber);
|
||||
}
|
||||
|
||||
WinCodeViewLineTables::WinCodeViewLineTables(AsmPrinter *AP)
|
||||
@ -282,8 +293,9 @@ void WinCodeViewLineTables::emitDebugInfoForFunction(const Function *GV) {
|
||||
ColSegEnd = ColSegI + FilenameSegmentLengths[LastSegmentStart];
|
||||
ColSegI != ColSegEnd; ++ColSegI) {
|
||||
unsigned ColumnNumber = InstrInfo[FI.Instrs[ColSegI]].ColumnNumber;
|
||||
assert(ColumnNumber <= COFF::CVL_MaxColumnNumber);
|
||||
Asm->EmitInt16(ColumnNumber); // Start column
|
||||
Asm->EmitInt16(ColumnNumber); // End column
|
||||
Asm->EmitInt16(0); // End column
|
||||
}
|
||||
Asm->OutStreamer->EmitLabel(FileSegmentEnd);
|
||||
};
|
||||
@ -320,7 +332,10 @@ void WinCodeViewLineTables::emitDebugInfoForFunction(const Function *GV) {
|
||||
|
||||
// The first PC with the given linenumber and the linenumber itself.
|
||||
EmitLabelDiff(*Asm->OutStreamer, Fn, Instr);
|
||||
Asm->EmitInt32(InstrInfo[Instr].LineNumber);
|
||||
uint32_t LineNumber = InstrInfo[Instr].LineNumber;
|
||||
assert(LineNumber <= COFF::CVL_MaxLineNumber);
|
||||
uint32_t LineData = LineNumber | COFF::CVL_IsStatement;
|
||||
Asm->EmitInt32(LineData);
|
||||
}
|
||||
|
||||
FinishPreviousChunk();
|
||||
|
@ -744,18 +744,6 @@ bool BranchFolder::CreateCommonTailOnlyBlock(MachineBasicBlock *&PredBB,
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool hasIdenticalMMOs(const MachineInstr *MI1, const MachineInstr *MI2) {
|
||||
auto I1 = MI1->memoperands_begin(), E1 = MI1->memoperands_end();
|
||||
auto I2 = MI2->memoperands_begin(), E2 = MI2->memoperands_end();
|
||||
if ((E1 - I1) != (E2 - I2))
|
||||
return false;
|
||||
for (; I1 != E1; ++I1, ++I2) {
|
||||
if (**I1 != **I2)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
removeMMOsFromMemoryOperations(MachineBasicBlock::iterator MBBIStartPos,
|
||||
MachineBasicBlock &MBBCommon) {
|
||||
@ -792,8 +780,7 @@ removeMMOsFromMemoryOperations(MachineBasicBlock::iterator MBBIStartPos,
|
||||
assert(MBBICommon->isIdenticalTo(&*MBBI) && "Expected matching MIIs!");
|
||||
|
||||
if (MBBICommon->mayLoad() || MBBICommon->mayStore())
|
||||
if (!hasIdenticalMMOs(&*MBBI, &*MBBICommon))
|
||||
MBBICommon->dropMemRefs();
|
||||
MBBICommon->setMemRefs(MBBICommon->mergeMemRefsWith(*MBBI));
|
||||
|
||||
++MBBI;
|
||||
++MBBICommon;
|
||||
|
@ -1108,7 +1108,7 @@ static bool OptimizeExtractBits(BinaryOperator *ShiftI, ConstantInt *CI,
|
||||
// <16 x i1> %mask, <16 x i32> %passthru)
|
||||
// to a chain of basic blocks, with loading element one-by-one if
|
||||
// the appropriate mask bit is set
|
||||
//
|
||||
//
|
||||
// %1 = bitcast i8* %addr to i32*
|
||||
// %2 = extractelement <16 x i1> %mask, i32 0
|
||||
// %3 = icmp eq i1 %2, true
|
||||
@ -1272,12 +1272,12 @@ static void ScalarizeMaskedLoad(CallInst *CI) {
|
||||
// %5 = getelementptr i32* %1, i32 0
|
||||
// store i32 %4, i32* %5
|
||||
// br label %else
|
||||
//
|
||||
//
|
||||
// else: ; preds = %0, %cond.store
|
||||
// %6 = extractelement <16 x i1> %mask, i32 1
|
||||
// %7 = icmp eq i1 %6, true
|
||||
// br i1 %7, label %cond.store1, label %else2
|
||||
//
|
||||
//
|
||||
// cond.store1: ; preds = %else
|
||||
// %8 = extractelement <16 x i32> %val, i32 1
|
||||
// %9 = getelementptr i32* %1, i32 1
|
||||
@ -1377,24 +1377,24 @@ static void ScalarizeMaskedStore(CallInst *CI) {
|
||||
// <16 x i1> %Mask, <16 x i32> %Src)
|
||||
// to a chain of basic blocks, with loading element one-by-one if
|
||||
// the appropriate mask bit is set
|
||||
//
|
||||
//
|
||||
// % Ptrs = getelementptr i32, i32* %base, <16 x i64> %ind
|
||||
// % Mask0 = extractelement <16 x i1> %Mask, i32 0
|
||||
// % ToLoad0 = icmp eq i1 % Mask0, true
|
||||
// br i1 % ToLoad0, label %cond.load, label %else
|
||||
//
|
||||
//
|
||||
// cond.load:
|
||||
// % Ptr0 = extractelement <16 x i32*> %Ptrs, i32 0
|
||||
// % Load0 = load i32, i32* % Ptr0, align 4
|
||||
// % Res0 = insertelement <16 x i32> undef, i32 % Load0, i32 0
|
||||
// br label %else
|
||||
//
|
||||
//
|
||||
// else:
|
||||
// %res.phi.else = phi <16 x i32>[% Res0, %cond.load], [undef, % 0]
|
||||
// % Mask1 = extractelement <16 x i1> %Mask, i32 1
|
||||
// % ToLoad1 = icmp eq i1 % Mask1, true
|
||||
// br i1 % ToLoad1, label %cond.load1, label %else2
|
||||
//
|
||||
//
|
||||
// cond.load1:
|
||||
// % Ptr1 = extractelement <16 x i32*> %Ptrs, i32 1
|
||||
// % Load1 = load i32, i32* % Ptr1, align 4
|
||||
@ -1526,7 +1526,7 @@ static void ScalarizeMaskedGather(CallInst *CI) {
|
||||
// % Ptr0 = extractelement <16 x i32*> %Ptrs, i32 0
|
||||
// store i32 %Elt0, i32* % Ptr0, align 4
|
||||
// br label %else
|
||||
//
|
||||
//
|
||||
// else:
|
||||
// % Mask1 = extractelement <16 x i1> % Mask, i32 1
|
||||
// % ToStore1 = icmp eq i1 % Mask1, true
|
||||
|
@ -19,6 +19,8 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/ADT/Statistic.h"
|
||||
#include "llvm/ADT/PostOrderIterator.h"
|
||||
#include "llvm/ADT/SmallPtrSet.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/CodeGen/MachineFunction.h"
|
||||
#include "llvm/CodeGen/MachineFunctionPass.h"
|
||||
@ -30,7 +32,7 @@
|
||||
#include "llvm/Target/TargetInstrInfo.h"
|
||||
#include "llvm/Target/TargetRegisterInfo.h"
|
||||
#include "llvm/Target/TargetSubtargetInfo.h"
|
||||
#include <deque>
|
||||
#include <queue>
|
||||
#include <list>
|
||||
|
||||
using namespace llvm;
|
||||
@ -76,16 +78,13 @@ class LiveDebugValues : public MachineFunctionPass {
|
||||
typedef std::list<VarLoc> VarLocList;
|
||||
typedef SmallDenseMap<const MachineBasicBlock *, VarLocList> VarLocInMBB;
|
||||
|
||||
bool OLChanged; // OutgoingLocs got changed for this bb.
|
||||
bool MBBJoined; // The MBB was joined.
|
||||
|
||||
void transferDebugValue(MachineInstr &MI, VarLocList &OpenRanges);
|
||||
void transferRegisterDef(MachineInstr &MI, VarLocList &OpenRanges);
|
||||
void transferTerminatorInst(MachineInstr &MI, VarLocList &OpenRanges,
|
||||
bool transferTerminatorInst(MachineInstr &MI, VarLocList &OpenRanges,
|
||||
VarLocInMBB &OutLocs);
|
||||
void transfer(MachineInstr &MI, VarLocList &OpenRanges, VarLocInMBB &OutLocs);
|
||||
bool transfer(MachineInstr &MI, VarLocList &OpenRanges, VarLocInMBB &OutLocs);
|
||||
|
||||
void join(MachineBasicBlock &MBB, VarLocInMBB &OutLocs, VarLocInMBB &InLocs);
|
||||
bool join(MachineBasicBlock &MBB, VarLocInMBB &OutLocs, VarLocInMBB &InLocs);
|
||||
|
||||
bool ExtendRanges(MachineFunction &MF);
|
||||
|
||||
@ -225,24 +224,18 @@ void LiveDebugValues::transferRegisterDef(MachineInstr &MI,
|
||||
}
|
||||
|
||||
/// Terminate all open ranges at the end of the current basic block.
|
||||
void LiveDebugValues::transferTerminatorInst(MachineInstr &MI,
|
||||
bool LiveDebugValues::transferTerminatorInst(MachineInstr &MI,
|
||||
VarLocList &OpenRanges,
|
||||
VarLocInMBB &OutLocs) {
|
||||
bool Changed = false;
|
||||
const MachineBasicBlock *CurMBB = MI.getParent();
|
||||
if (!(MI.isTerminator() || (&MI == &CurMBB->instr_back())))
|
||||
return;
|
||||
return false;
|
||||
|
||||
if (OpenRanges.empty())
|
||||
return;
|
||||
return false;
|
||||
|
||||
if (OutLocs.find(CurMBB) == OutLocs.end()) {
|
||||
// Create space for new Outgoing locs entries.
|
||||
VarLocList VLL;
|
||||
OutLocs.insert(std::make_pair(CurMBB, std::move(VLL)));
|
||||
}
|
||||
auto OL = OutLocs.find(CurMBB);
|
||||
assert(OL != OutLocs.end());
|
||||
VarLocList &VLL = OL->second;
|
||||
VarLocList &VLL = OutLocs[CurMBB];
|
||||
|
||||
for (auto OR : OpenRanges) {
|
||||
// Copy OpenRanges to OutLocs, if not already present.
|
||||
@ -251,28 +244,30 @@ void LiveDebugValues::transferTerminatorInst(MachineInstr &MI,
|
||||
if (std::find_if(VLL.begin(), VLL.end(),
|
||||
[&](const VarLoc &V) { return (OR == V); }) == VLL.end()) {
|
||||
VLL.push_back(std::move(OR));
|
||||
OLChanged = true;
|
||||
Changed = true;
|
||||
}
|
||||
}
|
||||
OpenRanges.clear();
|
||||
return Changed;
|
||||
}
|
||||
|
||||
/// This routine creates OpenRanges and OutLocs.
|
||||
void LiveDebugValues::transfer(MachineInstr &MI, VarLocList &OpenRanges,
|
||||
bool LiveDebugValues::transfer(MachineInstr &MI, VarLocList &OpenRanges,
|
||||
VarLocInMBB &OutLocs) {
|
||||
bool Changed = false;
|
||||
transferDebugValue(MI, OpenRanges);
|
||||
transferRegisterDef(MI, OpenRanges);
|
||||
transferTerminatorInst(MI, OpenRanges, OutLocs);
|
||||
Changed = transferTerminatorInst(MI, OpenRanges, OutLocs);
|
||||
return Changed;
|
||||
}
|
||||
|
||||
/// This routine joins the analysis results of all incoming edges in @MBB by
|
||||
/// inserting a new DBG_VALUE instruction at the start of the @MBB - if the same
|
||||
/// source variable in all the predecessors of @MBB reside in the same location.
|
||||
void LiveDebugValues::join(MachineBasicBlock &MBB, VarLocInMBB &OutLocs,
|
||||
bool LiveDebugValues::join(MachineBasicBlock &MBB, VarLocInMBB &OutLocs,
|
||||
VarLocInMBB &InLocs) {
|
||||
DEBUG(dbgs() << "join MBB: " << MBB.getName() << "\n");
|
||||
|
||||
MBBJoined = false;
|
||||
bool Changed = false;
|
||||
|
||||
VarLocList InLocsT; // Temporary incoming locations.
|
||||
|
||||
@ -282,7 +277,7 @@ void LiveDebugValues::join(MachineBasicBlock &MBB, VarLocInMBB &OutLocs,
|
||||
auto OL = OutLocs.find(p);
|
||||
// Join is null in case of empty OutLocs from any of the pred.
|
||||
if (OL == OutLocs.end())
|
||||
return;
|
||||
return false;
|
||||
|
||||
// Just copy over the Out locs to incoming locs for the first predecessor.
|
||||
if (p == *MBB.pred_begin()) {
|
||||
@ -292,27 +287,18 @@ void LiveDebugValues::join(MachineBasicBlock &MBB, VarLocInMBB &OutLocs,
|
||||
|
||||
// Join with this predecessor.
|
||||
VarLocList &VLL = OL->second;
|
||||
InLocsT.erase(std::remove_if(InLocsT.begin(), InLocsT.end(),
|
||||
[&](VarLoc &ILT) {
|
||||
return (std::find_if(VLL.begin(), VLL.end(),
|
||||
[&](const VarLoc &V) {
|
||||
return (ILT == V);
|
||||
}) == VLL.end());
|
||||
}),
|
||||
InLocsT.end());
|
||||
InLocsT.erase(
|
||||
std::remove_if(InLocsT.begin(), InLocsT.end(), [&](VarLoc &ILT) {
|
||||
return (std::find_if(VLL.begin(), VLL.end(), [&](const VarLoc &V) {
|
||||
return (ILT == V);
|
||||
}) == VLL.end());
|
||||
}), InLocsT.end());
|
||||
}
|
||||
|
||||
if (InLocsT.empty())
|
||||
return;
|
||||
return false;
|
||||
|
||||
if (InLocs.find(&MBB) == InLocs.end()) {
|
||||
// Create space for new Incoming locs entries.
|
||||
VarLocList VLL;
|
||||
InLocs.insert(std::make_pair(&MBB, std::move(VLL)));
|
||||
}
|
||||
auto IL = InLocs.find(&MBB);
|
||||
assert(IL != InLocs.end());
|
||||
VarLocList &ILL = IL->second;
|
||||
VarLocList &ILL = InLocs[&MBB];
|
||||
|
||||
// Insert DBG_VALUE instructions, if not already inserted.
|
||||
for (auto ILT : InLocsT) {
|
||||
@ -331,12 +317,13 @@ void LiveDebugValues::join(MachineBasicBlock &MBB, VarLocInMBB &OutLocs,
|
||||
MI->getOperand(1).setImm(DMI->getOperand(1).getImm());
|
||||
DEBUG(dbgs() << "Inserted: "; MI->dump(););
|
||||
++NumInserted;
|
||||
MBBJoined = true; // rerun transfer().
|
||||
Changed = true;
|
||||
|
||||
VarLoc V(ILT.Var, MI);
|
||||
ILL.push_back(std::move(V));
|
||||
}
|
||||
}
|
||||
return Changed;
|
||||
}
|
||||
|
||||
/// Calculate the liveness information for the given machine function and
|
||||
@ -346,48 +333,72 @@ bool LiveDebugValues::ExtendRanges(MachineFunction &MF) {
|
||||
DEBUG(dbgs() << "\nDebug Range Extension\n");
|
||||
|
||||
bool Changed = false;
|
||||
OLChanged = MBBJoined = false;
|
||||
bool OLChanged = false;
|
||||
bool MBBJoined = false;
|
||||
|
||||
VarLocList OpenRanges; // Ranges that are open until end of bb.
|
||||
VarLocInMBB OutLocs; // Ranges that exist beyond bb.
|
||||
VarLocInMBB InLocs; // Ranges that are incoming after joining.
|
||||
|
||||
std::deque<MachineBasicBlock *> BBWorklist;
|
||||
|
||||
DenseMap<unsigned int, MachineBasicBlock *> OrderToBB;
|
||||
DenseMap<MachineBasicBlock *, unsigned int> BBToOrder;
|
||||
std::priority_queue<unsigned int, std::vector<unsigned int>,
|
||||
std::greater<unsigned int>> Worklist;
|
||||
std::priority_queue<unsigned int, std::vector<unsigned int>,
|
||||
std::greater<unsigned int>> Pending;
|
||||
// Initialize every mbb with OutLocs.
|
||||
for (auto &MBB : MF)
|
||||
for (auto &MI : MBB)
|
||||
transfer(MI, OpenRanges, OutLocs);
|
||||
DEBUG(printVarLocInMBB(OutLocs, "OutLocs after initialization", dbgs()));
|
||||
|
||||
// Construct a worklist of MBBs.
|
||||
for (auto &MBB : MF)
|
||||
BBWorklist.push_back(&MBB);
|
||||
ReversePostOrderTraversal<MachineFunction *> RPOT(&MF);
|
||||
unsigned int RPONumber = 0;
|
||||
for (auto RI = RPOT.begin(), RE = RPOT.end(); RI != RE; ++RI) {
|
||||
OrderToBB[RPONumber] = *RI;
|
||||
BBToOrder[*RI] = RPONumber;
|
||||
Worklist.push(RPONumber);
|
||||
++RPONumber;
|
||||
}
|
||||
|
||||
// Perform join() and transfer() using the worklist until the ranges converge
|
||||
// Ranges have converged when the worklist is empty.
|
||||
while (!BBWorklist.empty()) {
|
||||
MachineBasicBlock *MBB = BBWorklist.front();
|
||||
BBWorklist.pop_front();
|
||||
// This is a standard "union of predecessor outs" dataflow problem.
|
||||
// To solve it, we perform join() and transfer() using the two worklist method
|
||||
// until the ranges converge.
|
||||
// Ranges have converged when both worklists are empty.
|
||||
while (!Worklist.empty() || !Pending.empty()) {
|
||||
// We track what is on the pending worklist to avoid inserting the same
|
||||
// thing twice. We could avoid this with a custom priority queue, but this
|
||||
// is probably not worth it.
|
||||
SmallPtrSet<MachineBasicBlock *, 16> OnPending;
|
||||
while (!Worklist.empty()) {
|
||||
MachineBasicBlock *MBB = OrderToBB[Worklist.top()];
|
||||
Worklist.pop();
|
||||
MBBJoined = join(*MBB, OutLocs, InLocs);
|
||||
|
||||
join(*MBB, OutLocs, InLocs);
|
||||
if (MBBJoined) {
|
||||
MBBJoined = false;
|
||||
Changed = true;
|
||||
for (auto &MI : *MBB)
|
||||
OLChanged |= transfer(MI, OpenRanges, OutLocs);
|
||||
DEBUG(printVarLocInMBB(OutLocs, "OutLocs after propagating", dbgs()));
|
||||
DEBUG(printVarLocInMBB(InLocs, "InLocs after propagating", dbgs()));
|
||||
|
||||
if (MBBJoined) {
|
||||
Changed = true;
|
||||
for (auto &MI : *MBB)
|
||||
transfer(MI, OpenRanges, OutLocs);
|
||||
DEBUG(printVarLocInMBB(OutLocs, "OutLocs after propagating", dbgs()));
|
||||
DEBUG(printVarLocInMBB(InLocs, "InLocs after propagating", dbgs()));
|
||||
|
||||
if (OLChanged) {
|
||||
OLChanged = false;
|
||||
for (auto s : MBB->successors())
|
||||
if (std::find(BBWorklist.begin(), BBWorklist.end(), s) ==
|
||||
BBWorklist.end()) // add if not already present.
|
||||
BBWorklist.push_back(s);
|
||||
if (OLChanged) {
|
||||
OLChanged = false;
|
||||
for (auto s : MBB->successors())
|
||||
if (!OnPending.count(s)) {
|
||||
OnPending.insert(s);
|
||||
Pending.push(BBToOrder[s]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Worklist.swap(Pending);
|
||||
// At this point, pending must be empty, since it was just the empty
|
||||
// worklist
|
||||
assert(Pending.empty() && "Pending should be empty");
|
||||
}
|
||||
|
||||
DEBUG(printVarLocInMBB(OutLocs, "Final OutLocs", dbgs()));
|
||||
DEBUG(printVarLocInMBB(InLocs, "Final InLocs", dbgs()));
|
||||
return Changed;
|
||||
|
@ -1328,15 +1328,15 @@ void LiveRangeUpdater::flush() {
|
||||
LR->verify();
|
||||
}
|
||||
|
||||
unsigned ConnectedVNInfoEqClasses::Classify(const LiveInterval *LI) {
|
||||
unsigned ConnectedVNInfoEqClasses::Classify(const LiveRange &LR) {
|
||||
// Create initial equivalence classes.
|
||||
EqClass.clear();
|
||||
EqClass.grow(LI->getNumValNums());
|
||||
EqClass.grow(LR.getNumValNums());
|
||||
|
||||
const VNInfo *used = nullptr, *unused = nullptr;
|
||||
|
||||
// Determine connections.
|
||||
for (const VNInfo *VNI : LI->valnos) {
|
||||
for (const VNInfo *VNI : LR.valnos) {
|
||||
// Group all unused values into one class.
|
||||
if (VNI->isUnused()) {
|
||||
if (unused)
|
||||
@ -1351,14 +1351,14 @@ unsigned ConnectedVNInfoEqClasses::Classify(const LiveInterval *LI) {
|
||||
// Connect to values live out of predecessors.
|
||||
for (MachineBasicBlock::const_pred_iterator PI = MBB->pred_begin(),
|
||||
PE = MBB->pred_end(); PI != PE; ++PI)
|
||||
if (const VNInfo *PVNI = LI->getVNInfoBefore(LIS.getMBBEndIdx(*PI)))
|
||||
if (const VNInfo *PVNI = LR.getVNInfoBefore(LIS.getMBBEndIdx(*PI)))
|
||||
EqClass.join(VNI->id, PVNI->id);
|
||||
} else {
|
||||
// Normal value defined by an instruction. Check for two-addr redef.
|
||||
// FIXME: This could be coincidental. Should we really check for a tied
|
||||
// operand constraint?
|
||||
// Note that VNI->def may be a use slot for an early clobber def.
|
||||
if (const VNInfo *UVNI = LI->getVNInfoBefore(VNI->def))
|
||||
if (const VNInfo *UVNI = LR.getVNInfoBefore(VNI->def))
|
||||
EqClass.join(VNI->id, UVNI->id);
|
||||
}
|
||||
}
|
||||
|
@ -1446,7 +1446,7 @@ void LiveIntervals::removeVRegDefAt(LiveInterval &LI, SlotIndex Pos) {
|
||||
void LiveIntervals::splitSeparateComponents(LiveInterval &LI,
|
||||
SmallVectorImpl<LiveInterval*> &SplitLIs) {
|
||||
ConnectedVNInfoEqClasses ConEQ(*this);
|
||||
unsigned NumComp = ConEQ.Classify(&LI);
|
||||
unsigned NumComp = ConEQ.Classify(LI);
|
||||
if (NumComp <= 1)
|
||||
return;
|
||||
DEBUG(dbgs() << " Split " << NumComp << " components: " << LI << '\n');
|
||||
|
@ -1182,7 +1182,7 @@ MachineBasicBlock::getProbabilityIterator(MachineBasicBlock::succ_iterator I) {
|
||||
|
||||
/// Return whether (physical) register "Reg" has been <def>ined and not <kill>ed
|
||||
/// as of just before "MI".
|
||||
///
|
||||
///
|
||||
/// Search is localised to a neighborhood of
|
||||
/// Neighborhood instructions before (searching for defs or kills) and N
|
||||
/// instructions after (searching just for defs) MI.
|
||||
|
@ -31,7 +31,7 @@ struct MachineFunctionPrinterPass : public MachineFunctionPass {
|
||||
const std::string Banner;
|
||||
|
||||
MachineFunctionPrinterPass() : MachineFunctionPass(ID), OS(dbgs()) { }
|
||||
MachineFunctionPrinterPass(raw_ostream &os, const std::string &banner)
|
||||
MachineFunctionPrinterPass(raw_ostream &os, const std::string &banner)
|
||||
: MachineFunctionPass(ID), OS(os), Banner(banner) {}
|
||||
|
||||
const char *getPassName() const override { return "MachineFunction Printer"; }
|
||||
@ -42,6 +42,8 @@ struct MachineFunctionPrinterPass : public MachineFunctionPass {
|
||||
}
|
||||
|
||||
bool runOnMachineFunction(MachineFunction &MF) override {
|
||||
if (!llvm::isFunctionInPrintList(MF.getName()))
|
||||
return false;
|
||||
OS << "# " << Banner << ":\n";
|
||||
MF.print(OS, getAnalysisIfAvailable<SlotIndexes>());
|
||||
return false;
|
||||
|
@ -866,14 +866,44 @@ void MachineInstr::addMemOperand(MachineFunction &MF,
|
||||
setMemRefs(NewMemRefs, NewMemRefs + NewNum);
|
||||
}
|
||||
|
||||
/// Check to see if the MMOs pointed to by the two MemRefs arrays are
|
||||
/// identical.
|
||||
static bool hasIdenticalMMOs(const MachineInstr &MI1, const MachineInstr &MI2) {
|
||||
auto I1 = MI1.memoperands_begin(), E1 = MI1.memoperands_end();
|
||||
auto I2 = MI2.memoperands_begin(), E2 = MI2.memoperands_end();
|
||||
if ((E1 - I1) != (E2 - I2))
|
||||
return false;
|
||||
for (; I1 != E1; ++I1, ++I2) {
|
||||
if (**I1 != **I2)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
std::pair<MachineInstr::mmo_iterator, unsigned>
|
||||
MachineInstr::mergeMemRefsWith(const MachineInstr& Other) {
|
||||
// TODO: If we end up with too many memory operands, return the empty
|
||||
// conservative set rather than failing asserts.
|
||||
|
||||
// If either of the incoming memrefs are empty, we must be conservative and
|
||||
// treat this as if we've exhausted our space for memrefs and dropped them.
|
||||
if (memoperands_empty() || Other.memoperands_empty())
|
||||
return std::make_pair(nullptr, 0);
|
||||
|
||||
// If both instructions have identical memrefs, we don't need to merge them.
|
||||
// Since many instructions have a single memref, and we tend to merge things
|
||||
// like pairs of loads from the same location, this catches a large number of
|
||||
// cases in practice.
|
||||
if (hasIdenticalMMOs(*this, Other))
|
||||
return std::make_pair(MemRefs, NumMemRefs);
|
||||
|
||||
// TODO: consider uniquing elements within the operand lists to reduce
|
||||
// space usage and fall back to conservative information less often.
|
||||
size_t CombinedNumMemRefs = (memoperands_end() - memoperands_begin())
|
||||
+ (Other.memoperands_end() - Other.memoperands_begin());
|
||||
size_t CombinedNumMemRefs = NumMemRefs + Other.NumMemRefs;
|
||||
|
||||
// If we don't have enough room to store this many memrefs, be conservative
|
||||
// and drop them. Otherwise, we'd fail asserts when trying to add them to
|
||||
// the new instruction.
|
||||
if (CombinedNumMemRefs != uint8_t(CombinedNumMemRefs))
|
||||
return std::make_pair(nullptr, 0);
|
||||
|
||||
MachineFunction *MF = getParent()->getParent();
|
||||
mmo_iterator MemBegin = MF->allocateMemRefsArray(CombinedNumMemRefs);
|
||||
|
@ -334,12 +334,11 @@ static bool InstructionStoresToFI(const MachineInstr *MI, int FI) {
|
||||
// writes to all slots.
|
||||
if (MI->memoperands_empty())
|
||||
return true;
|
||||
for (MachineInstr::mmo_iterator o = MI->memoperands_begin(),
|
||||
oe = MI->memoperands_end(); o != oe; ++o) {
|
||||
if (!(*o)->isStore() || !(*o)->getPseudoValue())
|
||||
for (const MachineMemOperand *MemOp : MI->memoperands()) {
|
||||
if (!MemOp->isStore() || !MemOp->getPseudoValue())
|
||||
continue;
|
||||
if (const FixedStackPseudoSourceValue *Value =
|
||||
dyn_cast<FixedStackPseudoSourceValue>((*o)->getPseudoValue())) {
|
||||
dyn_cast<FixedStackPseudoSourceValue>(MemOp->getPseudoValue())) {
|
||||
if (Value->getFrameIndex() == FI)
|
||||
return true;
|
||||
}
|
||||
@ -357,8 +356,7 @@ void MachineLICM::ProcessMI(MachineInstr *MI,
|
||||
bool RuledOut = false;
|
||||
bool HasNonInvariantUse = false;
|
||||
unsigned Def = 0;
|
||||
for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
|
||||
const MachineOperand &MO = MI->getOperand(i);
|
||||
for (const MachineOperand &MO : MI->operands()) {
|
||||
if (MO.isFI()) {
|
||||
// Remember if the instruction stores to the frame index.
|
||||
int FI = MO.getIndex();
|
||||
@ -452,9 +450,7 @@ void MachineLICM::HoistRegionPostRA() {
|
||||
// Walk the entire region, count number of defs for each register, and
|
||||
// collect potential LICM candidates.
|
||||
const std::vector<MachineBasicBlock *> &Blocks = CurLoop->getBlocks();
|
||||
for (unsigned i = 0, e = Blocks.size(); i != e; ++i) {
|
||||
MachineBasicBlock *BB = Blocks[i];
|
||||
|
||||
for (MachineBasicBlock *BB : Blocks) {
|
||||
// If the header of the loop containing this basic block is a landing pad,
|
||||
// then don't try to hoist instructions out of this loop.
|
||||
const MachineLoop *ML = MLI->getLoopFor(BB);
|
||||
@ -469,19 +465,15 @@ void MachineLICM::HoistRegionPostRA() {
|
||||
}
|
||||
|
||||
SpeculationState = SpeculateUnknown;
|
||||
for (MachineBasicBlock::iterator
|
||||
MII = BB->begin(), E = BB->end(); MII != E; ++MII) {
|
||||
MachineInstr *MI = &*MII;
|
||||
ProcessMI(MI, PhysRegDefs, PhysRegClobbers, StoredFIs, Candidates);
|
||||
}
|
||||
for (MachineInstr &MI : *BB)
|
||||
ProcessMI(&MI, PhysRegDefs, PhysRegClobbers, StoredFIs, Candidates);
|
||||
}
|
||||
|
||||
// Gather the registers read / clobbered by the terminator.
|
||||
BitVector TermRegs(NumRegs);
|
||||
MachineBasicBlock::iterator TI = Preheader->getFirstTerminator();
|
||||
if (TI != Preheader->end()) {
|
||||
for (unsigned i = 0, e = TI->getNumOperands(); i != e; ++i) {
|
||||
const MachineOperand &MO = TI->getOperand(i);
|
||||
for (const MachineOperand &MO : TI->operands()) {
|
||||
if (!MO.isReg())
|
||||
continue;
|
||||
unsigned Reg = MO.getReg();
|
||||
@ -500,17 +492,16 @@ void MachineLICM::HoistRegionPostRA() {
|
||||
// 3. Make sure candidate def should not clobber
|
||||
// registers read by the terminator. Similarly its def should not be
|
||||
// clobbered by the terminator.
|
||||
for (unsigned i = 0, e = Candidates.size(); i != e; ++i) {
|
||||
if (Candidates[i].FI != INT_MIN &&
|
||||
StoredFIs.count(Candidates[i].FI))
|
||||
for (CandidateInfo &Candidate : Candidates) {
|
||||
if (Candidate.FI != INT_MIN &&
|
||||
StoredFIs.count(Candidate.FI))
|
||||
continue;
|
||||
|
||||
unsigned Def = Candidates[i].Def;
|
||||
unsigned Def = Candidate.Def;
|
||||
if (!PhysRegClobbers.test(Def) && !TermRegs.test(Def)) {
|
||||
bool Safe = true;
|
||||
MachineInstr *MI = Candidates[i].MI;
|
||||
for (unsigned j = 0, ee = MI->getNumOperands(); j != ee; ++j) {
|
||||
const MachineOperand &MO = MI->getOperand(j);
|
||||
MachineInstr *MI = Candidate.MI;
|
||||
for (const MachineOperand &MO : MI->operands()) {
|
||||
if (!MO.isReg() || MO.isDef() || !MO.getReg())
|
||||
continue;
|
||||
unsigned Reg = MO.getReg();
|
||||
@ -523,7 +514,7 @@ void MachineLICM::HoistRegionPostRA() {
|
||||
}
|
||||
}
|
||||
if (Safe)
|
||||
HoistPostRA(MI, Candidates[i].Def);
|
||||
HoistPostRA(MI, Candidate.Def);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -532,15 +523,11 @@ void MachineLICM::HoistRegionPostRA() {
|
||||
/// sure it is not killed by any instructions in the loop.
|
||||
void MachineLICM::AddToLiveIns(unsigned Reg) {
|
||||
const std::vector<MachineBasicBlock *> &Blocks = CurLoop->getBlocks();
|
||||
for (unsigned i = 0, e = Blocks.size(); i != e; ++i) {
|
||||
MachineBasicBlock *BB = Blocks[i];
|
||||
for (MachineBasicBlock *BB : Blocks) {
|
||||
if (!BB->isLiveIn(Reg))
|
||||
BB->addLiveIn(Reg);
|
||||
for (MachineBasicBlock::iterator
|
||||
MII = BB->begin(), E = BB->end(); MII != E; ++MII) {
|
||||
MachineInstr *MI = &*MII;
|
||||
for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
|
||||
MachineOperand &MO = MI->getOperand(i);
|
||||
for (MachineInstr &MI : *BB) {
|
||||
for (MachineOperand &MO : MI.operands()) {
|
||||
if (!MO.isReg() || !MO.getReg() || MO.isDef()) continue;
|
||||
if (MO.getReg() == Reg || TRI->isSuperRegister(Reg, MO.getReg()))
|
||||
MO.setIsKill(false);
|
||||
@ -582,8 +569,8 @@ bool MachineLICM::IsGuaranteedToExecute(MachineBasicBlock *BB) {
|
||||
// Check loop exiting blocks.
|
||||
SmallVector<MachineBasicBlock*, 8> CurrentLoopExitingBlocks;
|
||||
CurLoop->getExitingBlocks(CurrentLoopExitingBlocks);
|
||||
for (unsigned i = 0, e = CurrentLoopExitingBlocks.size(); i != e; ++i)
|
||||
if (!DT->dominates(BB, CurrentLoopExitingBlocks[i])) {
|
||||
for (MachineBasicBlock *CurrentLoopExitingBlock : CurrentLoopExitingBlocks)
|
||||
if (!DT->dominates(BB, CurrentLoopExitingBlock)) {
|
||||
SpeculationState = SpeculateTrue;
|
||||
return false;
|
||||
}
|
||||
@ -689,8 +676,7 @@ void MachineLICM::HoistOutOfLoop(MachineDomTreeNode *HeaderN) {
|
||||
InitRegPressure(Preheader);
|
||||
|
||||
// Now perform LICM.
|
||||
for (unsigned i = 0, e = Scopes.size(); i != e; ++i) {
|
||||
MachineDomTreeNode *Node = Scopes[i];
|
||||
for (MachineDomTreeNode *Node : Scopes) {
|
||||
MachineBasicBlock *MBB = Node->getBlock();
|
||||
|
||||
EnterScope(MBB);
|
||||
@ -858,13 +844,11 @@ static bool mayLoadFromGOTOrConstantPool(MachineInstr &MI) {
|
||||
if (MI.memoperands_empty())
|
||||
return true;
|
||||
|
||||
for (MachineInstr::mmo_iterator I = MI.memoperands_begin(),
|
||||
E = MI.memoperands_end(); I != E; ++I) {
|
||||
if (const PseudoSourceValue *PSV = (*I)->getPseudoValue()) {
|
||||
for (MachineMemOperand *MemOp : MI.memoperands())
|
||||
if (const PseudoSourceValue *PSV = MemOp->getPseudoValue())
|
||||
if (PSV->isGOT() || PSV->isConstantPool())
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -899,9 +883,7 @@ bool MachineLICM::IsLoopInvariantInst(MachineInstr &I) {
|
||||
return false;
|
||||
|
||||
// The instruction is loop invariant if all of its operands are.
|
||||
for (unsigned i = 0, e = I.getNumOperands(); i != e; ++i) {
|
||||
const MachineOperand &MO = I.getOperand(i);
|
||||
|
||||
for (const MachineOperand &MO : I.operands()) {
|
||||
if (!MO.isReg())
|
||||
continue;
|
||||
|
||||
@ -1230,11 +1212,8 @@ MachineInstr *MachineLICM::ExtractHoistableLoad(MachineInstr *MI) {
|
||||
/// preheader that may become duplicates of instructions that are hoisted
|
||||
/// out of the loop.
|
||||
void MachineLICM::InitCSEMap(MachineBasicBlock *BB) {
|
||||
for (MachineBasicBlock::iterator I = BB->begin(),E = BB->end(); I != E; ++I) {
|
||||
const MachineInstr *MI = &*I;
|
||||
unsigned Opcode = MI->getOpcode();
|
||||
CSEMap[Opcode].push_back(MI);
|
||||
}
|
||||
for (MachineInstr &MI : *BB)
|
||||
CSEMap[MI.getOpcode()].push_back(&MI);
|
||||
}
|
||||
|
||||
/// Find an instruction amount PrevMIs that is a duplicate of MI.
|
||||
@ -1242,11 +1221,10 @@ void MachineLICM::InitCSEMap(MachineBasicBlock *BB) {
|
||||
const MachineInstr*
|
||||
MachineLICM::LookForDuplicate(const MachineInstr *MI,
|
||||
std::vector<const MachineInstr*> &PrevMIs) {
|
||||
for (unsigned i = 0, e = PrevMIs.size(); i != e; ++i) {
|
||||
const MachineInstr *PrevMI = PrevMIs[i];
|
||||
for (const MachineInstr *PrevMI : PrevMIs)
|
||||
if (TII->produceSameValue(MI, PrevMI, (PreRegAlloc ? MRI : nullptr)))
|
||||
return PrevMI;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@ -1296,8 +1274,7 @@ bool MachineLICM::EliminateCSE(MachineInstr *MI,
|
||||
}
|
||||
}
|
||||
|
||||
for (unsigned i = 0, e = Defs.size(); i != e; ++i) {
|
||||
unsigned Idx = Defs[i];
|
||||
for (unsigned Idx : Defs) {
|
||||
unsigned Reg = MI->getOperand(Idx).getReg();
|
||||
unsigned DupReg = Dup->getOperand(Idx).getReg();
|
||||
MRI->replaceRegWith(Reg, DupReg);
|
||||
@ -1370,11 +1347,9 @@ bool MachineLICM::Hoist(MachineInstr *MI, MachineBasicBlock *Preheader) {
|
||||
// Clear the kill flags of any register this instruction defines,
|
||||
// since they may need to be live throughout the entire loop
|
||||
// rather than just live for part of it.
|
||||
for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
|
||||
MachineOperand &MO = MI->getOperand(i);
|
||||
for (MachineOperand &MO : MI->operands())
|
||||
if (MO.isReg() && MO.isDef() && !MO.isDead())
|
||||
MRI->clearKillFlags(MO.getReg());
|
||||
}
|
||||
|
||||
// Add to the CSE map.
|
||||
if (CI != CSEMap.end())
|
||||
|
@ -1736,7 +1736,7 @@ void MachineVerifier::verifyLiveInterval(const LiveInterval &LI) {
|
||||
|
||||
// Check the LI only has one connected component.
|
||||
ConnectedVNInfoEqClasses ConEQ(*LiveInts);
|
||||
unsigned NumComp = ConEQ.Classify(&LI);
|
||||
unsigned NumComp = ConEQ.Classify(LI);
|
||||
if (NumComp > 1) {
|
||||
report("Multiple connected components in live interval", MF);
|
||||
report_context(LI);
|
||||
|
@ -2874,7 +2874,7 @@ void RegisterCoalescer::joinAllIntervals() {
|
||||
|
||||
std::vector<MBBPriorityInfo> MBBs;
|
||||
MBBs.reserve(MF->size());
|
||||
for (MachineFunction::iterator I = MF->begin(), E = MF->end();I != E;++I){
|
||||
for (MachineFunction::iterator I = MF->begin(), E = MF->end(); I != E; ++I) {
|
||||
MachineBasicBlock *MBB = &*I;
|
||||
MBBs.push_back(MBBPriorityInfo(MBB, Loops->getLoopDepth(MBB),
|
||||
JoinSplitEdges && isSplitEdge(MBB)));
|
||||
|
@ -313,21 +313,6 @@ static bool containsReg(ArrayRef<unsigned> RegUnits, unsigned RegUnit) {
|
||||
|
||||
namespace {
|
||||
|
||||
/// List of register defined and used by a machine instruction.
|
||||
class RegisterOperands {
|
||||
public:
|
||||
SmallVector<unsigned, 8> Uses;
|
||||
SmallVector<unsigned, 8> Defs;
|
||||
SmallVector<unsigned, 8> DeadDefs;
|
||||
|
||||
void collect(const MachineInstr &MI, const TargetRegisterInfo &TRI,
|
||||
const MachineRegisterInfo &MRI, bool IgnoreDead = false);
|
||||
|
||||
/// Use liveness information to find dead defs not marked with a dead flag
|
||||
/// and move them to the DeadDefs vector.
|
||||
void detectDeadDefs(const MachineInstr &MI, const LiveIntervals &LIS);
|
||||
};
|
||||
|
||||
/// Collect this instruction's unique uses and defs into SmallVectors for
|
||||
/// processing defs and uses in order.
|
||||
///
|
||||
@ -385,9 +370,11 @@ class RegisterOperandsCollector {
|
||||
}
|
||||
}
|
||||
|
||||
friend class RegisterOperands;
|
||||
friend class llvm::RegisterOperands;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
void RegisterOperands::collect(const MachineInstr &MI,
|
||||
const TargetRegisterInfo &TRI,
|
||||
const MachineRegisterInfo &MRI,
|
||||
@ -417,8 +404,6 @@ void RegisterOperands::detectDeadDefs(const MachineInstr &MI,
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
/// Initialize an array of N PressureDiffs.
|
||||
void PressureDiffs::init(unsigned N) {
|
||||
Size = N;
|
||||
@ -431,6 +416,18 @@ void PressureDiffs::init(unsigned N) {
|
||||
PDiffArray = reinterpret_cast<PressureDiff*>(calloc(N, sizeof(PressureDiff)));
|
||||
}
|
||||
|
||||
void PressureDiffs::addInstruction(unsigned Idx,
|
||||
const RegisterOperands &RegOpers,
|
||||
const MachineRegisterInfo &MRI) {
|
||||
PressureDiff &PDiff = (*this)[Idx];
|
||||
assert(!PDiff.begin()->isValid() && "stale PDiff");
|
||||
for (unsigned Reg : RegOpers.Defs)
|
||||
PDiff.addPressureChange(Reg, true, &MRI);
|
||||
|
||||
for (unsigned Reg : RegOpers.Uses)
|
||||
PDiff.addPressureChange(Reg, false, &MRI);
|
||||
}
|
||||
|
||||
/// Add a change in pressure to the pressure diff of a given instruction.
|
||||
void PressureDiff::addPressureChange(unsigned RegUnit, bool IsDec,
|
||||
const MachineRegisterInfo *MRI) {
|
||||
@ -467,18 +464,6 @@ void PressureDiff::addPressureChange(unsigned RegUnit, bool IsDec,
|
||||
}
|
||||
}
|
||||
|
||||
/// Record the pressure difference induced by the given operand list.
|
||||
static void collectPDiff(PressureDiff &PDiff, RegisterOperands &RegOpers,
|
||||
const MachineRegisterInfo *MRI) {
|
||||
assert(!PDiff.begin()->isValid() && "stale PDiff");
|
||||
|
||||
for (unsigned Reg : RegOpers.Defs)
|
||||
PDiff.addPressureChange(Reg, true, MRI);
|
||||
|
||||
for (unsigned Reg : RegOpers.Uses)
|
||||
PDiff.addPressureChange(Reg, false, MRI);
|
||||
}
|
||||
|
||||
/// Force liveness of registers.
|
||||
void RegPressureTracker::addLiveRegs(ArrayRef<unsigned> Regs) {
|
||||
for (unsigned Reg : Regs) {
|
||||
@ -514,39 +499,10 @@ void RegPressureTracker::discoverLiveOut(unsigned Reg) {
|
||||
/// registers that are both defined and used by the instruction. If a pressure
|
||||
/// difference pointer is provided record the changes is pressure caused by this
|
||||
/// instruction independent of liveness.
|
||||
void RegPressureTracker::recede(SmallVectorImpl<unsigned> *LiveUses,
|
||||
PressureDiff *PDiff) {
|
||||
assert(CurrPos != MBB->begin());
|
||||
if (!isBottomClosed())
|
||||
closeBottom();
|
||||
|
||||
// Open the top of the region using block iterators.
|
||||
if (!RequireIntervals && isTopClosed())
|
||||
static_cast<RegionPressure&>(P).openTop(CurrPos);
|
||||
|
||||
// Find the previous instruction.
|
||||
do
|
||||
--CurrPos;
|
||||
while (CurrPos != MBB->begin() && CurrPos->isDebugValue());
|
||||
void RegPressureTracker::recede(const RegisterOperands &RegOpers,
|
||||
SmallVectorImpl<unsigned> *LiveUses) {
|
||||
assert(!CurrPos->isDebugValue());
|
||||
|
||||
SlotIndex SlotIdx;
|
||||
if (RequireIntervals)
|
||||
SlotIdx = LIS->getInstructionIndex(CurrPos).getRegSlot();
|
||||
|
||||
// Open the top of the region using slot indexes.
|
||||
if (RequireIntervals && isTopClosed())
|
||||
static_cast<IntervalPressure&>(P).openTop(SlotIdx);
|
||||
|
||||
const MachineInstr &MI = *CurrPos;
|
||||
RegisterOperands RegOpers;
|
||||
RegOpers.collect(MI, *TRI, *MRI);
|
||||
if (RequireIntervals)
|
||||
RegOpers.detectDeadDefs(MI, *LIS);
|
||||
|
||||
if (PDiff)
|
||||
collectPDiff(*PDiff, RegOpers, MRI);
|
||||
|
||||
// Boost pressure for all dead defs together.
|
||||
increaseRegPressure(RegOpers.DeadDefs);
|
||||
decreaseRegPressure(RegOpers.DeadDefs);
|
||||
@ -560,6 +516,10 @@ void RegPressureTracker::recede(SmallVectorImpl<unsigned> *LiveUses,
|
||||
discoverLiveOut(Reg);
|
||||
}
|
||||
|
||||
SlotIndex SlotIdx;
|
||||
if (RequireIntervals)
|
||||
SlotIdx = LIS->getInstructionIndex(CurrPos).getRegSlot();
|
||||
|
||||
// Generate liveness for uses.
|
||||
for (unsigned Reg : RegOpers.Uses) {
|
||||
if (!LiveRegs.contains(Reg)) {
|
||||
@ -586,6 +546,41 @@ void RegPressureTracker::recede(SmallVectorImpl<unsigned> *LiveUses,
|
||||
}
|
||||
}
|
||||
|
||||
void RegPressureTracker::recedeSkipDebugValues() {
|
||||
assert(CurrPos != MBB->begin());
|
||||
if (!isBottomClosed())
|
||||
closeBottom();
|
||||
|
||||
// Open the top of the region using block iterators.
|
||||
if (!RequireIntervals && isTopClosed())
|
||||
static_cast<RegionPressure&>(P).openTop(CurrPos);
|
||||
|
||||
// Find the previous instruction.
|
||||
do
|
||||
--CurrPos;
|
||||
while (CurrPos != MBB->begin() && CurrPos->isDebugValue());
|
||||
|
||||
SlotIndex SlotIdx;
|
||||
if (RequireIntervals)
|
||||
SlotIdx = LIS->getInstructionIndex(CurrPos).getRegSlot();
|
||||
|
||||
// Open the top of the region using slot indexes.
|
||||
if (RequireIntervals && isTopClosed())
|
||||
static_cast<IntervalPressure&>(P).openTop(SlotIdx);
|
||||
}
|
||||
|
||||
void RegPressureTracker::recede(SmallVectorImpl<unsigned> *LiveUses) {
|
||||
recedeSkipDebugValues();
|
||||
|
||||
const MachineInstr &MI = *CurrPos;
|
||||
RegisterOperands RegOpers;
|
||||
RegOpers.collect(MI, *TRI, *MRI);
|
||||
if (RequireIntervals)
|
||||
RegOpers.detectDeadDefs(MI, *LIS);
|
||||
|
||||
recede(RegOpers, LiveUses);
|
||||
}
|
||||
|
||||
/// Advance across the current instruction.
|
||||
void RegPressureTracker::advance() {
|
||||
assert(!TrackUntiedDefs && "unsupported mode");
|
||||
|
@ -896,11 +896,16 @@ void ScheduleDAGInstrs::buildSchedGraph(AliasAnalysis *AA,
|
||||
assert(SU && "No SUnit mapped to this MI");
|
||||
|
||||
if (RPTracker) {
|
||||
PressureDiff *PDiff = PDiffs ? &(*PDiffs)[SU->NodeNum] : nullptr;
|
||||
RPTracker->recede(/*LiveUses=*/nullptr, PDiff);
|
||||
assert(RPTracker->getPos() == std::prev(MII) &&
|
||||
"RPTracker can't find MI");
|
||||
collectVRegUses(SU);
|
||||
|
||||
RegisterOperands RegOpers;
|
||||
RegOpers.collect(*MI, *TRI, MRI);
|
||||
if (PDiffs != nullptr)
|
||||
PDiffs->addInstruction(SU->NodeNum, RegOpers, MRI);
|
||||
|
||||
RPTracker->recedeSkipDebugValues();
|
||||
assert(&*RPTracker->getPos() == MI && "RPTracker in sync");
|
||||
RPTracker->recede(RegOpers);
|
||||
}
|
||||
|
||||
assert(
|
||||
@ -1005,6 +1010,9 @@ void ScheduleDAGInstrs::buildSchedGraph(AliasAnalysis *AA,
|
||||
addChainDependency(AAForDep, MFI, MF.getDataLayout(), SU,
|
||||
I->second[i], RejectMemNodes, TrueMemOrderLatency);
|
||||
}
|
||||
// This call must come after calls to addChainDependency() since it
|
||||
// consumes the 'RejectMemNodes' list that addChainDependency() possibly
|
||||
// adds to.
|
||||
adjustChainDeps(AA, MFI, MF.getDataLayout(), SU, &ExitSU, RejectMemNodes,
|
||||
TrueMemOrderLatency);
|
||||
PendingLoads.clear();
|
||||
@ -1086,6 +1094,9 @@ void ScheduleDAGInstrs::buildSchedGraph(AliasAnalysis *AA,
|
||||
addChainDependency(AAForDep, MFI, MF.getDataLayout(), SU, AliasChain,
|
||||
RejectMemNodes);
|
||||
}
|
||||
// This call must come after calls to addChainDependency() since it
|
||||
// consumes the 'RejectMemNodes' list that addChainDependency() possibly
|
||||
// adds to.
|
||||
adjustChainDeps(AA, MFI, MF.getDataLayout(), SU, &ExitSU, RejectMemNodes,
|
||||
TrueMemOrderLatency);
|
||||
} else if (MI->mayLoad()) {
|
||||
@ -1133,13 +1144,16 @@ void ScheduleDAGInstrs::buildSchedGraph(AliasAnalysis *AA,
|
||||
else
|
||||
NonAliasMemUses[V].push_back(SU);
|
||||
}
|
||||
if (MayAlias)
|
||||
adjustChainDeps(AA, MFI, MF.getDataLayout(), SU, &ExitSU,
|
||||
RejectMemNodes, /*Latency=*/0);
|
||||
// Add dependencies on alias and barrier chains, if needed.
|
||||
if (MayAlias && AliasChain)
|
||||
addChainDependency(AAForDep, MFI, MF.getDataLayout(), SU, AliasChain,
|
||||
RejectMemNodes);
|
||||
if (MayAlias)
|
||||
// This call must come after calls to addChainDependency() since it
|
||||
// consumes the 'RejectMemNodes' list that addChainDependency()
|
||||
// possibly adds to.
|
||||
adjustChainDeps(AA, MFI, MF.getDataLayout(), SU, &ExitSU,
|
||||
RejectMemNodes, /*Latency=*/0);
|
||||
if (BarrierChain)
|
||||
BarrierChain->addPred(SDep(SU, SDep::Barrier));
|
||||
}
|
||||
|
@ -7325,6 +7325,7 @@ SDValue DAGCombiner::visitBITCAST(SDNode *N) {
|
||||
// fold (bitcast (fneg x)) ->
|
||||
// flipbit = signbit
|
||||
// (xor (bitcast x) (build_pair flipbit, flipbit))
|
||||
//
|
||||
// fold (bitcast (fabs x)) ->
|
||||
// flipbit = (and (extract_element (bitcast x), 0), signbit)
|
||||
// (xor (bitcast x) (build_pair flipbit, flipbit))
|
||||
@ -8794,20 +8795,21 @@ SDValue DAGCombiner::visitFSQRT(SDNode *N) {
|
||||
ZeroCmp, Zero, RV);
|
||||
}
|
||||
|
||||
/// copysign(x, fp_extend(y)) -> copysign(x, y)
|
||||
/// copysign(x, fp_round(y)) -> copysign(x, y)
|
||||
static inline bool CanCombineFCOPYSIGN_EXTEND_ROUND(SDNode *N) {
|
||||
// copysign(x, fp_extend(y)) -> copysign(x, y)
|
||||
// copysign(x, fp_round(y)) -> copysign(x, y)
|
||||
// Do not optimize out type conversion of f128 type yet.
|
||||
// For some target like x86_64, configuration is changed
|
||||
// to keep one f128 value in one SSE register, but
|
||||
// instruction selection cannot handle FCOPYSIGN on
|
||||
// SSE registers yet.
|
||||
SDValue N1 = N->getOperand(1);
|
||||
EVT N1VT = N1->getValueType(0);
|
||||
EVT N1Op0VT = N1->getOperand(0)->getValueType(0);
|
||||
return (N1.getOpcode() == ISD::FP_EXTEND ||
|
||||
N1.getOpcode() == ISD::FP_ROUND) &&
|
||||
(N1VT == N1Op0VT || N1Op0VT != MVT::f128);
|
||||
if ((N1.getOpcode() == ISD::FP_EXTEND ||
|
||||
N1.getOpcode() == ISD::FP_ROUND)) {
|
||||
// Do not optimize out type conversion of f128 type yet.
|
||||
// For some targets like x86_64, configuration is changed to keep one f128
|
||||
// value in one SSE register, but instruction selection cannot handle
|
||||
// FCOPYSIGN on SSE registers yet.
|
||||
EVT N1VT = N1->getValueType(0);
|
||||
EVT N1Op0VT = N1->getOperand(0)->getValueType(0);
|
||||
return (N1VT == N1Op0VT || N1Op0VT != MVT::f128);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
SDValue DAGCombiner::visitFCOPYSIGN(SDNode *N) {
|
||||
|
@ -297,8 +297,6 @@ void FunctionLoweringInfo::set(const Function &fn, MachineFunction &mf,
|
||||
else if (Personality == EHPersonality::CoreCLR)
|
||||
calculateClrEHStateNumbers(&fn, EHInfo);
|
||||
|
||||
calculateCatchReturnSuccessorColors(&fn, EHInfo);
|
||||
|
||||
// Map all BB references in the WinEH data to MBBs.
|
||||
for (WinEHTryBlockMapEntry &TBME : EHInfo.TryBlockMap) {
|
||||
for (WinEHHandlerType &H : TBME.HandlerArray) {
|
||||
|
@ -2941,6 +2941,18 @@ SDValue SelectionDAGLegalize::ExpandBitCount(unsigned Opc, SDValue Op,
|
||||
// This trivially expands to CTLZ.
|
||||
return DAG.getNode(ISD::CTLZ, dl, Op.getValueType(), Op);
|
||||
case ISD::CTLZ: {
|
||||
EVT VT = Op.getValueType();
|
||||
unsigned len = VT.getSizeInBits();
|
||||
|
||||
if (TLI.isOperationLegalOrCustom(ISD::CTLZ_ZERO_UNDEF, VT)) {
|
||||
EVT SetCCVT = getSetCCResultType(VT);
|
||||
SDValue CTLZ = DAG.getNode(ISD::CTLZ_ZERO_UNDEF, dl, VT, Op);
|
||||
SDValue Zero = DAG.getConstant(0, dl, VT);
|
||||
SDValue SrcIsZero = DAG.getSetCC(dl, SetCCVT, Op, Zero, ISD::SETEQ);
|
||||
return DAG.getNode(ISD::SELECT, dl, VT, SrcIsZero,
|
||||
DAG.getConstant(len, dl, VT), CTLZ);
|
||||
}
|
||||
|
||||
// for now, we do this:
|
||||
// x = x | (x >> 1);
|
||||
// x = x | (x >> 2);
|
||||
@ -2950,9 +2962,7 @@ SDValue SelectionDAGLegalize::ExpandBitCount(unsigned Opc, SDValue Op,
|
||||
// return popcount(~x);
|
||||
//
|
||||
// Ref: "Hacker's Delight" by Henry Warren
|
||||
EVT VT = Op.getValueType();
|
||||
EVT ShVT = TLI.getShiftAmountTy(VT, DAG.getDataLayout());
|
||||
unsigned len = VT.getSizeInBits();
|
||||
for (unsigned i = 0; (1U << i) <= (len / 2); ++i) {
|
||||
SDValue Tmp3 = DAG.getConstant(1ULL << i, dl, ShVT);
|
||||
Op = DAG.getNode(ISD::OR, dl, VT, Op,
|
||||
|
@ -262,12 +262,8 @@ SDValue DAGTypeLegalizer::PromoteIntRes_BITCAST(SDNode *N) {
|
||||
return DAG.getNode(ISD::ANY_EXTEND, dl, NOutVT, GetSoftenedFloat(InOp));
|
||||
case TargetLowering::TypePromoteFloat: {
|
||||
// Convert the promoted float by hand.
|
||||
if (NOutVT.bitsEq(NInVT)) {
|
||||
SDValue PromotedOp = GetPromotedFloat(InOp);
|
||||
SDValue Trunc = DAG.getNode(ISD::FP_TO_FP16, dl, NOutVT, PromotedOp);
|
||||
return DAG.getNode(ISD::AssertZext, dl, NOutVT, Trunc,
|
||||
DAG.getValueType(OutVT));
|
||||
}
|
||||
SDValue PromotedOp = GetPromotedFloat(InOp);
|
||||
return DAG.getNode(ISD::FP_TO_FP16, dl, NOutVT, PromotedOp);
|
||||
break;
|
||||
}
|
||||
case TargetLowering::TypeExpandInteger:
|
||||
|
@ -1205,8 +1205,13 @@ void SelectionDAGBuilder::visitCatchRet(const CatchReturnInst &I) {
|
||||
// Figure out the funclet membership for the catchret's successor.
|
||||
// This will be used by the FuncletLayout pass to determine how to order the
|
||||
// BB's.
|
||||
WinEHFuncInfo *EHInfo = DAG.getMachineFunction().getWinEHFuncInfo();
|
||||
const BasicBlock *SuccessorColor = EHInfo->CatchRetSuccessorColorMap[&I];
|
||||
// A 'catchret' returns to the outer scope's color.
|
||||
Value *ParentPad = I.getParentPad();
|
||||
const BasicBlock *SuccessorColor;
|
||||
if (isa<ConstantTokenNone>(ParentPad))
|
||||
SuccessorColor = &FuncInfo.Fn->getEntryBlock();
|
||||
else
|
||||
SuccessorColor = cast<Instruction>(ParentPad)->getParent();
|
||||
assert(SuccessorColor && "No parent funclet for catchret!");
|
||||
MachineBasicBlock *SuccessorColorMBB = FuncInfo.MBBMap[SuccessorColor];
|
||||
assert(SuccessorColorMBB && "No MBB for SuccessorColor!");
|
||||
|
@ -461,7 +461,9 @@ static void lowerIncomingStatepointValue(SDValue Incoming,
|
||||
// If the original value was a constant, make sure it gets recorded as
|
||||
// such in the stackmap. This is required so that the consumer can
|
||||
// parse any internal format to the deopt state. It also handles null
|
||||
// pointers and other constant pointers in GC states
|
||||
// pointers and other constant pointers in GC states. Note the constant
|
||||
// vectors do not appear to actually hit this path and that anything larger
|
||||
// than an i64 value (not type!) will fail asserts here.
|
||||
pushStackMapConstant(Ops, Builder, C->getSExtValue());
|
||||
} else if (FrameIndexSDNode *FI = dyn_cast<FrameIndexSDNode>(Incoming)) {
|
||||
// This handles allocas as arguments to the statepoint (this is only
|
||||
@ -505,27 +507,27 @@ static void lowerStatepointMetaArgs(SmallVectorImpl<SDValue> &Ops,
|
||||
|
||||
#ifndef NDEBUG
|
||||
// Check that each of the gc pointer and bases we've gotten out of the
|
||||
// safepoint is something the strategy thinks might be a pointer into the GC
|
||||
// heap. This is basically just here to help catch errors during statepoint
|
||||
// insertion. TODO: This should actually be in the Verifier, but we can't get
|
||||
// to the GCStrategy from there (yet).
|
||||
// safepoint is something the strategy thinks might be a pointer (or vector
|
||||
// of pointers) into the GC heap. This is basically just here to help catch
|
||||
// errors during statepoint insertion. TODO: This should actually be in the
|
||||
// Verifier, but we can't get to the GCStrategy from there (yet).
|
||||
GCStrategy &S = Builder.GFI->getStrategy();
|
||||
for (const Value *V : Bases) {
|
||||
auto Opt = S.isGCManagedPointer(V->getType());
|
||||
auto Opt = S.isGCManagedPointer(V->getType()->getScalarType());
|
||||
if (Opt.hasValue()) {
|
||||
assert(Opt.getValue() &&
|
||||
"non gc managed base pointer found in statepoint");
|
||||
}
|
||||
}
|
||||
for (const Value *V : Ptrs) {
|
||||
auto Opt = S.isGCManagedPointer(V->getType());
|
||||
auto Opt = S.isGCManagedPointer(V->getType()->getScalarType());
|
||||
if (Opt.hasValue()) {
|
||||
assert(Opt.getValue() &&
|
||||
"non gc managed derived pointer found in statepoint");
|
||||
}
|
||||
}
|
||||
for (const Value *V : Relocations) {
|
||||
auto Opt = S.isGCManagedPointer(V->getType());
|
||||
auto Opt = S.isGCManagedPointer(V->getType()->getScalarType());
|
||||
if (Opt.hasValue()) {
|
||||
assert(Opt.getValue() && "non gc managed pointer relocated");
|
||||
}
|
||||
|
@ -47,6 +47,7 @@
|
||||
// MachineFrameInfo is updated with this information.
|
||||
//===----------------------------------------------------------------------===//
|
||||
#include "llvm/ADT/BitVector.h"
|
||||
#include "llvm/ADT/PostOrderIterator.h"
|
||||
#include "llvm/ADT/SetVector.h"
|
||||
#include "llvm/ADT/Statistic.h"
|
||||
// To check for profitability.
|
||||
@ -263,6 +264,8 @@ MachineBasicBlock *FindIDom(MachineBasicBlock &Block, ListOfBBs BBs,
|
||||
if (!IDom)
|
||||
break;
|
||||
}
|
||||
if (IDom == &Block)
|
||||
return nullptr;
|
||||
return IDom;
|
||||
}
|
||||
|
||||
@ -352,13 +355,9 @@ void ShrinkWrap::updateSaveRestorePoints(MachineBasicBlock &MBB,
|
||||
if (MLI->getLoopDepth(Save) > MLI->getLoopDepth(Restore)) {
|
||||
// Push Save outside of this loop if immediate dominator is different
|
||||
// from save block. If immediate dominator is not different, bail out.
|
||||
MachineBasicBlock *IDom = FindIDom<>(*Save, Save->predecessors(), *MDT);
|
||||
if (IDom != Save)
|
||||
Save = IDom;
|
||||
else {
|
||||
Save = nullptr;
|
||||
Save = FindIDom<>(*Save, Save->predecessors(), *MDT);
|
||||
if (!Save)
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// If the loop does not exit, there is no point in looking
|
||||
// for a post-dominator outside the loop.
|
||||
@ -386,6 +385,41 @@ void ShrinkWrap::updateSaveRestorePoints(MachineBasicBlock &MBB,
|
||||
}
|
||||
}
|
||||
|
||||
/// Check whether the edge (\p SrcBB, \p DestBB) is a backedge according to MLI.
|
||||
/// I.e., check if it exists a loop that contains SrcBB and where DestBB is the
|
||||
/// loop header.
|
||||
static bool isProperBackedge(const MachineLoopInfo &MLI,
|
||||
const MachineBasicBlock *SrcBB,
|
||||
const MachineBasicBlock *DestBB) {
|
||||
for (const MachineLoop *Loop = MLI.getLoopFor(SrcBB); Loop;
|
||||
Loop = Loop->getParentLoop()) {
|
||||
if (Loop->getHeader() == DestBB)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Check if the CFG of \p MF is irreducible.
|
||||
static bool isIrreducibleCFG(const MachineFunction &MF,
|
||||
const MachineLoopInfo &MLI) {
|
||||
const MachineBasicBlock *Entry = &*MF.begin();
|
||||
ReversePostOrderTraversal<const MachineBasicBlock *> RPOT(Entry);
|
||||
BitVector VisitedBB(MF.getNumBlockIDs());
|
||||
for (const MachineBasicBlock *MBB : RPOT) {
|
||||
VisitedBB.set(MBB->getNumber());
|
||||
for (const MachineBasicBlock *SuccBB : MBB->successors()) {
|
||||
if (!VisitedBB.test(SuccBB->getNumber()))
|
||||
continue;
|
||||
// We already visited SuccBB, thus MBB->SuccBB must be a backedge.
|
||||
// Check that the head matches what we have in the loop information.
|
||||
// Otherwise, we have an irreducible graph.
|
||||
if (!isProperBackedge(MLI, MBB, SuccBB))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ShrinkWrap::runOnMachineFunction(MachineFunction &MF) {
|
||||
if (MF.empty() || !isShrinkWrapEnabled(MF))
|
||||
return false;
|
||||
@ -394,6 +428,17 @@ bool ShrinkWrap::runOnMachineFunction(MachineFunction &MF) {
|
||||
|
||||
init(MF);
|
||||
|
||||
if (isIrreducibleCFG(MF, *MLI)) {
|
||||
// If MF is irreducible, a block may be in a loop without
|
||||
// MachineLoopInfo reporting it. I.e., we may use the
|
||||
// post-dominance property in loops, which lead to incorrect
|
||||
// results. Moreover, we may miss that the prologue and
|
||||
// epilogue are not in the same loop, leading to unbalanced
|
||||
// construction/deconstruction of the stack frame.
|
||||
DEBUG(dbgs() << "Irreducible CFGs are not supported yet\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
const TargetRegisterInfo *TRI = MF.getSubtarget().getRegisterInfo();
|
||||
std::unique_ptr<RegScavenger> RS(
|
||||
TRI->requiresRegisterScavenging(MF) ? new RegScavenger() : nullptr);
|
||||
|
@ -43,6 +43,7 @@
|
||||
#include "llvm/CodeGen/PseudoSourceValue.h"
|
||||
#include "llvm/CodeGen/SlotIndexes.h"
|
||||
#include "llvm/CodeGen/StackProtector.h"
|
||||
#include "llvm/CodeGen/WinEHFuncInfo.h"
|
||||
#include "llvm/IR/DebugInfo.h"
|
||||
#include "llvm/IR/Dominators.h"
|
||||
#include "llvm/IR/Function.h"
|
||||
@ -570,6 +571,14 @@ void StackColoring::remapInstructions(DenseMap<int, int> &SlotRemap) {
|
||||
}
|
||||
}
|
||||
|
||||
// Update the location of C++ catch objects for the MSVC personality routine.
|
||||
if (WinEHFuncInfo *EHInfo = MF->getWinEHFuncInfo())
|
||||
for (WinEHTryBlockMapEntry &TBME : EHInfo->TryBlockMap)
|
||||
for (WinEHHandlerType &H : TBME.HandlerArray)
|
||||
if (H.CatchObj.FrameIndex != INT_MAX &&
|
||||
SlotRemap.count(H.CatchObj.FrameIndex))
|
||||
H.CatchObj.FrameIndex = SlotRemap[H.CatchObj.FrameIndex];
|
||||
|
||||
DEBUG(dbgs()<<"Fixed "<<FixedMemOp<<" machine memory operands.\n");
|
||||
DEBUG(dbgs()<<"Fixed "<<FixedDbg<<" debug locations.\n");
|
||||
DEBUG(dbgs()<<"Fixed "<<FixedInstr<<" machine instructions.\n");
|
||||
|
@ -144,10 +144,11 @@ static void addTryBlockMapEntry(WinEHFuncInfo &FuncInfo, int TryLow,
|
||||
HT.TypeDescriptor = cast<GlobalVariable>(TypeInfo->stripPointerCasts());
|
||||
HT.Adjectives = cast<ConstantInt>(CPI->getArgOperand(1))->getZExtValue();
|
||||
HT.Handler = CPI->getParent();
|
||||
if (isa<ConstantPointerNull>(CPI->getArgOperand(2)))
|
||||
HT.CatchObj.Alloca = nullptr;
|
||||
if (auto *AI =
|
||||
dyn_cast<AllocaInst>(CPI->getArgOperand(2)->stripPointerCasts()))
|
||||
HT.CatchObj.Alloca = AI;
|
||||
else
|
||||
HT.CatchObj.Alloca = cast<AllocaInst>(CPI->getArgOperand(2));
|
||||
HT.CatchObj.Alloca = nullptr;
|
||||
TBME.HandlerArray.push_back(HT);
|
||||
}
|
||||
FuncInfo.TryBlockMap.push_back(TBME);
|
||||
@ -664,24 +665,6 @@ void WinEHPrepare::colorFunclets(Function &F) {
|
||||
}
|
||||
}
|
||||
|
||||
void llvm::calculateCatchReturnSuccessorColors(const Function *Fn,
|
||||
WinEHFuncInfo &FuncInfo) {
|
||||
for (const BasicBlock &BB : *Fn) {
|
||||
const auto *CatchRet = dyn_cast<CatchReturnInst>(BB.getTerminator());
|
||||
if (!CatchRet)
|
||||
continue;
|
||||
// A 'catchret' returns to the outer scope's color.
|
||||
Value *ParentPad = CatchRet->getParentPad();
|
||||
const BasicBlock *Color;
|
||||
if (isa<ConstantTokenNone>(ParentPad))
|
||||
Color = &Fn->getEntryBlock();
|
||||
else
|
||||
Color = cast<Instruction>(ParentPad)->getParent();
|
||||
// Record the catchret successor's funclet membership.
|
||||
FuncInfo.CatchRetSuccessorColorMap[CatchRet] = Color;
|
||||
}
|
||||
}
|
||||
|
||||
void WinEHPrepare::demotePHIsOnFunclets(Function &F) {
|
||||
// Strip PHI nodes off of EH pads.
|
||||
SmallVector<PHINode *, 16> PHINodes;
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include "llvm/DebugInfo/Symbolize/DIPrinter.h"
|
||||
|
||||
#include "llvm/DebugInfo/DIContext.h"
|
||||
#include "llvm/Support/LineIterator.h"
|
||||
|
||||
namespace llvm {
|
||||
namespace symbolize {
|
||||
@ -24,7 +25,37 @@ namespace symbolize {
|
||||
static const char kDILineInfoBadString[] = "<invalid>";
|
||||
static const char kBadString[] = "??";
|
||||
|
||||
void DIPrinter::printName(const DILineInfo &Info, bool Inlined) {
|
||||
// Prints source code around in the FileName the Line.
|
||||
void DIPrinter::printContext(std::string FileName, int64_t Line) {
|
||||
if (PrintSourceContext <= 0)
|
||||
return;
|
||||
|
||||
ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =
|
||||
MemoryBuffer::getFile(FileName);
|
||||
if (!BufOrErr)
|
||||
return;
|
||||
|
||||
std::unique_ptr<MemoryBuffer> Buf = std::move(BufOrErr.get());
|
||||
int64_t FirstLine =
|
||||
std::max(static_cast<int64_t>(1), Line - PrintSourceContext / 2);
|
||||
int64_t LastLine = FirstLine + PrintSourceContext;
|
||||
size_t MaxLineNumberWidth = std::ceil(std::log10(LastLine));
|
||||
|
||||
for (line_iterator I = line_iterator(*Buf, false);
|
||||
!I.is_at_eof() && I.line_number() <= LastLine; ++I) {
|
||||
int64_t L = I.line_number();
|
||||
if (L >= FirstLine && L <= LastLine) {
|
||||
OS << format_decimal(L, MaxLineNumberWidth);
|
||||
if (L == Line)
|
||||
OS << " >: ";
|
||||
else
|
||||
OS << " : ";
|
||||
OS << *I << "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DIPrinter::print(const DILineInfo &Info, bool Inlined) {
|
||||
if (PrintFunctionNames) {
|
||||
std::string FunctionName = Info.FunctionName;
|
||||
if (FunctionName == kDILineInfoBadString)
|
||||
@ -38,21 +69,22 @@ void DIPrinter::printName(const DILineInfo &Info, bool Inlined) {
|
||||
if (Filename == kDILineInfoBadString)
|
||||
Filename = kBadString;
|
||||
OS << Filename << ":" << Info.Line << ":" << Info.Column << "\n";
|
||||
printContext(Filename, Info.Line);
|
||||
}
|
||||
|
||||
DIPrinter &DIPrinter::operator<<(const DILineInfo &Info) {
|
||||
printName(Info, false);
|
||||
print(Info, false);
|
||||
return *this;
|
||||
}
|
||||
|
||||
DIPrinter &DIPrinter::operator<<(const DIInliningInfo &Info) {
|
||||
uint32_t FramesNum = Info.getNumberOfFrames();
|
||||
if (FramesNum == 0) {
|
||||
printName(DILineInfo(), false);
|
||||
print(DILineInfo(), false);
|
||||
return *this;
|
||||
}
|
||||
for (uint32_t i = 0; i < FramesNum; i++)
|
||||
printName(Info.getFrame(i), i > 0);
|
||||
print(Info.getFrame(i), i > 0);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
//===------- OrcTargetSupport.cpp - Target support utilities for Orc ------===//
|
||||
//===------ OrcArchSupport.cpp - Architecture specific support code -------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
@ -8,7 +8,7 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/ADT/Triple.h"
|
||||
#include "llvm/ExecutionEngine/Orc/OrcTargetSupport.h"
|
||||
#include "llvm/ExecutionEngine/Orc/OrcArchitectureSupport.h"
|
||||
#include "llvm/Support/Process.h"
|
||||
#include <array>
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
#include "OrcCBindingsStack.h"
|
||||
|
||||
#include "llvm/ExecutionEngine/Orc/OrcTargetSupport.h"
|
||||
#include "llvm/ExecutionEngine/Orc/OrcArchitectureSupport.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/DynamicLibrary.h"
|
||||
#include <cstdio>
|
||||
|
@ -221,7 +221,8 @@ class OrcCBindingsStack {
|
||||
ModuleHandleT addIRModuleLazy(Module* M,
|
||||
LLVMOrcSymbolResolverFn ExternalResolver,
|
||||
void *ExternalResolverCtx) {
|
||||
return addIRModule(CODLayer, std::move(M), nullptr,
|
||||
return addIRModule(CODLayer, std::move(M),
|
||||
llvm::make_unique<SectionMemoryManager>(),
|
||||
std::move(ExternalResolver), ExternalResolverCtx);
|
||||
}
|
||||
|
||||
|
57
contrib/llvm/lib/ExecutionEngine/Orc/OrcError.cpp
Normal file
57
contrib/llvm/lib/ExecutionEngine/Orc/OrcError.cpp
Normal file
@ -0,0 +1,57 @@
|
||||
//===---------------- OrcError.cpp - Error codes for ORC ------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Error codes for ORC.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/ExecutionEngine/Orc/OrcError.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Support/ManagedStatic.h"
|
||||
|
||||
using namespace llvm;
|
||||
using namespace llvm::orc;
|
||||
|
||||
namespace {
|
||||
|
||||
class OrcErrorCategory : public std::error_category {
|
||||
public:
|
||||
const char *name() const LLVM_NOEXCEPT override { return "orc"; }
|
||||
|
||||
std::string message(int condition) const override {
|
||||
switch (static_cast<OrcErrorCode>(condition)) {
|
||||
case OrcErrorCode::RemoteAllocatorDoesNotExist:
|
||||
return "Remote allocator does not exist";
|
||||
case OrcErrorCode::RemoteAllocatorIdAlreadyInUse:
|
||||
return "Remote allocator Id already in use";
|
||||
case OrcErrorCode::RemoteMProtectAddrUnrecognized:
|
||||
return "Remote mprotect call references unallocated memory";
|
||||
case OrcErrorCode::RemoteIndirectStubsOwnerDoesNotExist:
|
||||
return "Remote indirect stubs owner does not exist";
|
||||
case OrcErrorCode::RemoteIndirectStubsOwnerIdAlreadyInUse:
|
||||
return "Remote indirect stubs owner Id already in use";
|
||||
case OrcErrorCode::UnexpectedRPCCall:
|
||||
return "Unexpected RPC call";
|
||||
}
|
||||
llvm_unreachable("Unhandled error code");
|
||||
}
|
||||
};
|
||||
|
||||
static ManagedStatic<OrcErrorCategory> OrcErrCat;
|
||||
}
|
||||
|
||||
namespace llvm {
|
||||
namespace orc {
|
||||
|
||||
std::error_code orcError(OrcErrorCode ErrCode) {
|
||||
typedef std::underlying_type<OrcErrorCode>::type UT;
|
||||
return std::error_code(static_cast<UT>(ErrCode), *OrcErrCat);
|
||||
}
|
||||
}
|
||||
}
|
@ -54,10 +54,13 @@ class OrcMCJITReplacement : public ExecutionEngine {
|
||||
return Addr;
|
||||
}
|
||||
|
||||
void reserveAllocationSpace(uintptr_t CodeSize, uintptr_t DataSizeRO,
|
||||
uintptr_t DataSizeRW) override {
|
||||
return ClientMM->reserveAllocationSpace(CodeSize, DataSizeRO,
|
||||
DataSizeRW);
|
||||
void reserveAllocationSpace(uintptr_t CodeSize, uint32_t CodeAlign,
|
||||
uintptr_t RODataSize, uint32_t RODataAlign,
|
||||
uintptr_t RWDataSize,
|
||||
uint32_t RWDataAlign) override {
|
||||
return ClientMM->reserveAllocationSpace(CodeSize, CodeAlign,
|
||||
RODataSize, RODataAlign,
|
||||
RWDataSize, RWDataAlign);
|
||||
}
|
||||
|
||||
bool needsToReserveAllocationSpace() override {
|
||||
@ -74,6 +77,11 @@ class OrcMCJITReplacement : public ExecutionEngine {
|
||||
return ClientMM->deregisterEHFrames(Addr, LoadAddr, Size);
|
||||
}
|
||||
|
||||
void notifyObjectLoaded(RuntimeDyld &RTDyld,
|
||||
const object::ObjectFile &O) override {
|
||||
return ClientMM->notifyObjectLoaded(RTDyld, O);
|
||||
}
|
||||
|
||||
void notifyObjectLoaded(ExecutionEngine *EE,
|
||||
const object::ObjectFile &O) override {
|
||||
return ClientMM->notifyObjectLoaded(EE, O);
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user