Update llvm, clang and lldb to trunk r257626, and update build glue.

This commit is contained in:
dim 2016-01-14 17:42:46 +00:00
commit 8e5c968a84
522 changed files with 20308 additions and 7672 deletions

View File

@ -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.

View 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

View File

@ -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 {

View 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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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.

View File

@ -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.

View File

@ -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();

View File

@ -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

View File

@ -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);

View File

@ -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;

View File

@ -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:

View File

@ -108,9 +108,7 @@ class ObjectLinkingLayer : public ObjectLinkingLayerBase {
void Finalize() override {
State = Finalizing;
RTDyld->resolveRelocations();
RTDyld->registerEHFrames();
MemMgr->finalizeMemory();
RTDyld->finalizeWithMemoryManagerLocking();
State = Finalized;
}

View File

@ -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

View 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

View File

@ -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

View File

@ -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

View File

@ -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

View 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

View 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

View File

@ -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

View File

@ -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.

View File

@ -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">;

View File

@ -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.

View File

@ -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.

View File

@ -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]>;

View File

@ -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.".

View File

@ -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);

View File

@ -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().

View File

@ -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&);

View File

@ -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);

View File

@ -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

View File

@ -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
};

View File

@ -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 {

View File

@ -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.

View File

@ -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;

View File

@ -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;

View File

@ -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,

View File

@ -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_

View File

@ -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 {

View File

@ -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

View File

@ -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) {

View File

@ -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());
}

View File

@ -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,

View File

@ -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.

View File

@ -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)

View File

@ -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);
}
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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
///

View File

@ -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.

View File

@ -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;

View File

@ -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;

View File

@ -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.
}

View File

@ -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) {

View File

@ -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

View File

@ -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()) {

View File

@ -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.

View File

@ -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.
//

View File

@ -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.
//

View File

@ -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:

View File

@ -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");
}

View File

@ -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)) {

View File

@ -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.

View 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
//===----------------------------------------------------------------------===//

View File

@ -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,

View File

@ -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.

View File

@ -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();

View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -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);
}
}

View File

@ -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');

View File

@ -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.

View File

@ -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;

View File

@ -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);

View File

@ -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())

View File

@ -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);

View File

@ -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)));

View File

@ -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");

View File

@ -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));
}

View File

@ -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) {

View File

@ -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) {

View File

@ -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,

View File

@ -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:

View File

@ -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!");

View File

@ -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");
}

View File

@ -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);

View File

@ -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");

View File

@ -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;

View File

@ -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;
}

View File

@ -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>

View File

@ -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>

View File

@ -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);
}

View 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);
}
}
}

View File

@ -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