Vendor import of llvm trunk r304659:
https://llvm.org/svn/llvm-project/llvm/trunk@304659
This commit is contained in:
parent
f382538d47
commit
d288ef4c17
@ -415,6 +415,9 @@ public:
|
||||
append(IL.begin(), IL.end());
|
||||
}
|
||||
|
||||
// FIXME: Consider assigning over existing elements, rather than clearing &
|
||||
// re-initializing them - for all assign(...) variants.
|
||||
|
||||
void assign(size_type NumElts, const T &Elt) {
|
||||
clear();
|
||||
if (this->capacity() < NumElts)
|
||||
@ -423,6 +426,11 @@ public:
|
||||
std::uninitialized_fill(this->begin(), this->end(), Elt);
|
||||
}
|
||||
|
||||
template <typename in_iter> void assign(in_iter in_start, in_iter in_end) {
|
||||
clear();
|
||||
append(in_start, in_end);
|
||||
}
|
||||
|
||||
void assign(std::initializer_list<T> IL) {
|
||||
clear();
|
||||
append(IL);
|
||||
|
@ -58,6 +58,7 @@ public:
|
||||
/// comes before \p B in \p BB. This is a simplification that considers
|
||||
/// cached instruction positions and ignores other basic blocks, being
|
||||
/// only relevant to compare relative instructions positions inside \p BB.
|
||||
/// Returns false for A == B.
|
||||
bool dominates(const Instruction *A, const Instruction *B);
|
||||
};
|
||||
|
||||
|
@ -78,6 +78,11 @@ public:
|
||||
return PMT_RegionPassManager;
|
||||
}
|
||||
//@}
|
||||
|
||||
protected:
|
||||
/// Optional passes call this function to check whether the pass should be
|
||||
/// skipped. This is the case when optimization bisect is over the limit.
|
||||
bool skipRegion(Region &R) const;
|
||||
};
|
||||
|
||||
/// @brief The pass manager to schedule RegionPasses.
|
||||
|
@ -636,7 +636,7 @@ private:
|
||||
/// @}
|
||||
|
||||
public:
|
||||
BackedgeTakenInfo() : MaxAndComplete(nullptr, 0) {}
|
||||
BackedgeTakenInfo() : MaxAndComplete(nullptr, 0), MaxOrZero(false) {}
|
||||
|
||||
BackedgeTakenInfo(BackedgeTakenInfo &&) = default;
|
||||
BackedgeTakenInfo &operator=(BackedgeTakenInfo &&) = default;
|
||||
|
@ -10,83 +10,77 @@
|
||||
#ifndef LLVM_CODEGEN_MACHINEREGIONINFO_H
|
||||
#define LLVM_CODEGEN_MACHINEREGIONINFO_H
|
||||
|
||||
#include "llvm/ADT/DepthFirstIterator.h"
|
||||
#include "llvm/Analysis/RegionInfo.h"
|
||||
#include "llvm/Analysis/RegionIterator.h"
|
||||
#include "llvm/CodeGen/MachineBasicBlock.h"
|
||||
#include "llvm/CodeGen/MachineDominanceFrontier.h"
|
||||
#include "llvm/CodeGen/MachineDominators.h"
|
||||
#include "llvm/CodeGen/MachineFunction.h"
|
||||
#include "llvm/CodeGen/MachineFunctionPass.h"
|
||||
#include "llvm/CodeGen/MachineLoopInfo.h"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class MachineDominatorTree;
|
||||
struct MachinePostDominatorTree;
|
||||
class MachineRegion;
|
||||
class MachineRegionNode;
|
||||
class MachineRegionInfo;
|
||||
|
||||
template<>
|
||||
struct RegionTraits<MachineFunction> {
|
||||
typedef MachineFunction FuncT;
|
||||
typedef MachineBasicBlock BlockT;
|
||||
typedef MachineRegion RegionT;
|
||||
typedef MachineRegionNode RegionNodeT;
|
||||
typedef MachineRegionInfo RegionInfoT;
|
||||
typedef MachineDominatorTree DomTreeT;
|
||||
typedef MachineDomTreeNode DomTreeNodeT;
|
||||
typedef MachinePostDominatorTree PostDomTreeT;
|
||||
typedef MachineDominanceFrontier DomFrontierT;
|
||||
typedef MachineInstr InstT;
|
||||
typedef MachineLoop LoopT;
|
||||
typedef MachineLoopInfo LoopInfoT;
|
||||
template <> struct RegionTraits<MachineFunction> {
|
||||
using FuncT = MachineFunction;
|
||||
using BlockT = MachineBasicBlock;
|
||||
using RegionT = MachineRegion;
|
||||
using RegionNodeT = MachineRegionNode;
|
||||
using RegionInfoT = MachineRegionInfo;
|
||||
using DomTreeT = MachineDominatorTree;
|
||||
using DomTreeNodeT = MachineDomTreeNode;
|
||||
using PostDomTreeT = MachinePostDominatorTree;
|
||||
using DomFrontierT = MachineDominanceFrontier;
|
||||
using InstT = MachineInstr;
|
||||
using LoopT = MachineLoop;
|
||||
using LoopInfoT = MachineLoopInfo;
|
||||
|
||||
static unsigned getNumSuccessors(MachineBasicBlock *BB) {
|
||||
return BB->succ_size();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class MachineRegionNode : public RegionNodeBase<RegionTraits<MachineFunction>> {
|
||||
public:
|
||||
inline MachineRegionNode(MachineRegion *Parent,
|
||||
MachineBasicBlock *Entry,
|
||||
inline MachineRegionNode(MachineRegion *Parent, MachineBasicBlock *Entry,
|
||||
bool isSubRegion = false)
|
||||
: RegionNodeBase<RegionTraits<MachineFunction>>(Parent, Entry, isSubRegion) {
|
||||
|
||||
}
|
||||
: RegionNodeBase<RegionTraits<MachineFunction>>(Parent, Entry,
|
||||
isSubRegion) {}
|
||||
|
||||
bool operator==(const MachineRegion &RN) const {
|
||||
return this == reinterpret_cast<const MachineRegionNode*>(&RN);
|
||||
return this == reinterpret_cast<const MachineRegionNode *>(&RN);
|
||||
}
|
||||
};
|
||||
|
||||
class MachineRegion : public RegionBase<RegionTraits<MachineFunction>> {
|
||||
public:
|
||||
MachineRegion(MachineBasicBlock *Entry, MachineBasicBlock *Exit,
|
||||
MachineRegionInfo* RI,
|
||||
MachineDominatorTree *DT, MachineRegion *Parent = nullptr);
|
||||
MachineRegionInfo *RI, MachineDominatorTree *DT,
|
||||
MachineRegion *Parent = nullptr);
|
||||
~MachineRegion();
|
||||
|
||||
bool operator==(const MachineRegionNode &RN) const {
|
||||
return &RN == reinterpret_cast<const MachineRegionNode*>(this);
|
||||
return &RN == reinterpret_cast<const MachineRegionNode *>(this);
|
||||
}
|
||||
};
|
||||
|
||||
class MachineRegionInfo : public RegionInfoBase<RegionTraits<MachineFunction>> {
|
||||
public:
|
||||
explicit MachineRegionInfo();
|
||||
|
||||
~MachineRegionInfo() override;
|
||||
|
||||
// updateStatistics - Update statistic about created regions.
|
||||
void updateStatistics(MachineRegion *R) final;
|
||||
|
||||
void recalculate(MachineFunction &F,
|
||||
MachineDominatorTree *DT,
|
||||
MachinePostDominatorTree *PDT,
|
||||
MachineDominanceFrontier *DF);
|
||||
void recalculate(MachineFunction &F, MachineDominatorTree *DT,
|
||||
MachinePostDominatorTree *PDT, MachineDominanceFrontier *DF);
|
||||
};
|
||||
|
||||
class MachineRegionInfoPass : public MachineFunctionPass {
|
||||
@ -94,17 +88,13 @@ class MachineRegionInfoPass : public MachineFunctionPass {
|
||||
|
||||
public:
|
||||
static char ID;
|
||||
explicit MachineRegionInfoPass();
|
||||
|
||||
explicit MachineRegionInfoPass();
|
||||
~MachineRegionInfoPass() override;
|
||||
|
||||
MachineRegionInfo &getRegionInfo() {
|
||||
return RI;
|
||||
}
|
||||
MachineRegionInfo &getRegionInfo() { return RI; }
|
||||
|
||||
const MachineRegionInfo &getRegionInfo() const {
|
||||
return RI;
|
||||
}
|
||||
const MachineRegionInfo &getRegionInfo() const { return RI; }
|
||||
|
||||
/// @name MachineFunctionPass interface
|
||||
//@{
|
||||
@ -117,66 +107,76 @@ public:
|
||||
//@}
|
||||
};
|
||||
|
||||
|
||||
template <>
|
||||
template <>
|
||||
inline MachineBasicBlock* RegionNodeBase<RegionTraits<MachineFunction>>::getNodeAs<MachineBasicBlock>() const {
|
||||
inline MachineBasicBlock *
|
||||
RegionNodeBase<RegionTraits<MachineFunction>>::getNodeAs<MachineBasicBlock>()
|
||||
const {
|
||||
assert(!isSubRegion() && "This is not a MachineBasicBlock RegionNode!");
|
||||
return getEntry();
|
||||
}
|
||||
|
||||
template<>
|
||||
template<>
|
||||
inline MachineRegion* RegionNodeBase<RegionTraits<MachineFunction>>::getNodeAs<MachineRegion>() const {
|
||||
template <>
|
||||
template <>
|
||||
inline MachineRegion *
|
||||
RegionNodeBase<RegionTraits<MachineFunction>>::getNodeAs<MachineRegion>()
|
||||
const {
|
||||
assert(isSubRegion() && "This is not a subregion RegionNode!");
|
||||
auto Unconst = const_cast<RegionNodeBase<RegionTraits<MachineFunction>>*>(this);
|
||||
return reinterpret_cast<MachineRegion*>(Unconst);
|
||||
auto Unconst =
|
||||
const_cast<RegionNodeBase<RegionTraits<MachineFunction>> *>(this);
|
||||
return reinterpret_cast<MachineRegion *>(Unconst);
|
||||
}
|
||||
|
||||
|
||||
RegionNodeGraphTraits(MachineRegionNode, MachineBasicBlock, MachineRegion);
|
||||
RegionNodeGraphTraits(const MachineRegionNode, MachineBasicBlock, MachineRegion);
|
||||
RegionNodeGraphTraits(const MachineRegionNode, MachineBasicBlock,
|
||||
MachineRegion);
|
||||
|
||||
RegionGraphTraits(MachineRegion, MachineRegionNode);
|
||||
RegionGraphTraits(const MachineRegion, const MachineRegionNode);
|
||||
|
||||
template <> struct GraphTraits<MachineRegionInfo*>
|
||||
: public GraphTraits<FlatIt<MachineRegionNode*> > {
|
||||
typedef df_iterator<NodeRef, df_iterator_default_set<NodeRef>, false,
|
||||
GraphTraits<FlatIt<NodeRef>>>
|
||||
nodes_iterator;
|
||||
template <>
|
||||
struct GraphTraits<MachineRegionInfo *>
|
||||
: public GraphTraits<FlatIt<MachineRegionNode *>> {
|
||||
using nodes_iterator = df_iterator<NodeRef, df_iterator_default_set<NodeRef>,
|
||||
false, GraphTraits<FlatIt<NodeRef>>>;
|
||||
|
||||
static NodeRef getEntryNode(MachineRegionInfo *RI) {
|
||||
return GraphTraits<FlatIt<MachineRegion*> >::getEntryNode(RI->getTopLevelRegion());
|
||||
return GraphTraits<FlatIt<MachineRegion *>>::getEntryNode(
|
||||
RI->getTopLevelRegion());
|
||||
}
|
||||
static nodes_iterator nodes_begin(MachineRegionInfo* RI) {
|
||||
|
||||
static nodes_iterator nodes_begin(MachineRegionInfo *RI) {
|
||||
return nodes_iterator::begin(getEntryNode(RI));
|
||||
}
|
||||
|
||||
static nodes_iterator nodes_end(MachineRegionInfo *RI) {
|
||||
return nodes_iterator::end(getEntryNode(RI));
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct GraphTraits<MachineRegionInfoPass*>
|
||||
: public GraphTraits<MachineRegionInfo *> {
|
||||
typedef df_iterator<NodeRef, df_iterator_default_set<NodeRef>, false,
|
||||
GraphTraits<FlatIt<NodeRef>>>
|
||||
nodes_iterator;
|
||||
template <>
|
||||
struct GraphTraits<MachineRegionInfoPass *>
|
||||
: public GraphTraits<MachineRegionInfo *> {
|
||||
using nodes_iterator = df_iterator<NodeRef, df_iterator_default_set<NodeRef>,
|
||||
false, GraphTraits<FlatIt<NodeRef>>>;
|
||||
|
||||
static NodeRef getEntryNode(MachineRegionInfoPass *RI) {
|
||||
return GraphTraits<MachineRegionInfo*>::getEntryNode(&RI->getRegionInfo());
|
||||
return GraphTraits<MachineRegionInfo *>::getEntryNode(&RI->getRegionInfo());
|
||||
}
|
||||
static nodes_iterator nodes_begin(MachineRegionInfoPass* RI) {
|
||||
return GraphTraits<MachineRegionInfo*>::nodes_begin(&RI->getRegionInfo());
|
||||
|
||||
static nodes_iterator nodes_begin(MachineRegionInfoPass *RI) {
|
||||
return GraphTraits<MachineRegionInfo *>::nodes_begin(&RI->getRegionInfo());
|
||||
}
|
||||
|
||||
static nodes_iterator nodes_end(MachineRegionInfoPass *RI) {
|
||||
return GraphTraits<MachineRegionInfo*>::nodes_end(&RI->getRegionInfo());
|
||||
return GraphTraits<MachineRegionInfo *>::nodes_end(&RI->getRegionInfo());
|
||||
}
|
||||
};
|
||||
|
||||
extern template class RegionBase<RegionTraits<MachineFunction>>;
|
||||
extern template class RegionNodeBase<RegionTraits<MachineFunction>>;
|
||||
extern template class RegionInfoBase<RegionTraits<MachineFunction>>;
|
||||
}
|
||||
|
||||
#endif
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_CODEGEN_MACHINEREGIONINFO_H
|
||||
|
@ -14,11 +14,13 @@
|
||||
#ifndef LLVM_CODEGEN_MACHINEREGISTERINFO_H
|
||||
#define LLVM_CODEGEN_MACHINEREGISTERINFO_H
|
||||
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/BitVector.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/IndexedMap.h"
|
||||
#include "llvm/ADT/iterator_range.h"
|
||||
#include "llvm/ADT/PointerUnion.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/CodeGen/GlobalISel/RegisterBank.h"
|
||||
#include "llvm/CodeGen/LowLevelType.h"
|
||||
#include "llvm/CodeGen/MachineBasicBlock.h"
|
||||
@ -41,8 +43,8 @@ namespace llvm {
|
||||
class PSetIterator;
|
||||
|
||||
/// Convenient type to represent either a register class or a register bank.
|
||||
typedef PointerUnion<const TargetRegisterClass *, const RegisterBank *>
|
||||
RegClassOrRegBank;
|
||||
using RegClassOrRegBank =
|
||||
PointerUnion<const TargetRegisterClass *, const RegisterBank *>;
|
||||
|
||||
/// MachineRegisterInfo - Keep track of information for virtual and physical
|
||||
/// registers, including vreg register classes, use/def chains for registers,
|
||||
@ -125,7 +127,7 @@ private:
|
||||
/// started.
|
||||
BitVector ReservedRegs;
|
||||
|
||||
typedef DenseMap<unsigned, LLT> VRegToTypeMap;
|
||||
using VRegToTypeMap = DenseMap<unsigned, LLT>;
|
||||
/// Map generic virtual registers to their actual size.
|
||||
mutable std::unique_ptr<VRegToTypeMap> VRegToType;
|
||||
|
||||
@ -266,8 +268,8 @@ public:
|
||||
|
||||
/// reg_iterator/reg_begin/reg_end - Walk all defs and uses of the specified
|
||||
/// register.
|
||||
typedef defusechain_iterator<true,true,false,true,false,false>
|
||||
reg_iterator;
|
||||
using reg_iterator =
|
||||
defusechain_iterator<true, true, false, true, false, false>;
|
||||
reg_iterator reg_begin(unsigned RegNo) const {
|
||||
return reg_iterator(getRegUseDefListHead(RegNo));
|
||||
}
|
||||
@ -279,8 +281,8 @@ public:
|
||||
|
||||
/// reg_instr_iterator/reg_instr_begin/reg_instr_end - Walk all defs and uses
|
||||
/// of the specified register, stepping by MachineInstr.
|
||||
typedef defusechain_instr_iterator<true,true,false,false,true,false>
|
||||
reg_instr_iterator;
|
||||
using reg_instr_iterator =
|
||||
defusechain_instr_iterator<true, true, false, false, true, false>;
|
||||
reg_instr_iterator reg_instr_begin(unsigned RegNo) const {
|
||||
return reg_instr_iterator(getRegUseDefListHead(RegNo));
|
||||
}
|
||||
@ -295,8 +297,8 @@ public:
|
||||
|
||||
/// reg_bundle_iterator/reg_bundle_begin/reg_bundle_end - Walk all defs and uses
|
||||
/// of the specified register, stepping by bundle.
|
||||
typedef defusechain_instr_iterator<true,true,false,false,false,true>
|
||||
reg_bundle_iterator;
|
||||
using reg_bundle_iterator =
|
||||
defusechain_instr_iterator<true, true, false, false, false, true>;
|
||||
reg_bundle_iterator reg_bundle_begin(unsigned RegNo) const {
|
||||
return reg_bundle_iterator(getRegUseDefListHead(RegNo));
|
||||
}
|
||||
@ -314,8 +316,8 @@ public:
|
||||
|
||||
/// reg_nodbg_iterator/reg_nodbg_begin/reg_nodbg_end - Walk all defs and uses
|
||||
/// of the specified register, skipping those marked as Debug.
|
||||
typedef defusechain_iterator<true,true,true,true,false,false>
|
||||
reg_nodbg_iterator;
|
||||
using reg_nodbg_iterator =
|
||||
defusechain_iterator<true, true, true, true, false, false>;
|
||||
reg_nodbg_iterator reg_nodbg_begin(unsigned RegNo) const {
|
||||
return reg_nodbg_iterator(getRegUseDefListHead(RegNo));
|
||||
}
|
||||
@ -331,8 +333,8 @@ public:
|
||||
/// reg_instr_nodbg_iterator/reg_instr_nodbg_begin/reg_instr_nodbg_end - Walk
|
||||
/// all defs and uses of the specified register, stepping by MachineInstr,
|
||||
/// skipping those marked as Debug.
|
||||
typedef defusechain_instr_iterator<true,true,true,false,true,false>
|
||||
reg_instr_nodbg_iterator;
|
||||
using reg_instr_nodbg_iterator =
|
||||
defusechain_instr_iterator<true, true, true, false, true, false>;
|
||||
reg_instr_nodbg_iterator reg_instr_nodbg_begin(unsigned RegNo) const {
|
||||
return reg_instr_nodbg_iterator(getRegUseDefListHead(RegNo));
|
||||
}
|
||||
@ -348,8 +350,8 @@ public:
|
||||
/// reg_bundle_nodbg_iterator/reg_bundle_nodbg_begin/reg_bundle_nodbg_end - Walk
|
||||
/// all defs and uses of the specified register, stepping by bundle,
|
||||
/// skipping those marked as Debug.
|
||||
typedef defusechain_instr_iterator<true,true,true,false,false,true>
|
||||
reg_bundle_nodbg_iterator;
|
||||
using reg_bundle_nodbg_iterator =
|
||||
defusechain_instr_iterator<true, true, true, false, false, true>;
|
||||
reg_bundle_nodbg_iterator reg_bundle_nodbg_begin(unsigned RegNo) const {
|
||||
return reg_bundle_nodbg_iterator(getRegUseDefListHead(RegNo));
|
||||
}
|
||||
@ -369,8 +371,8 @@ public:
|
||||
}
|
||||
|
||||
/// def_iterator/def_begin/def_end - Walk all defs of the specified register.
|
||||
typedef defusechain_iterator<false,true,false,true,false,false>
|
||||
def_iterator;
|
||||
using def_iterator =
|
||||
defusechain_iterator<false, true, false, true, false, false>;
|
||||
def_iterator def_begin(unsigned RegNo) const {
|
||||
return def_iterator(getRegUseDefListHead(RegNo));
|
||||
}
|
||||
@ -382,8 +384,8 @@ public:
|
||||
|
||||
/// def_instr_iterator/def_instr_begin/def_instr_end - Walk all defs of the
|
||||
/// specified register, stepping by MachineInst.
|
||||
typedef defusechain_instr_iterator<false,true,false,false,true,false>
|
||||
def_instr_iterator;
|
||||
using def_instr_iterator =
|
||||
defusechain_instr_iterator<false, true, false, false, true, false>;
|
||||
def_instr_iterator def_instr_begin(unsigned RegNo) const {
|
||||
return def_instr_iterator(getRegUseDefListHead(RegNo));
|
||||
}
|
||||
@ -398,8 +400,8 @@ public:
|
||||
|
||||
/// def_bundle_iterator/def_bundle_begin/def_bundle_end - Walk all defs of the
|
||||
/// specified register, stepping by bundle.
|
||||
typedef defusechain_instr_iterator<false,true,false,false,false,true>
|
||||
def_bundle_iterator;
|
||||
using def_bundle_iterator =
|
||||
defusechain_instr_iterator<false, true, false, false, false, true>;
|
||||
def_bundle_iterator def_bundle_begin(unsigned RegNo) const {
|
||||
return def_bundle_iterator(getRegUseDefListHead(RegNo));
|
||||
}
|
||||
@ -425,8 +427,8 @@ public:
|
||||
}
|
||||
|
||||
/// use_iterator/use_begin/use_end - Walk all uses of the specified register.
|
||||
typedef defusechain_iterator<true,false,false,true,false,false>
|
||||
use_iterator;
|
||||
using use_iterator =
|
||||
defusechain_iterator<true, false, false, true, false, false>;
|
||||
use_iterator use_begin(unsigned RegNo) const {
|
||||
return use_iterator(getRegUseDefListHead(RegNo));
|
||||
}
|
||||
@ -438,8 +440,8 @@ public:
|
||||
|
||||
/// use_instr_iterator/use_instr_begin/use_instr_end - Walk all uses of the
|
||||
/// specified register, stepping by MachineInstr.
|
||||
typedef defusechain_instr_iterator<true,false,false,false,true,false>
|
||||
use_instr_iterator;
|
||||
using use_instr_iterator =
|
||||
defusechain_instr_iterator<true, false, false, false, true, false>;
|
||||
use_instr_iterator use_instr_begin(unsigned RegNo) const {
|
||||
return use_instr_iterator(getRegUseDefListHead(RegNo));
|
||||
}
|
||||
@ -454,8 +456,8 @@ public:
|
||||
|
||||
/// use_bundle_iterator/use_bundle_begin/use_bundle_end - Walk all uses of the
|
||||
/// specified register, stepping by bundle.
|
||||
typedef defusechain_instr_iterator<true,false,false,false,false,true>
|
||||
use_bundle_iterator;
|
||||
using use_bundle_iterator =
|
||||
defusechain_instr_iterator<true, false, false, false, false, true>;
|
||||
use_bundle_iterator use_bundle_begin(unsigned RegNo) const {
|
||||
return use_bundle_iterator(getRegUseDefListHead(RegNo));
|
||||
}
|
||||
@ -482,8 +484,8 @@ public:
|
||||
|
||||
/// use_nodbg_iterator/use_nodbg_begin/use_nodbg_end - Walk all uses of the
|
||||
/// specified register, skipping those marked as Debug.
|
||||
typedef defusechain_iterator<true,false,true,true,false,false>
|
||||
use_nodbg_iterator;
|
||||
using use_nodbg_iterator =
|
||||
defusechain_iterator<true, false, true, true, false, false>;
|
||||
use_nodbg_iterator use_nodbg_begin(unsigned RegNo) const {
|
||||
return use_nodbg_iterator(getRegUseDefListHead(RegNo));
|
||||
}
|
||||
@ -499,8 +501,8 @@ public:
|
||||
/// use_instr_nodbg_iterator/use_instr_nodbg_begin/use_instr_nodbg_end - Walk
|
||||
/// all uses of the specified register, stepping by MachineInstr, skipping
|
||||
/// those marked as Debug.
|
||||
typedef defusechain_instr_iterator<true,false,true,false,true,false>
|
||||
use_instr_nodbg_iterator;
|
||||
using use_instr_nodbg_iterator =
|
||||
defusechain_instr_iterator<true, false, true, false, true, false>;
|
||||
use_instr_nodbg_iterator use_instr_nodbg_begin(unsigned RegNo) const {
|
||||
return use_instr_nodbg_iterator(getRegUseDefListHead(RegNo));
|
||||
}
|
||||
@ -516,8 +518,8 @@ public:
|
||||
/// use_bundle_nodbg_iterator/use_bundle_nodbg_begin/use_bundle_nodbg_end - Walk
|
||||
/// all uses of the specified register, stepping by bundle, skipping
|
||||
/// those marked as Debug.
|
||||
typedef defusechain_instr_iterator<true,false,true,false,false,true>
|
||||
use_bundle_nodbg_iterator;
|
||||
using use_bundle_nodbg_iterator =
|
||||
defusechain_instr_iterator<true, false, true, false, false, true>;
|
||||
use_bundle_nodbg_iterator use_bundle_nodbg_begin(unsigned RegNo) const {
|
||||
return use_bundle_nodbg_iterator(getRegUseDefListHead(RegNo));
|
||||
}
|
||||
@ -593,7 +595,6 @@ public:
|
||||
/// Return the register class of the specified virtual register.
|
||||
/// This shouldn't be used directly unless \p Reg has a register class.
|
||||
/// \see getRegClassOrNull when this might happen.
|
||||
///
|
||||
const TargetRegisterClass *getRegClass(unsigned Reg) const {
|
||||
assert(VRegInfo[Reg].first.is<const TargetRegisterClass *>() &&
|
||||
"Register class not set, wrong accessor");
|
||||
@ -620,7 +621,6 @@ public:
|
||||
/// a register bank or has been assigned a register class.
|
||||
/// \note It is possible to get the register bank from the register class via
|
||||
/// RegisterBankInfo::getRegBankFromRegClass.
|
||||
///
|
||||
const RegisterBank *getRegBankOrNull(unsigned Reg) const {
|
||||
const RegClassOrRegBank &Val = VRegInfo[Reg].first;
|
||||
return Val.dyn_cast<const RegisterBank *>();
|
||||
@ -629,17 +629,14 @@ public:
|
||||
/// Return the register bank or register class of \p Reg.
|
||||
/// \note Before the register bank gets assigned (i.e., before the
|
||||
/// RegBankSelect pass) \p Reg may not have either.
|
||||
///
|
||||
const RegClassOrRegBank &getRegClassOrRegBank(unsigned Reg) const {
|
||||
return VRegInfo[Reg].first;
|
||||
}
|
||||
|
||||
/// setRegClass - Set the register class of the specified virtual register.
|
||||
///
|
||||
void setRegClass(unsigned Reg, const TargetRegisterClass *RC);
|
||||
|
||||
/// Set the register bank to \p RegBank for \p Reg.
|
||||
///
|
||||
void setRegBank(unsigned Reg, const RegisterBank &RegBank);
|
||||
|
||||
void setRegClassOrRegBank(unsigned Reg,
|
||||
@ -653,7 +650,6 @@ public:
|
||||
/// new register class, or NULL if no such class exists.
|
||||
/// This should only be used when the constraint is known to be trivial, like
|
||||
/// GR32 -> GR32_NOSP. Beware of increasing register pressure.
|
||||
///
|
||||
const TargetRegisterClass *constrainRegClass(unsigned Reg,
|
||||
const TargetRegisterClass *RC,
|
||||
unsigned MinNumRegs = 0);
|
||||
@ -665,12 +661,10 @@ public:
|
||||
/// This method can be used after constraints have been removed from a
|
||||
/// virtual register, for example after removing instructions or splitting
|
||||
/// the live range.
|
||||
///
|
||||
bool recomputeRegClass(unsigned Reg);
|
||||
|
||||
/// createVirtualRegister - Create and return a new virtual register in the
|
||||
/// function with the specified register class.
|
||||
///
|
||||
unsigned createVirtualRegister(const TargetRegisterClass *RegClass);
|
||||
|
||||
/// Accessor for VRegToType. This accessor should only be used
|
||||
@ -704,7 +698,6 @@ public:
|
||||
unsigned createIncompleteVirtualRegister();
|
||||
|
||||
/// getNumVirtRegs - Return the number of virtual registers created.
|
||||
///
|
||||
unsigned getNumVirtRegs() const { return VRegInfo.size(); }
|
||||
|
||||
/// clearVirtRegs - Remove all virtual registers (after physreg assignment).
|
||||
@ -810,7 +803,6 @@ public:
|
||||
///
|
||||
/// Reserved registers may belong to an allocatable register class, but the
|
||||
/// target has explicitly requested that they are not used.
|
||||
///
|
||||
bool isReserved(unsigned PhysReg) const {
|
||||
return getReservedRegs().test(PhysReg);
|
||||
}
|
||||
@ -838,8 +830,8 @@ public:
|
||||
|
||||
// Iteration support for the live-ins set. It's kept in sorted order
|
||||
// by register number.
|
||||
typedef std::vector<std::pair<unsigned,unsigned>>::const_iterator
|
||||
livein_iterator;
|
||||
using livein_iterator =
|
||||
std::vector<std::pair<unsigned,unsigned>>::const_iterator;
|
||||
livein_iterator livein_begin() const { return LiveIns.begin(); }
|
||||
livein_iterator livein_end() const { return LiveIns.end(); }
|
||||
bool livein_empty() const { return LiveIns.empty(); }
|
||||
@ -910,10 +902,10 @@ public:
|
||||
}
|
||||
|
||||
public:
|
||||
typedef std::iterator<std::forward_iterator_tag,
|
||||
MachineInstr, ptrdiff_t>::reference reference;
|
||||
typedef std::iterator<std::forward_iterator_tag,
|
||||
MachineInstr, ptrdiff_t>::pointer pointer;
|
||||
using reference = std::iterator<std::forward_iterator_tag,
|
||||
MachineInstr, ptrdiff_t>::reference;
|
||||
using pointer = std::iterator<std::forward_iterator_tag,
|
||||
MachineInstr, ptrdiff_t>::pointer;
|
||||
|
||||
defusechain_iterator() = default;
|
||||
|
||||
@ -1016,10 +1008,10 @@ public:
|
||||
}
|
||||
|
||||
public:
|
||||
typedef std::iterator<std::forward_iterator_tag,
|
||||
MachineInstr, ptrdiff_t>::reference reference;
|
||||
typedef std::iterator<std::forward_iterator_tag,
|
||||
MachineInstr, ptrdiff_t>::pointer pointer;
|
||||
using reference = std::iterator<std::forward_iterator_tag,
|
||||
MachineInstr, ptrdiff_t>::reference;
|
||||
using pointer = std::iterator<std::forward_iterator_tag,
|
||||
MachineInstr, ptrdiff_t>::pointer;
|
||||
|
||||
defusechain_instr_iterator() = default;
|
||||
|
||||
|
@ -104,10 +104,15 @@ extern cl::opt<bool> ForceBottomUp;
|
||||
|
||||
class LiveIntervals;
|
||||
class MachineDominatorTree;
|
||||
class MachineFunction;
|
||||
class MachineInstr;
|
||||
class MachineLoopInfo;
|
||||
class RegisterClassInfo;
|
||||
class SchedDFSResult;
|
||||
class ScheduleHazardRecognizer;
|
||||
class TargetInstrInfo;
|
||||
class TargetPassConfig;
|
||||
class TargetRegisterInfo;
|
||||
|
||||
/// MachineSchedContext provides enough context from the MachineScheduler pass
|
||||
/// for the target to instantiate a scheduler.
|
||||
@ -129,10 +134,10 @@ struct MachineSchedContext {
|
||||
/// schedulers.
|
||||
class MachineSchedRegistry : public MachinePassRegistryNode {
|
||||
public:
|
||||
typedef ScheduleDAGInstrs *(*ScheduleDAGCtor)(MachineSchedContext *);
|
||||
using ScheduleDAGCtor = ScheduleDAGInstrs *(*)(MachineSchedContext *);
|
||||
|
||||
// RegisterPassParser requires a (misnamed) FunctionPassCtor type.
|
||||
typedef ScheduleDAGCtor FunctionPassCtor;
|
||||
using FunctionPassCtor = ScheduleDAGCtor;
|
||||
|
||||
static MachinePassRegistry Registry;
|
||||
|
||||
@ -527,7 +532,7 @@ public:
|
||||
|
||||
unsigned size() const { return Queue.size(); }
|
||||
|
||||
typedef std::vector<SUnit*>::iterator iterator;
|
||||
using iterator = std::vector<SUnit*>::iterator;
|
||||
|
||||
iterator begin() { return Queue.begin(); }
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
//===---------- CostAllocator.h - PBQP Cost Allocator -----------*- C++ -*-===//
|
||||
//===- CostAllocator.h - PBQP Cost Allocator --------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
@ -19,26 +19,28 @@
|
||||
#define LLVM_CODEGEN_PBQP_COSTALLOCATOR_H
|
||||
|
||||
#include "llvm/ADT/DenseSet.h"
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
|
||||
namespace llvm {
|
||||
namespace PBQP {
|
||||
|
||||
template <typename ValueT>
|
||||
class ValuePool {
|
||||
template <typename ValueT> class ValuePool {
|
||||
public:
|
||||
typedef std::shared_ptr<const ValueT> PoolRef;
|
||||
using PoolRef = std::shared_ptr<const ValueT>;
|
||||
|
||||
private:
|
||||
|
||||
class PoolEntry : public std::enable_shared_from_this<PoolEntry> {
|
||||
public:
|
||||
template <typename ValueKeyT>
|
||||
PoolEntry(ValuePool &Pool, ValueKeyT Value)
|
||||
: Pool(Pool), Value(std::move(Value)) {}
|
||||
|
||||
~PoolEntry() { Pool.removeEntry(this); }
|
||||
const ValueT& getValue() const { return Value; }
|
||||
|
||||
const ValueT &getValue() const { return Value; }
|
||||
|
||||
private:
|
||||
ValuePool &Pool;
|
||||
ValueT Value;
|
||||
@ -46,10 +48,10 @@ private:
|
||||
|
||||
class PoolEntryDSInfo {
|
||||
public:
|
||||
static inline PoolEntry* getEmptyKey() { return nullptr; }
|
||||
static inline PoolEntry *getEmptyKey() { return nullptr; }
|
||||
|
||||
static inline PoolEntry* getTombstoneKey() {
|
||||
return reinterpret_cast<PoolEntry*>(static_cast<uintptr_t>(1));
|
||||
static inline PoolEntry *getTombstoneKey() {
|
||||
return reinterpret_cast<PoolEntry *>(static_cast<uintptr_t>(1));
|
||||
}
|
||||
|
||||
template <typename ValueKeyT>
|
||||
@ -66,8 +68,7 @@ private:
|
||||
}
|
||||
|
||||
template <typename ValueKeyT1, typename ValueKeyT2>
|
||||
static
|
||||
bool isEqual(const ValueKeyT1 &C1, const ValueKeyT2 &C2) {
|
||||
static bool isEqual(const ValueKeyT1 &C1, const ValueKeyT2 &C2) {
|
||||
return C1 == C2;
|
||||
}
|
||||
|
||||
@ -83,10 +84,9 @@ private:
|
||||
return P1 == P2;
|
||||
return isEqual(P1->getValue(), P2);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
typedef DenseSet<PoolEntry*, PoolEntryDSInfo> EntrySetT;
|
||||
using EntrySetT = DenseSet<PoolEntry *, PoolEntryDSInfo>;
|
||||
|
||||
EntrySetT EntrySet;
|
||||
|
||||
@ -105,28 +105,31 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
template <typename VectorT, typename MatrixT>
|
||||
class PoolCostAllocator {
|
||||
template <typename VectorT, typename MatrixT> class PoolCostAllocator {
|
||||
private:
|
||||
typedef ValuePool<VectorT> VectorCostPool;
|
||||
typedef ValuePool<MatrixT> MatrixCostPool;
|
||||
using VectorCostPool = ValuePool<VectorT>;
|
||||
using MatrixCostPool = ValuePool<MatrixT>;
|
||||
|
||||
public:
|
||||
typedef VectorT Vector;
|
||||
typedef MatrixT Matrix;
|
||||
typedef typename VectorCostPool::PoolRef VectorPtr;
|
||||
typedef typename MatrixCostPool::PoolRef MatrixPtr;
|
||||
using Vector = VectorT;
|
||||
using Matrix = MatrixT;
|
||||
using VectorPtr = typename VectorCostPool::PoolRef;
|
||||
using MatrixPtr = typename MatrixCostPool::PoolRef;
|
||||
|
||||
template <typename VectorKeyT>
|
||||
VectorPtr getVector(VectorKeyT v) { return VectorPool.getValue(std::move(v)); }
|
||||
template <typename VectorKeyT> VectorPtr getVector(VectorKeyT v) {
|
||||
return VectorPool.getValue(std::move(v));
|
||||
}
|
||||
|
||||
template <typename MatrixKeyT> MatrixPtr getMatrix(MatrixKeyT m) {
|
||||
return MatrixPool.getValue(std::move(m));
|
||||
}
|
||||
|
||||
template <typename MatrixKeyT>
|
||||
MatrixPtr getMatrix(MatrixKeyT m) { return MatrixPool.getValue(std::move(m)); }
|
||||
private:
|
||||
VectorCostPool VectorPool;
|
||||
MatrixCostPool MatrixPool;
|
||||
};
|
||||
|
||||
} // namespace PBQP
|
||||
} // namespace llvm
|
||||
} // end namespace PBQP
|
||||
} // end namespace llvm
|
||||
|
||||
#endif
|
||||
#endif // LLVM_CODEGEN_PBQP_COSTALLOCATOR_H
|
||||
|
@ -1,4 +1,4 @@
|
||||
//===-------------------- Graph.h - PBQP Graph ------------------*- C++ -*-===//
|
||||
//===- Graph.h - PBQP Graph -------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
@ -11,16 +11,14 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
|
||||
#ifndef LLVM_CODEGEN_PBQP_GRAPH_H
|
||||
#define LLVM_CODEGEN_PBQP_GRAPH_H
|
||||
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <iterator>
|
||||
#include <limits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
@ -28,8 +26,8 @@ namespace PBQP {
|
||||
|
||||
class GraphBase {
|
||||
public:
|
||||
typedef unsigned NodeId;
|
||||
typedef unsigned EdgeId;
|
||||
using NodeId = unsigned;
|
||||
using EdgeId = unsigned;
|
||||
|
||||
/// @brief Returns a value representing an invalid (non-existent) node.
|
||||
static NodeId invalidNodeId() {
|
||||
@ -48,32 +46,32 @@ namespace PBQP {
|
||||
template <typename SolverT>
|
||||
class Graph : public GraphBase {
|
||||
private:
|
||||
typedef typename SolverT::CostAllocator CostAllocator;
|
||||
using CostAllocator = typename SolverT::CostAllocator;
|
||||
|
||||
public:
|
||||
typedef typename SolverT::RawVector RawVector;
|
||||
typedef typename SolverT::RawMatrix RawMatrix;
|
||||
typedef typename SolverT::Vector Vector;
|
||||
typedef typename SolverT::Matrix Matrix;
|
||||
typedef typename CostAllocator::VectorPtr VectorPtr;
|
||||
typedef typename CostAllocator::MatrixPtr MatrixPtr;
|
||||
typedef typename SolverT::NodeMetadata NodeMetadata;
|
||||
typedef typename SolverT::EdgeMetadata EdgeMetadata;
|
||||
typedef typename SolverT::GraphMetadata GraphMetadata;
|
||||
using RawVector = typename SolverT::RawVector;
|
||||
using RawMatrix = typename SolverT::RawMatrix;
|
||||
using Vector = typename SolverT::Vector;
|
||||
using Matrix = typename SolverT::Matrix;
|
||||
using VectorPtr = typename CostAllocator::VectorPtr;
|
||||
using MatrixPtr = typename CostAllocator::MatrixPtr;
|
||||
using NodeMetadata = typename SolverT::NodeMetadata;
|
||||
using EdgeMetadata = typename SolverT::EdgeMetadata;
|
||||
using GraphMetadata = typename SolverT::GraphMetadata;
|
||||
|
||||
private:
|
||||
|
||||
class NodeEntry {
|
||||
public:
|
||||
typedef std::vector<EdgeId> AdjEdgeList;
|
||||
typedef AdjEdgeList::size_type AdjEdgeIdx;
|
||||
typedef AdjEdgeList::const_iterator AdjEdgeItr;
|
||||
using AdjEdgeList = std::vector<EdgeId>;
|
||||
using AdjEdgeIdx = AdjEdgeList::size_type;
|
||||
using AdjEdgeItr = AdjEdgeList::const_iterator;
|
||||
|
||||
NodeEntry(VectorPtr Costs) : Costs(std::move(Costs)) {}
|
||||
|
||||
static AdjEdgeIdx getInvalidAdjEdgeIdx() {
|
||||
return std::numeric_limits<AdjEdgeIdx>::max();
|
||||
}
|
||||
|
||||
NodeEntry(VectorPtr Costs) : Costs(std::move(Costs)) {}
|
||||
|
||||
AdjEdgeIdx addAdjEdgeId(EdgeId EId) {
|
||||
AdjEdgeIdx Idx = AdjEdgeIds.size();
|
||||
AdjEdgeIds.push_back(EId);
|
||||
@ -96,6 +94,7 @@ namespace PBQP {
|
||||
|
||||
VectorPtr Costs;
|
||||
NodeMetadata Metadata;
|
||||
|
||||
private:
|
||||
AdjEdgeList AdjEdgeIds;
|
||||
};
|
||||
@ -150,8 +149,10 @@ namespace PBQP {
|
||||
|
||||
NodeId getN1Id() const { return NIds[0]; }
|
||||
NodeId getN2Id() const { return NIds[1]; }
|
||||
|
||||
MatrixPtr Costs;
|
||||
EdgeMetadata Metadata;
|
||||
|
||||
private:
|
||||
NodeId NIds[2];
|
||||
typename NodeEntry::AdjEdgeIdx ThisEdgeAdjIdxs[2];
|
||||
@ -161,18 +162,20 @@ namespace PBQP {
|
||||
|
||||
GraphMetadata Metadata;
|
||||
CostAllocator CostAlloc;
|
||||
SolverT *Solver;
|
||||
SolverT *Solver = nullptr;
|
||||
|
||||
typedef std::vector<NodeEntry> NodeVector;
|
||||
typedef std::vector<NodeId> FreeNodeVector;
|
||||
using NodeVector = std::vector<NodeEntry>;
|
||||
using FreeNodeVector = std::vector<NodeId>;
|
||||
NodeVector Nodes;
|
||||
FreeNodeVector FreeNodeIds;
|
||||
|
||||
typedef std::vector<EdgeEntry> EdgeVector;
|
||||
typedef std::vector<EdgeId> FreeEdgeVector;
|
||||
using EdgeVector = std::vector<EdgeEntry>;
|
||||
using FreeEdgeVector = std::vector<EdgeId>;
|
||||
EdgeVector Edges;
|
||||
FreeEdgeVector FreeEdgeIds;
|
||||
|
||||
Graph(const Graph &Other) {}
|
||||
|
||||
// ----- INTERNAL METHODS -----
|
||||
|
||||
NodeEntry &getNode(NodeId NId) {
|
||||
@ -220,20 +223,18 @@ namespace PBQP {
|
||||
return EId;
|
||||
}
|
||||
|
||||
Graph(const Graph &Other) {}
|
||||
void operator=(const Graph &Other) {}
|
||||
|
||||
public:
|
||||
|
||||
typedef typename NodeEntry::AdjEdgeItr AdjEdgeItr;
|
||||
using AdjEdgeItr = typename NodeEntry::AdjEdgeItr;
|
||||
|
||||
class NodeItr {
|
||||
public:
|
||||
typedef std::forward_iterator_tag iterator_category;
|
||||
typedef NodeId value_type;
|
||||
typedef int difference_type;
|
||||
typedef NodeId* pointer;
|
||||
typedef NodeId& reference;
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
using value_type = NodeId;
|
||||
using difference_type = int;
|
||||
using pointer = NodeId *;
|
||||
using reference = NodeId &;
|
||||
|
||||
NodeItr(NodeId CurNId, const Graph &G)
|
||||
: CurNId(CurNId), EndNId(G.Nodes.size()), FreeNodeIds(G.FreeNodeIds) {
|
||||
@ -283,53 +284,65 @@ namespace PBQP {
|
||||
|
||||
class NodeIdSet {
|
||||
public:
|
||||
NodeIdSet(const Graph &G) : G(G) { }
|
||||
NodeIdSet(const Graph &G) : G(G) {}
|
||||
|
||||
NodeItr begin() const { return NodeItr(0, G); }
|
||||
NodeItr end() const { return NodeItr(G.Nodes.size(), G); }
|
||||
|
||||
bool empty() const { return G.Nodes.empty(); }
|
||||
|
||||
typename NodeVector::size_type size() const {
|
||||
return G.Nodes.size() - G.FreeNodeIds.size();
|
||||
}
|
||||
|
||||
private:
|
||||
const Graph& G;
|
||||
};
|
||||
|
||||
class EdgeIdSet {
|
||||
public:
|
||||
EdgeIdSet(const Graph &G) : G(G) { }
|
||||
EdgeIdSet(const Graph &G) : G(G) {}
|
||||
|
||||
EdgeItr begin() const { return EdgeItr(0, G); }
|
||||
EdgeItr end() const { return EdgeItr(G.Edges.size(), G); }
|
||||
|
||||
bool empty() const { return G.Edges.empty(); }
|
||||
|
||||
typename NodeVector::size_type size() const {
|
||||
return G.Edges.size() - G.FreeEdgeIds.size();
|
||||
}
|
||||
|
||||
private:
|
||||
const Graph& G;
|
||||
};
|
||||
|
||||
class AdjEdgeIdSet {
|
||||
public:
|
||||
AdjEdgeIdSet(const NodeEntry &NE) : NE(NE) { }
|
||||
AdjEdgeIdSet(const NodeEntry &NE) : NE(NE) {}
|
||||
|
||||
typename NodeEntry::AdjEdgeItr begin() const {
|
||||
return NE.getAdjEdgeIds().begin();
|
||||
}
|
||||
|
||||
typename NodeEntry::AdjEdgeItr end() const {
|
||||
return NE.getAdjEdgeIds().end();
|
||||
}
|
||||
|
||||
bool empty() const { return NE.getAdjEdgeIds().empty(); }
|
||||
|
||||
typename NodeEntry::AdjEdgeList::size_type size() const {
|
||||
return NE.getAdjEdgeIds().size();
|
||||
}
|
||||
|
||||
private:
|
||||
const NodeEntry &NE;
|
||||
};
|
||||
|
||||
/// @brief Construct an empty PBQP graph.
|
||||
Graph() : Solver(nullptr) {}
|
||||
Graph() = default;
|
||||
|
||||
/// @brief Construct an empty PBQP graph with the given graph metadata.
|
||||
Graph(GraphMetadata Metadata)
|
||||
: Metadata(std::move(Metadata)), Solver(nullptr) {}
|
||||
Graph(GraphMetadata Metadata) : Metadata(std::move(Metadata)) {}
|
||||
|
||||
/// @brief Get a reference to the graph metadata.
|
||||
GraphMetadata& getMetadata() { return Metadata; }
|
||||
@ -656,7 +669,7 @@ namespace PBQP {
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace PBQP
|
||||
} // namespace llvm
|
||||
} // end namespace PBQP
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_CODEGEN_PBQP_GRAPH_HPP
|
||||
|
@ -1,4 +1,4 @@
|
||||
//===------ Math.h - PBQP Vector and Matrix classes -------------*- C++ -*-===//
|
||||
//===- Math.h - PBQP Vector and Matrix classes ------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
@ -11,20 +11,22 @@
|
||||
#define LLVM_CODEGEN_PBQP_MATH_H
|
||||
|
||||
#include "llvm/ADT/Hashing.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
namespace llvm {
|
||||
namespace PBQP {
|
||||
|
||||
typedef float PBQPNum;
|
||||
using PBQPNum = float;
|
||||
|
||||
/// \brief PBQP Vector class.
|
||||
class Vector {
|
||||
friend hash_code hash_value(const Vector &);
|
||||
public:
|
||||
|
||||
public:
|
||||
/// \brief Construct a PBQP vector of the given size.
|
||||
explicit Vector(unsigned Length)
|
||||
: Length(Length), Data(llvm::make_unique<PBQPNum []>(Length)) {}
|
||||
@ -120,8 +122,8 @@ OStream& operator<<(OStream &OS, const Vector &V) {
|
||||
class Matrix {
|
||||
private:
|
||||
friend hash_code hash_value(const Matrix &);
|
||||
public:
|
||||
|
||||
public:
|
||||
/// \brief Construct a PBQP Matrix with the given dimensions.
|
||||
Matrix(unsigned Rows, unsigned Cols) :
|
||||
Rows(Rows), Cols(Cols), Data(llvm::make_unique<PBQPNum []>(Rows * Cols)) {
|
||||
@ -253,9 +255,11 @@ OStream& operator<<(OStream &OS, const Matrix &M) {
|
||||
template <typename Metadata>
|
||||
class MDVector : public Vector {
|
||||
public:
|
||||
MDVector(const Vector &v) : Vector(v), md(*this) { }
|
||||
MDVector(const Vector &v) : Vector(v), md(*this) {}
|
||||
MDVector(Vector &&v) : Vector(std::move(v)), md(*this) { }
|
||||
|
||||
const Metadata& getMetadata() const { return md; }
|
||||
|
||||
private:
|
||||
Metadata md;
|
||||
};
|
||||
@ -268,9 +272,11 @@ inline hash_code hash_value(const MDVector<Metadata> &V) {
|
||||
template <typename Metadata>
|
||||
class MDMatrix : public Matrix {
|
||||
public:
|
||||
MDMatrix(const Matrix &m) : Matrix(m), md(*this) { }
|
||||
MDMatrix(const Matrix &m) : Matrix(m), md(*this) {}
|
||||
MDMatrix(Matrix &&m) : Matrix(std::move(m)), md(*this) { }
|
||||
|
||||
const Metadata& getMetadata() const { return md; }
|
||||
|
||||
private:
|
||||
Metadata md;
|
||||
};
|
||||
@ -280,7 +286,7 @@ inline hash_code hash_value(const MDMatrix<Metadata> &M) {
|
||||
return hash_value(static_cast<const Matrix&>(M));
|
||||
}
|
||||
|
||||
} // namespace PBQP
|
||||
} // namespace llvm
|
||||
} // end namespace PBQP
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_CODEGEN_PBQP_MATH_H
|
||||
|
@ -1,4 +1,4 @@
|
||||
//===----------- ReductionRules.h - Reduction Rules -------------*- C++ -*-===//
|
||||
//===- ReductionRules.h - Reduction Rules -----------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
@ -17,6 +17,8 @@
|
||||
#include "Graph.h"
|
||||
#include "Math.h"
|
||||
#include "Solution.h"
|
||||
#include <cassert>
|
||||
#include <limits>
|
||||
|
||||
namespace llvm {
|
||||
namespace PBQP {
|
||||
@ -27,11 +29,11 @@ namespace PBQP {
|
||||
/// neighbor. Notify the problem domain.
|
||||
template <typename GraphT>
|
||||
void applyR1(GraphT &G, typename GraphT::NodeId NId) {
|
||||
typedef typename GraphT::NodeId NodeId;
|
||||
typedef typename GraphT::EdgeId EdgeId;
|
||||
typedef typename GraphT::Vector Vector;
|
||||
typedef typename GraphT::Matrix Matrix;
|
||||
typedef typename GraphT::RawVector RawVector;
|
||||
using NodeId = typename GraphT::NodeId;
|
||||
using EdgeId = typename GraphT::EdgeId;
|
||||
using Vector = typename GraphT::Vector;
|
||||
using Matrix = typename GraphT::Matrix;
|
||||
using RawVector = typename GraphT::RawVector;
|
||||
|
||||
assert(G.getNodeDegree(NId) == 1 &&
|
||||
"R1 applied to node with degree != 1.");
|
||||
@ -71,11 +73,11 @@ namespace PBQP {
|
||||
|
||||
template <typename GraphT>
|
||||
void applyR2(GraphT &G, typename GraphT::NodeId NId) {
|
||||
typedef typename GraphT::NodeId NodeId;
|
||||
typedef typename GraphT::EdgeId EdgeId;
|
||||
typedef typename GraphT::Vector Vector;
|
||||
typedef typename GraphT::Matrix Matrix;
|
||||
typedef typename GraphT::RawMatrix RawMatrix;
|
||||
using NodeId = typename GraphT::NodeId;
|
||||
using EdgeId = typename GraphT::EdgeId;
|
||||
using Vector = typename GraphT::Vector;
|
||||
using Matrix = typename GraphT::Matrix;
|
||||
using RawMatrix = typename GraphT::RawMatrix;
|
||||
|
||||
assert(G.getNodeDegree(NId) == 2 &&
|
||||
"R2 applied to node with degree != 2.");
|
||||
@ -177,9 +179,9 @@ namespace PBQP {
|
||||
// state.
|
||||
template <typename GraphT, typename StackT>
|
||||
Solution backpropagate(GraphT& G, StackT stack) {
|
||||
typedef GraphBase::NodeId NodeId;
|
||||
typedef typename GraphT::Matrix Matrix;
|
||||
typedef typename GraphT::RawVector RawVector;
|
||||
using NodeId = GraphBase::NodeId;
|
||||
using Matrix = typename GraphT::Matrix;
|
||||
using RawVector = typename GraphT::RawVector;
|
||||
|
||||
Solution s;
|
||||
|
||||
@ -215,7 +217,7 @@ namespace PBQP {
|
||||
return s;
|
||||
}
|
||||
|
||||
} // namespace PBQP
|
||||
} // namespace llvm
|
||||
} // end namespace PBQP
|
||||
} // end namespace llvm
|
||||
|
||||
#endif
|
||||
#endif // LLVM_CODEGEN_PBQP_REDUCTIONRULES_H
|
||||
|
@ -26,7 +26,7 @@ namespace PBQP {
|
||||
/// To get the selection for each node in the problem use the getSelection method.
|
||||
class Solution {
|
||||
private:
|
||||
typedef std::map<GraphBase::NodeId, unsigned> SelectionsMap;
|
||||
using SelectionsMap = std::map<GraphBase::NodeId, unsigned>;
|
||||
SelectionsMap selections;
|
||||
|
||||
unsigned r0Reductions = 0;
|
||||
|
@ -1,4 +1,4 @@
|
||||
//===-- RegAllocPBQP.h ------------------------------------------*- C++ -*-===//
|
||||
//===- RegAllocPBQP.h -------------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
@ -16,23 +16,22 @@
|
||||
#ifndef LLVM_CODEGEN_PBQPRACONSTRAINT_H
|
||||
#define LLVM_CODEGEN_PBQPRACONSTRAINT_H
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
namespace PBQP {
|
||||
namespace RegAlloc {
|
||||
|
||||
// Forward declare PBQP graph class.
|
||||
class PBQPRAGraph;
|
||||
}
|
||||
}
|
||||
|
||||
class LiveIntervals;
|
||||
class MachineBlockFrequencyInfo;
|
||||
class MachineFunction;
|
||||
class TargetRegisterInfo;
|
||||
} // end namespace RegAlloc
|
||||
} // end namespace PBQP
|
||||
|
||||
typedef PBQP::RegAlloc::PBQPRAGraph PBQPRAGraph;
|
||||
using PBQPRAGraph = PBQP::RegAlloc::PBQPRAGraph;
|
||||
|
||||
/// @brief Abstract base for classes implementing PBQP register allocation
|
||||
/// constraints (e.g. Spill-costs, interference, coalescing).
|
||||
@ -40,6 +39,7 @@ class PBQPRAConstraint {
|
||||
public:
|
||||
virtual ~PBQPRAConstraint() = 0;
|
||||
virtual void apply(PBQPRAGraph &G) = 0;
|
||||
|
||||
private:
|
||||
virtual void anchor();
|
||||
};
|
||||
@ -59,11 +59,13 @@ public:
|
||||
if (C)
|
||||
Constraints.push_back(std::move(C));
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<std::unique_ptr<PBQPRAConstraint>> Constraints;
|
||||
|
||||
void anchor() override;
|
||||
};
|
||||
|
||||
}
|
||||
} // end namespace llvm
|
||||
|
||||
#endif /* LLVM_CODEGEN_PBQPRACONSTRAINT_H */
|
||||
#endif // LLVM_CODEGEN_PBQPRACONSTRAINT_H
|
||||
|
@ -140,6 +140,9 @@ namespace llvm {
|
||||
/// Greedy register allocator.
|
||||
extern char &RAGreedyID;
|
||||
|
||||
/// Basic register allocator.
|
||||
extern char &RABasicID;
|
||||
|
||||
/// VirtRegRewriter pass. Rewrite virtual registers to physical registers as
|
||||
/// assigned in VirtRegMap.
|
||||
extern char &VirtRegRewriterID;
|
||||
|
@ -130,10 +130,10 @@ inline hash_code hash_value(const AllowedRegVector &OptRegs) {
|
||||
/// \brief Holds graph-level metadata relevant to PBQP RA problems.
|
||||
class GraphMetadata {
|
||||
private:
|
||||
typedef ValuePool<AllowedRegVector> AllowedRegVecPool;
|
||||
using AllowedRegVecPool = ValuePool<AllowedRegVector>;
|
||||
|
||||
public:
|
||||
typedef AllowedRegVecPool::PoolRef AllowedRegVecRef;
|
||||
using AllowedRegVecRef = AllowedRegVecPool::PoolRef;
|
||||
|
||||
GraphMetadata(MachineFunction &MF,
|
||||
LiveIntervals &LIS,
|
||||
@ -167,17 +167,17 @@ private:
|
||||
/// \brief Holds solver state and other metadata relevant to each PBQP RA node.
|
||||
class NodeMetadata {
|
||||
public:
|
||||
typedef RegAlloc::AllowedRegVector AllowedRegVector;
|
||||
using AllowedRegVector = RegAlloc::AllowedRegVector;
|
||||
|
||||
// The node's reduction state. The order in this enum is important,
|
||||
// as it is assumed nodes can only progress up (i.e. towards being
|
||||
// optimally reducible) when reducing the graph.
|
||||
typedef enum {
|
||||
using ReductionState = enum {
|
||||
Unprocessed,
|
||||
NotProvablyAllocatable,
|
||||
ConservativelyAllocatable,
|
||||
OptimallyReducible
|
||||
} ReductionState;
|
||||
};
|
||||
|
||||
NodeMetadata() = default;
|
||||
|
||||
@ -267,23 +267,23 @@ private:
|
||||
|
||||
class RegAllocSolverImpl {
|
||||
private:
|
||||
typedef MDMatrix<MatrixMetadata> RAMatrix;
|
||||
using RAMatrix = MDMatrix<MatrixMetadata>;
|
||||
|
||||
public:
|
||||
typedef PBQP::Vector RawVector;
|
||||
typedef PBQP::Matrix RawMatrix;
|
||||
typedef PBQP::Vector Vector;
|
||||
typedef RAMatrix Matrix;
|
||||
typedef PBQP::PoolCostAllocator<Vector, Matrix> CostAllocator;
|
||||
using RawVector = PBQP::Vector;
|
||||
using RawMatrix = PBQP::Matrix;
|
||||
using Vector = PBQP::Vector;
|
||||
using Matrix = RAMatrix;
|
||||
using CostAllocator = PBQP::PoolCostAllocator<Vector, Matrix>;
|
||||
|
||||
typedef GraphBase::NodeId NodeId;
|
||||
typedef GraphBase::EdgeId EdgeId;
|
||||
using NodeId = GraphBase::NodeId;
|
||||
using EdgeId = GraphBase::EdgeId;
|
||||
|
||||
typedef RegAlloc::NodeMetadata NodeMetadata;
|
||||
struct EdgeMetadata { };
|
||||
typedef RegAlloc::GraphMetadata GraphMetadata;
|
||||
using NodeMetadata = RegAlloc::NodeMetadata;
|
||||
struct EdgeMetadata {};
|
||||
using GraphMetadata = RegAlloc::GraphMetadata;
|
||||
|
||||
typedef PBQP::Graph<RegAllocSolverImpl> Graph;
|
||||
using Graph = PBQP::Graph<RegAllocSolverImpl>;
|
||||
|
||||
RegAllocSolverImpl(Graph &G) : G(G) {}
|
||||
|
||||
@ -426,7 +426,7 @@ private:
|
||||
std::vector<GraphBase::NodeId> reduce() {
|
||||
assert(!G.empty() && "Cannot reduce empty graph.");
|
||||
|
||||
typedef GraphBase::NodeId NodeId;
|
||||
using NodeId = GraphBase::NodeId;
|
||||
std::vector<NodeId> NodeStack;
|
||||
|
||||
// Consume worklists.
|
||||
@ -459,7 +459,6 @@ private:
|
||||
ConservativelyAllocatableNodes.erase(NItr);
|
||||
NodeStack.push_back(NId);
|
||||
G.disconnectAllNeighborsFromNode(NId);
|
||||
|
||||
} else if (!NotProvablyAllocatableNodes.empty()) {
|
||||
NodeSet::iterator NItr =
|
||||
std::min_element(NotProvablyAllocatableNodes.begin(),
|
||||
@ -493,7 +492,7 @@ private:
|
||||
};
|
||||
|
||||
Graph& G;
|
||||
typedef std::set<NodeId> NodeSet;
|
||||
using NodeSet = std::set<NodeId>;
|
||||
NodeSet OptimallyReducibleNodes;
|
||||
NodeSet ConservativelyAllocatableNodes;
|
||||
NodeSet NotProvablyAllocatableNodes;
|
||||
@ -501,7 +500,7 @@ private:
|
||||
|
||||
class PBQPRAGraph : public PBQP::Graph<RegAllocSolverImpl> {
|
||||
private:
|
||||
typedef PBQP::Graph<RegAllocSolverImpl> BaseT;
|
||||
using BaseT = PBQP::Graph<RegAllocSolverImpl>;
|
||||
|
||||
public:
|
||||
PBQPRAGraph(GraphMetadata Metadata) : BaseT(std::move(Metadata)) {}
|
||||
|
@ -204,6 +204,10 @@ private:
|
||||
void setLiveInsUsed(const MachineBasicBlock &MBB);
|
||||
};
|
||||
|
||||
/// Replaces all frame index virtual registers with physical registers. Uses the
|
||||
/// register scavenger to find an appropriate register to use.
|
||||
void scavengeFrameVirtualRegs(MachineFunction &MF, RegScavenger &RS);
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_CODEGEN_REGISTERSCAVENGING_H
|
||||
|
@ -1,4 +1,4 @@
|
||||
//==- ScheduleDAGInstrs.h - MachineInstr Scheduling --------------*- C++ -*-==//
|
||||
//===- ScheduleDAGInstrs.h - MachineInstr Scheduling ------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
@ -15,22 +15,38 @@
|
||||
#ifndef LLVM_CODEGEN_SCHEDULEDAGINSTRS_H
|
||||
#define LLVM_CODEGEN_SCHEDULEDAGINSTRS_H
|
||||
|
||||
#include "llvm/ADT/MapVector.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/PointerIntPair.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/SparseMultiSet.h"
|
||||
#include "llvm/ADT/SparseSet.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/CodeGen/LivePhysRegs.h"
|
||||
#include "llvm/CodeGen/MachineBasicBlock.h"
|
||||
#include "llvm/CodeGen/ScheduleDAG.h"
|
||||
#include "llvm/CodeGen/TargetSchedule.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include "llvm/MC/LaneBitmask.h"
|
||||
#include "llvm/Target/TargetRegisterInfo.h"
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <list>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class LiveIntervals;
|
||||
class MachineFrameInfo;
|
||||
class MachineFunction;
|
||||
class MachineInstr;
|
||||
class MachineLoopInfo;
|
||||
class MachineDominatorTree;
|
||||
class RegPressureTracker;
|
||||
class MachineOperand;
|
||||
struct MCSchedClassDesc;
|
||||
class PressureDiffs;
|
||||
class PseudoSourceValue;
|
||||
class RegPressureTracker;
|
||||
class UndefValue;
|
||||
class Value;
|
||||
|
||||
/// An individual mapping from virtual register number to SUnit.
|
||||
struct VReg2SUnit {
|
||||
@ -70,31 +86,34 @@ namespace llvm {
|
||||
/// Use a SparseMultiSet to track physical registers. Storage is only
|
||||
/// allocated once for the pass. It can be cleared in constant time and reused
|
||||
/// without any frees.
|
||||
typedef SparseMultiSet<PhysRegSUOper, llvm::identity<unsigned>, uint16_t>
|
||||
Reg2SUnitsMap;
|
||||
using Reg2SUnitsMap =
|
||||
SparseMultiSet<PhysRegSUOper, identity<unsigned>, uint16_t>;
|
||||
|
||||
/// Use SparseSet as a SparseMap by relying on the fact that it never
|
||||
/// compares ValueT's, only unsigned keys. This allows the set to be cleared
|
||||
/// between scheduling regions in constant time as long as ValueT does not
|
||||
/// require a destructor.
|
||||
typedef SparseSet<VReg2SUnit, VirtReg2IndexFunctor> VReg2SUnitMap;
|
||||
using VReg2SUnitMap = SparseSet<VReg2SUnit, VirtReg2IndexFunctor>;
|
||||
|
||||
/// Track local uses of virtual registers. These uses are gathered by the DAG
|
||||
/// builder and may be consulted by the scheduler to avoid iterating an entire
|
||||
/// vreg use list.
|
||||
typedef SparseMultiSet<VReg2SUnit, VirtReg2IndexFunctor> VReg2SUnitMultiMap;
|
||||
using VReg2SUnitMultiMap = SparseMultiSet<VReg2SUnit, VirtReg2IndexFunctor>;
|
||||
|
||||
typedef SparseMultiSet<VReg2SUnitOperIdx, VirtReg2IndexFunctor>
|
||||
VReg2SUnitOperIdxMultiMap;
|
||||
using VReg2SUnitOperIdxMultiMap =
|
||||
SparseMultiSet<VReg2SUnitOperIdx, VirtReg2IndexFunctor>;
|
||||
|
||||
using ValueType = PointerUnion<const Value *, const PseudoSourceValue *>;
|
||||
|
||||
typedef PointerUnion<const Value *, const PseudoSourceValue *> ValueType;
|
||||
struct UnderlyingObject : PointerIntPair<ValueType, 1, bool> {
|
||||
UnderlyingObject(ValueType V, bool MayAlias)
|
||||
: PointerIntPair<ValueType, 1, bool>(V, MayAlias) {}
|
||||
|
||||
ValueType getValue() const { return getPointer(); }
|
||||
bool mayAlias() const { return getInt(); }
|
||||
};
|
||||
typedef SmallVector<UnderlyingObject, 4> UnderlyingObjectsVector;
|
||||
|
||||
using UnderlyingObjectsVector = SmallVector<UnderlyingObject, 4>;
|
||||
|
||||
/// A ScheduleDAG for scheduling lists of MachineInstr.
|
||||
class ScheduleDAGInstrs : public ScheduleDAG {
|
||||
@ -114,10 +133,10 @@ namespace llvm {
|
||||
/// reordering. A specialized scheduler can override
|
||||
/// TargetInstrInfo::isSchedulingBoundary then enable this flag to indicate
|
||||
/// it has taken responsibility for scheduling the terminator correctly.
|
||||
bool CanHandleTerminators;
|
||||
bool CanHandleTerminators = false;
|
||||
|
||||
/// Whether lane masks should get tracked.
|
||||
bool TrackLaneMasks;
|
||||
bool TrackLaneMasks = false;
|
||||
|
||||
// State specific to the current scheduling region.
|
||||
// ------------------------------------------------
|
||||
@ -155,12 +174,12 @@ namespace llvm {
|
||||
/// Tracks the last instructions in this region using each virtual register.
|
||||
VReg2SUnitOperIdxMultiMap CurrentVRegUses;
|
||||
|
||||
AliasAnalysis *AAForDep;
|
||||
AliasAnalysis *AAForDep = nullptr;
|
||||
|
||||
/// Remember a generic side-effecting instruction as we proceed.
|
||||
/// No other SU ever gets scheduled around it (except in the special
|
||||
/// case of a huge region that gets reduced).
|
||||
SUnit *BarrierChain;
|
||||
SUnit *BarrierChain = nullptr;
|
||||
|
||||
public:
|
||||
/// A list of SUnits, used in Value2SUsMap, during DAG construction.
|
||||
@ -168,7 +187,7 @@ namespace llvm {
|
||||
/// implementation of this data structure, such as a singly linked list
|
||||
/// with a memory pool (SmallVector was tried but slow and SparseSet is not
|
||||
/// applicable).
|
||||
typedef std::list<SUnit *> SUList;
|
||||
using SUList = std::list<SUnit *>;
|
||||
|
||||
protected:
|
||||
/// \brief A map from ValueType to SUList, used during DAG construction, as
|
||||
@ -216,13 +235,13 @@ namespace llvm {
|
||||
/// For an unanalyzable memory access, this Value is used in maps.
|
||||
UndefValue *UnknownValue;
|
||||
|
||||
typedef std::vector<std::pair<MachineInstr *, MachineInstr *>>
|
||||
DbgValueVector;
|
||||
using DbgValueVector =
|
||||
std::vector<std::pair<MachineInstr *, MachineInstr *>>;
|
||||
/// Remember instruction that precedes DBG_VALUE.
|
||||
/// These are generated by buildSchedGraph but persist so they can be
|
||||
/// referenced when emitting the final schedule.
|
||||
DbgValueVector DbgValues;
|
||||
MachineInstr *FirstDbgValue;
|
||||
MachineInstr *FirstDbgValue = nullptr;
|
||||
|
||||
/// Set of live physical registers for updating kill flags.
|
||||
LivePhysRegs LiveRegs;
|
||||
@ -232,7 +251,7 @@ namespace llvm {
|
||||
const MachineLoopInfo *mli,
|
||||
bool RemoveKillFlags = false);
|
||||
|
||||
~ScheduleDAGInstrs() override {}
|
||||
~ScheduleDAGInstrs() override = default;
|
||||
|
||||
/// Gets the machine model for instruction scheduling.
|
||||
const TargetSchedModel *getSchedModel() const { return &SchedModel; }
|
||||
@ -354,6 +373,7 @@ namespace llvm {
|
||||
return nullptr;
|
||||
return I->second;
|
||||
}
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif
|
||||
#endif // LLVM_CODEGEN_SCHEDULEDAGINSTRS_H
|
||||
|
@ -1,4 +1,4 @@
|
||||
//===-- llvm/CodeGen/SelectionDAG.h - InstSelection DAG ---------*- C++ -*-===//
|
||||
//===- llvm/CodeGen/SelectionDAG.h - InstSelection DAG ----------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
@ -15,35 +15,72 @@
|
||||
#ifndef LLVM_CODEGEN_SELECTIONDAG_H
|
||||
#define LLVM_CODEGEN_SELECTIONDAG_H
|
||||
|
||||
#include "llvm/ADT/APFloat.h"
|
||||
#include "llvm/ADT/APInt.h"
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/DenseSet.h"
|
||||
#include "llvm/ADT/SetVector.h"
|
||||
#include "llvm/ADT/StringMap.h"
|
||||
#include "llvm/ADT/FoldingSet.h"
|
||||
#include "llvm/ADT/ilist.h"
|
||||
#include "llvm/ADT/iterator.h"
|
||||
#include "llvm/ADT/iterator_range.h"
|
||||
#include "llvm/ADT/SetVector.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/StringMap.h"
|
||||
#include "llvm/Analysis/AliasAnalysis.h"
|
||||
#include "llvm/CodeGen/DAGCombine.h"
|
||||
#include "llvm/CodeGen/ISDOpcodes.h"
|
||||
#include "llvm/CodeGen/MachineFunction.h"
|
||||
#include "llvm/CodeGen/MachineMemOperand.h"
|
||||
#include "llvm/CodeGen/MachineValueType.h"
|
||||
#include "llvm/CodeGen/SelectionDAGNodes.h"
|
||||
#include "llvm/CodeGen/ValueTypes.h"
|
||||
#include "llvm/IR/DebugLoc.h"
|
||||
#include "llvm/IR/Instructions.h"
|
||||
#include "llvm/IR/Metadata.h"
|
||||
#include "llvm/Support/Allocator.h"
|
||||
#include "llvm/Support/ArrayRecycler.h"
|
||||
#include "llvm/Support/AtomicOrdering.h"
|
||||
#include "llvm/Support/Casting.h"
|
||||
#include "llvm/Support/CodeGen.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Support/RecyclingAllocator.h"
|
||||
#include "llvm/Target/TargetMachine.h"
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class BlockAddress;
|
||||
class Constant;
|
||||
class ConstantFP;
|
||||
class ConstantInt;
|
||||
class DataLayout;
|
||||
struct fltSemantics;
|
||||
class GlobalValue;
|
||||
struct KnownBits;
|
||||
class LLVMContext;
|
||||
class MachineBasicBlock;
|
||||
class MachineConstantPoolValue;
|
||||
class MachineFunction;
|
||||
class MDNode;
|
||||
class MCSymbol;
|
||||
class OptimizationRemarkEmitter;
|
||||
class SDDbgValue;
|
||||
class TargetLowering;
|
||||
class SelectionDAG;
|
||||
class SelectionDAGTargetInfo;
|
||||
class TargetLowering;
|
||||
class TargetMachine;
|
||||
class TargetSubtargetInfo;
|
||||
class Value;
|
||||
|
||||
class SDVTListNode : public FoldingSetNode {
|
||||
friend struct FoldingSetTrait<SDVTListNode>;
|
||||
|
||||
/// A reference to an Interned FoldingSetNodeID for this node.
|
||||
/// The Allocator in SelectionDAG holds the data.
|
||||
/// SDVTList contains all types which are frequently accessed in SelectionDAG.
|
||||
@ -55,11 +92,13 @@ class SDVTListNode : public FoldingSetNode {
|
||||
/// The hash value for SDVTList is fixed, so cache it to avoid
|
||||
/// hash calculation.
|
||||
unsigned HashValue;
|
||||
|
||||
public:
|
||||
SDVTListNode(const FoldingSetNodeIDRef ID, const EVT *VT, unsigned int Num) :
|
||||
FastID(ID), VTs(VT), NumVTs(Num) {
|
||||
HashValue = ID.ComputeHash();
|
||||
}
|
||||
|
||||
SDVTList getSDVTList() {
|
||||
SDVTList result = {VTs, NumVTs};
|
||||
return result;
|
||||
@ -72,12 +111,14 @@ template<> struct FoldingSetTrait<SDVTListNode> : DefaultFoldingSetTrait<SDVTLis
|
||||
static void Profile(const SDVTListNode &X, FoldingSetNodeID& ID) {
|
||||
ID = X.FastID;
|
||||
}
|
||||
|
||||
static bool Equals(const SDVTListNode &X, const FoldingSetNodeID &ID,
|
||||
unsigned IDHash, FoldingSetNodeID &TempID) {
|
||||
if (X.HashValue != IDHash)
|
||||
return false;
|
||||
return ID == X.FastID;
|
||||
}
|
||||
|
||||
static unsigned ComputeHash(const SDVTListNode &X, FoldingSetNodeID &TempID) {
|
||||
return X.HashValue;
|
||||
}
|
||||
@ -104,13 +145,13 @@ class SDDbgInfo {
|
||||
BumpPtrAllocator Alloc;
|
||||
SmallVector<SDDbgValue*, 32> DbgValues;
|
||||
SmallVector<SDDbgValue*, 32> ByvalParmDbgValues;
|
||||
typedef DenseMap<const SDNode*, SmallVector<SDDbgValue*, 2> > DbgValMapType;
|
||||
using DbgValMapType = DenseMap<const SDNode *, SmallVector<SDDbgValue *, 2>>;
|
||||
DbgValMapType DbgValMap;
|
||||
|
||||
void operator=(const SDDbgInfo&) = delete;
|
||||
SDDbgInfo(const SDDbgInfo&) = delete;
|
||||
public:
|
||||
SDDbgInfo() {}
|
||||
SDDbgInfo() = default;
|
||||
SDDbgInfo(const SDDbgInfo &) = delete;
|
||||
SDDbgInfo &operator=(const SDDbgInfo &) = delete;
|
||||
|
||||
void add(SDDbgValue *V, const SDNode *Node, bool isParameter) {
|
||||
if (isParameter) {
|
||||
@ -144,14 +185,14 @@ public:
|
||||
return ArrayRef<SDDbgValue*>();
|
||||
}
|
||||
|
||||
typedef SmallVectorImpl<SDDbgValue*>::iterator DbgIterator;
|
||||
using DbgIterator = SmallVectorImpl<SDDbgValue*>::iterator;
|
||||
|
||||
DbgIterator DbgBegin() { return DbgValues.begin(); }
|
||||
DbgIterator DbgEnd() { return DbgValues.end(); }
|
||||
DbgIterator ByvalParmDbgBegin() { return ByvalParmDbgValues.begin(); }
|
||||
DbgIterator ByvalParmDbgEnd() { return ByvalParmDbgValues.end(); }
|
||||
};
|
||||
|
||||
class SelectionDAG;
|
||||
void checkForCycles(const SelectionDAG *DAG, bool force = false);
|
||||
|
||||
/// This is used to represent a portion of an LLVM function in a low-level
|
||||
@ -167,8 +208,8 @@ void checkForCycles(const SelectionDAG *DAG, bool force = false);
|
||||
///
|
||||
class SelectionDAG {
|
||||
const TargetMachine &TM;
|
||||
const SelectionDAGTargetInfo *TSI;
|
||||
const TargetLowering *TLI;
|
||||
const SelectionDAGTargetInfo *TSI = nullptr;
|
||||
const TargetLowering *TLI = nullptr;
|
||||
MachineFunction *MF;
|
||||
LLVMContext *Context;
|
||||
CodeGenOpt::Level OptLevel;
|
||||
@ -188,9 +229,9 @@ class SelectionDAG {
|
||||
|
||||
/// The AllocatorType for allocating SDNodes. We use
|
||||
/// pool allocation with recycling.
|
||||
typedef RecyclingAllocator<BumpPtrAllocator, SDNode, sizeof(LargestSDNode),
|
||||
alignof(MostAlignedSDNode)>
|
||||
NodeAllocatorType;
|
||||
using NodeAllocatorType = RecyclingAllocator<BumpPtrAllocator, SDNode,
|
||||
sizeof(LargestSDNode),
|
||||
alignof(MostAlignedSDNode)>;
|
||||
|
||||
/// Pool allocation for nodes.
|
||||
NodeAllocatorType NodeAllocator;
|
||||
@ -243,9 +284,11 @@ public:
|
||||
|
||||
struct DAGNodeDeletedListener : public DAGUpdateListener {
|
||||
std::function<void(SDNode *, SDNode *)> Callback;
|
||||
|
||||
DAGNodeDeletedListener(SelectionDAG &DAG,
|
||||
std::function<void(SDNode *, SDNode *)> Callback)
|
||||
: DAGUpdateListener(DAG), Callback(std::move(Callback)) {}
|
||||
|
||||
void NodeDeleted(SDNode *N, SDNode *E) override { Callback(N, E); }
|
||||
};
|
||||
|
||||
@ -254,7 +297,7 @@ public:
|
||||
/// have legal types. This is important after type legalization since
|
||||
/// any illegally typed nodes generated after this point will not experience
|
||||
/// type legalization.
|
||||
bool NewNodesMustHaveLegalTypes;
|
||||
bool NewNodesMustHaveLegalTypes = false;
|
||||
|
||||
private:
|
||||
/// DAGUpdateListener is a friend so it can manipulate the listener stack.
|
||||
@ -262,7 +305,7 @@ private:
|
||||
|
||||
/// Linked list of registered DAGUpdateListener instances.
|
||||
/// This stack is maintained by DAGUpdateListener RAII.
|
||||
DAGUpdateListener *UpdateListeners;
|
||||
DAGUpdateListener *UpdateListeners = nullptr;
|
||||
|
||||
/// Implementation of setSubgraphColor.
|
||||
/// Return whether we had to truncate the search.
|
||||
@ -316,11 +359,10 @@ private:
|
||||
Node->OperandList = nullptr;
|
||||
}
|
||||
|
||||
void operator=(const SelectionDAG&) = delete;
|
||||
SelectionDAG(const SelectionDAG&) = delete;
|
||||
|
||||
public:
|
||||
explicit SelectionDAG(const TargetMachine &TM, llvm::CodeGenOpt::Level);
|
||||
explicit SelectionDAG(const TargetMachine &TM, CodeGenOpt::Level);
|
||||
SelectionDAG(const SelectionDAG &) = delete;
|
||||
SelectionDAG &operator=(const SelectionDAG &) = delete;
|
||||
~SelectionDAG();
|
||||
|
||||
/// Prepare this SelectionDAG to process code in the given MachineFunction.
|
||||
@ -364,12 +406,16 @@ public:
|
||||
/// Convenience for setting subgraph color attribute.
|
||||
void setSubgraphColor(SDNode *N, const char *Color);
|
||||
|
||||
typedef ilist<SDNode>::const_iterator allnodes_const_iterator;
|
||||
using allnodes_const_iterator = ilist<SDNode>::const_iterator;
|
||||
|
||||
allnodes_const_iterator allnodes_begin() const { return AllNodes.begin(); }
|
||||
allnodes_const_iterator allnodes_end() const { return AllNodes.end(); }
|
||||
typedef ilist<SDNode>::iterator allnodes_iterator;
|
||||
|
||||
using allnodes_iterator = ilist<SDNode>::iterator;
|
||||
|
||||
allnodes_iterator allnodes_begin() { return AllNodes.begin(); }
|
||||
allnodes_iterator allnodes_end() { return AllNodes.end(); }
|
||||
|
||||
ilist<SDNode>::size_type allnodes_size() const {
|
||||
return AllNodes.size();
|
||||
}
|
||||
@ -475,7 +521,6 @@ public:
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Node creation methods.
|
||||
//
|
||||
|
||||
/// \brief Create a ConstantSDNode wrapping a constant value.
|
||||
/// If VT is a vector type, the constant is splatted into a BUILD_VECTOR.
|
||||
@ -1251,9 +1296,11 @@ public:
|
||||
|
||||
SDDbgInfo::DbgIterator DbgBegin() { return DbgInfo->DbgBegin(); }
|
||||
SDDbgInfo::DbgIterator DbgEnd() { return DbgInfo->DbgEnd(); }
|
||||
|
||||
SDDbgInfo::DbgIterator ByvalParmDbgBegin() {
|
||||
return DbgInfo->ByvalParmDbgBegin();
|
||||
}
|
||||
|
||||
SDDbgInfo::DbgIterator ByvalParmDbgEnd() {
|
||||
return DbgInfo->ByvalParmDbgEnd();
|
||||
}
|
||||
@ -1479,10 +1526,12 @@ private:
|
||||
};
|
||||
|
||||
template <> struct GraphTraits<SelectionDAG*> : public GraphTraits<SDNode*> {
|
||||
typedef pointer_iterator<SelectionDAG::allnodes_iterator> nodes_iterator;
|
||||
using nodes_iterator = pointer_iterator<SelectionDAG::allnodes_iterator>;
|
||||
|
||||
static nodes_iterator nodes_begin(SelectionDAG *G) {
|
||||
return nodes_iterator(G->allnodes_begin());
|
||||
}
|
||||
|
||||
static nodes_iterator nodes_end(SelectionDAG *G) {
|
||||
return nodes_iterator(G->allnodes_end());
|
||||
}
|
||||
@ -1493,7 +1542,6 @@ SDValue SelectionDAG::getTargetMemSDNode(SDVTList VTs,
|
||||
ArrayRef<SDValue> Ops,
|
||||
const SDLoc &dl, EVT MemVT,
|
||||
MachineMemOperand *MMO) {
|
||||
|
||||
/// Compose node ID and try to find an existing node.
|
||||
FoldingSetNodeID ID;
|
||||
unsigned Opcode =
|
||||
@ -1524,6 +1572,6 @@ SDValue SelectionDAG::getTargetMemSDNode(SDVTList VTs,
|
||||
return SDValue(N, 0);
|
||||
}
|
||||
|
||||
} // end namespace llvm
|
||||
} // end namespace llvm
|
||||
|
||||
#endif
|
||||
#endif // LLVM_CODEGEN_SELECTIONDAG_H
|
||||
|
@ -37,6 +37,7 @@
|
||||
#include "llvm/IR/DebugLoc.h"
|
||||
#include "llvm/IR/Instruction.h"
|
||||
#include "llvm/IR/Instructions.h"
|
||||
#include "llvm/IR/Metadata.h"
|
||||
#include "llvm/Support/AlignOf.h"
|
||||
#include "llvm/Support/AtomicOrdering.h"
|
||||
#include "llvm/Support/Casting.h"
|
||||
@ -53,14 +54,18 @@
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class SelectionDAG;
|
||||
class APInt;
|
||||
class Constant;
|
||||
template <typename T> struct DenseMapInfo;
|
||||
class GlobalValue;
|
||||
class MachineBasicBlock;
|
||||
class MachineConstantPoolValue;
|
||||
class SDNode;
|
||||
class Value;
|
||||
class MCSymbol;
|
||||
template <typename T> struct DenseMapInfo;
|
||||
class raw_ostream;
|
||||
class SDNode;
|
||||
class SelectionDAG;
|
||||
class Type;
|
||||
class Value;
|
||||
|
||||
void checkForCycles(const SDNode *N, const SelectionDAG *DAG = nullptr,
|
||||
bool force = false);
|
||||
@ -229,13 +234,15 @@ template <> struct isPodLike<SDValue> { static const bool value = true; };
|
||||
/// Allow casting operators to work directly on
|
||||
/// SDValues as if they were SDNode*'s.
|
||||
template<> struct simplify_type<SDValue> {
|
||||
typedef SDNode* SimpleType;
|
||||
using SimpleType = SDNode *;
|
||||
|
||||
static SimpleType getSimplifiedValue(SDValue &Val) {
|
||||
return Val.getNode();
|
||||
}
|
||||
};
|
||||
template<> struct simplify_type<const SDValue> {
|
||||
typedef /*const*/ SDNode* SimpleType;
|
||||
using SimpleType = /*const*/ SDNode *;
|
||||
|
||||
static SimpleType getSimplifiedValue(const SDValue &Val) {
|
||||
return Val.getNode();
|
||||
}
|
||||
@ -330,7 +337,8 @@ private:
|
||||
/// simplify_type specializations - Allow casting operators to work directly on
|
||||
/// SDValues as if they were SDNode*'s.
|
||||
template<> struct simplify_type<SDUse> {
|
||||
typedef SDNode* SimpleType;
|
||||
using SimpleType = SDNode *;
|
||||
|
||||
static SimpleType getSimplifiedValue(SDUse &Val) {
|
||||
return Val.getNode();
|
||||
}
|
||||
@ -695,10 +703,10 @@ public:
|
||||
explicit use_iterator(SDUse *op) : Op(op) {}
|
||||
|
||||
public:
|
||||
typedef std::iterator<std::forward_iterator_tag,
|
||||
SDUse, ptrdiff_t>::reference reference;
|
||||
typedef std::iterator<std::forward_iterator_tag,
|
||||
SDUse, ptrdiff_t>::pointer pointer;
|
||||
using reference = std::iterator<std::forward_iterator_tag,
|
||||
SDUse, ptrdiff_t>::reference;
|
||||
using pointer = std::iterator<std::forward_iterator_tag,
|
||||
SDUse, ptrdiff_t>::pointer;
|
||||
|
||||
use_iterator() = default;
|
||||
use_iterator(const use_iterator &I) : Op(I.Op) {}
|
||||
@ -824,7 +832,7 @@ public:
|
||||
return OperandList[Num];
|
||||
}
|
||||
|
||||
typedef SDUse* op_iterator;
|
||||
using op_iterator = SDUse *;
|
||||
|
||||
op_iterator op_begin() const { return OperandList; }
|
||||
op_iterator op_end() const { return OperandList+NumOperands; }
|
||||
@ -896,7 +904,8 @@ public:
|
||||
return getValueType(ResNo).getSizeInBits();
|
||||
}
|
||||
|
||||
typedef const EVT* value_iterator;
|
||||
using value_iterator = const EVT *;
|
||||
|
||||
value_iterator value_begin() const { return ValueList; }
|
||||
value_iterator value_end() const { return ValueList+NumValues; }
|
||||
|
||||
@ -1822,8 +1831,7 @@ class BlockAddressSDNode : public SDNode {
|
||||
BlockAddressSDNode(unsigned NodeTy, EVT VT, const BlockAddress *ba,
|
||||
int64_t o, unsigned char Flags)
|
||||
: SDNode(NodeTy, 0, DebugLoc(), getSDVTList(VT)),
|
||||
BA(ba), Offset(o), TargetFlags(Flags) {
|
||||
}
|
||||
BA(ba), Offset(o), TargetFlags(Flags) {}
|
||||
|
||||
public:
|
||||
const BlockAddress *getBlockAddress() const { return BA; }
|
||||
@ -2154,7 +2162,7 @@ public:
|
||||
/// instruction selection proper phase.
|
||||
class MachineSDNode : public SDNode {
|
||||
public:
|
||||
typedef MachineMemOperand **mmo_iterator;
|
||||
using mmo_iterator = MachineMemOperand **;
|
||||
|
||||
private:
|
||||
friend class SelectionDAG;
|
||||
@ -2226,8 +2234,8 @@ public:
|
||||
};
|
||||
|
||||
template <> struct GraphTraits<SDNode*> {
|
||||
typedef SDNode *NodeRef;
|
||||
typedef SDNodeIterator ChildIteratorType;
|
||||
using NodeRef = SDNode *;
|
||||
using ChildIteratorType = SDNodeIterator;
|
||||
|
||||
static NodeRef getEntryNode(SDNode *N) { return N; }
|
||||
|
||||
@ -2244,12 +2252,12 @@ template <> struct GraphTraits<SDNode*> {
|
||||
///
|
||||
/// This needs to be a union because the largest node differs on 32 bit systems
|
||||
/// with 4 and 8 byte pointer alignment, respectively.
|
||||
typedef AlignedCharArrayUnion<AtomicSDNode, TargetIndexSDNode,
|
||||
BlockAddressSDNode, GlobalAddressSDNode>
|
||||
LargestSDNode;
|
||||
using LargestSDNode = AlignedCharArrayUnion<AtomicSDNode, TargetIndexSDNode,
|
||||
BlockAddressSDNode,
|
||||
GlobalAddressSDNode>;
|
||||
|
||||
/// The SDNode class with the greatest alignment requirement.
|
||||
typedef GlobalAddressSDNode MostAlignedSDNode;
|
||||
using MostAlignedSDNode = GlobalAddressSDNode;
|
||||
|
||||
namespace ISD {
|
||||
|
||||
|
@ -20,17 +20,26 @@
|
||||
#define LLVM_CODEGEN_SLOTINDEXES_H
|
||||
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/ilist.h"
|
||||
#include "llvm/ADT/IntervalMap.h"
|
||||
#include "llvm/ADT/PointerIntPair.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/ilist.h"
|
||||
#include "llvm/CodeGen/MachineBasicBlock.h"
|
||||
#include "llvm/CodeGen/MachineFunction.h"
|
||||
#include "llvm/CodeGen/MachineFunctionPass.h"
|
||||
#include "llvm/CodeGen/MachineInstr.h"
|
||||
#include "llvm/CodeGen/MachineInstrBundle.h"
|
||||
#include "llvm/Pass.h"
|
||||
#include "llvm/Support/Allocator.h"
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <iterator>
|
||||
#include <utility>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class raw_ostream;
|
||||
|
||||
/// This class represents an entry in the slot index list held in the
|
||||
/// SlotIndexes pass. It should not be used directly. See the
|
||||
/// SlotIndex & SlotIndexes classes for the public interface to this
|
||||
@ -40,7 +49,6 @@ namespace llvm {
|
||||
unsigned index;
|
||||
|
||||
public:
|
||||
|
||||
IndexListEntry(MachineInstr *mi, unsigned index) : mi(mi), index(index) {}
|
||||
|
||||
MachineInstr* getInstr() const { return mi; }
|
||||
@ -301,7 +309,7 @@ namespace llvm {
|
||||
return os;
|
||||
}
|
||||
|
||||
typedef std::pair<SlotIndex, MachineBasicBlock*> IdxMBBPair;
|
||||
using IdxMBBPair = std::pair<SlotIndex, MachineBasicBlock *>;
|
||||
|
||||
inline bool operator<(SlotIndex V, const IdxMBBPair &IM) {
|
||||
return V < IM.first;
|
||||
@ -325,7 +333,7 @@ namespace llvm {
|
||||
// IndexListEntry allocator.
|
||||
BumpPtrAllocator ileAllocator;
|
||||
|
||||
typedef ilist<IndexListEntry> IndexList;
|
||||
using IndexList = ilist<IndexListEntry>;
|
||||
IndexList indexList;
|
||||
|
||||
#ifdef EXPENSIVE_CHECKS
|
||||
@ -334,7 +342,7 @@ namespace llvm {
|
||||
|
||||
MachineFunction *mf;
|
||||
|
||||
typedef DenseMap<const MachineInstr*, SlotIndex> Mi2IndexMap;
|
||||
using Mi2IndexMap = DenseMap<const MachineInstr *, SlotIndex>;
|
||||
Mi2IndexMap mi2iMap;
|
||||
|
||||
/// MBBRanges - Map MBB number to (start, stop) indexes.
|
||||
@ -436,7 +444,7 @@ namespace llvm {
|
||||
const MachineBasicBlock *MBB = MI.getParent();
|
||||
assert(MBB && "MI must be inserted inna basic block");
|
||||
MachineBasicBlock::const_iterator I = MI, B = MBB->begin();
|
||||
for (;;) {
|
||||
while (true) {
|
||||
if (I == B)
|
||||
return getMBBStartIdx(MBB);
|
||||
--I;
|
||||
@ -453,7 +461,7 @@ namespace llvm {
|
||||
const MachineBasicBlock *MBB = MI.getParent();
|
||||
assert(MBB && "MI must be inserted inna basic block");
|
||||
MachineBasicBlock::const_iterator I = MI, E = MBB->end();
|
||||
for (;;) {
|
||||
while (true) {
|
||||
++I;
|
||||
if (I == E)
|
||||
return getMBBEndIdx(MBB);
|
||||
@ -497,21 +505,25 @@ namespace llvm {
|
||||
|
||||
/// Iterator over the idx2MBBMap (sorted pairs of slot index of basic block
|
||||
/// begin and basic block)
|
||||
typedef SmallVectorImpl<IdxMBBPair>::const_iterator MBBIndexIterator;
|
||||
using MBBIndexIterator = SmallVectorImpl<IdxMBBPair>::const_iterator;
|
||||
|
||||
/// Move iterator to the next IdxMBBPair where the SlotIndex is greater or
|
||||
/// equal to \p To.
|
||||
MBBIndexIterator advanceMBBIndex(MBBIndexIterator I, SlotIndex To) const {
|
||||
return std::lower_bound(I, idx2MBBMap.end(), To);
|
||||
}
|
||||
|
||||
/// Get an iterator pointing to the IdxMBBPair with the biggest SlotIndex
|
||||
/// that is greater or equal to \p Idx.
|
||||
MBBIndexIterator findMBBIndex(SlotIndex Idx) const {
|
||||
return advanceMBBIndex(idx2MBBMap.begin(), Idx);
|
||||
}
|
||||
|
||||
/// Returns an iterator for the begin of the idx2MBBMap.
|
||||
MBBIndexIterator MBBIndexBegin() const {
|
||||
return idx2MBBMap.begin();
|
||||
}
|
||||
|
||||
/// Return an iterator for the end of the idx2MBBMap.
|
||||
MBBIndexIterator MBBIndexEnd() const {
|
||||
return idx2MBBMap.end();
|
||||
|
@ -145,21 +145,27 @@ public:
|
||||
///
|
||||
/// Statepoint operands take the form:
|
||||
/// <id>, <num patch bytes >, <num call arguments>, <call target>,
|
||||
/// [call arguments], <StackMaps::ConstantOp>, <calling convention>,
|
||||
/// [call arguments...],
|
||||
/// <StackMaps::ConstantOp>, <calling convention>,
|
||||
/// <StackMaps::ConstantOp>, <statepoint flags>,
|
||||
/// <StackMaps::ConstantOp>, <num other args>, [other args],
|
||||
/// [gc values]
|
||||
/// <StackMaps::ConstantOp>, <num deopt args>, [deopt args...],
|
||||
/// <gc base/derived pairs...> <gc allocas...>
|
||||
/// Note that the last two sets of arguments are not currently length
|
||||
/// prefixed.
|
||||
class StatepointOpers {
|
||||
private:
|
||||
// TODO:: we should change the STATEPOINT representation so that CC and
|
||||
// Flags should be part of meta operands, with args and deopt operands, and
|
||||
// gc operands all prefixed by their length and a type code. This would be
|
||||
// much more consistent.
|
||||
public:
|
||||
// These values are aboolute offsets into the operands of the statepoint
|
||||
// instruction.
|
||||
enum { IDPos, NBytesPos, NCallArgsPos, CallTargetPos, MetaEnd };
|
||||
|
||||
// These values are relative offests from the start of the statepoint meta
|
||||
// arguments (i.e. the end of the call arguments).
|
||||
enum { CCOffset = 1, FlagsOffset = 3, NumVMSArgsOffset = 5 };
|
||||
enum { CCOffset = 1, FlagsOffset = 3, NumDeoptOperandsOffset = 5 };
|
||||
|
||||
public:
|
||||
explicit StatepointOpers(const MachineInstr *MI) : MI(MI) {}
|
||||
|
||||
/// Get starting index of non call related arguments
|
||||
@ -220,7 +226,7 @@ public:
|
||||
// OpTypes are used to encode information about the following logical
|
||||
// operand (which may consist of several MachineOperands) for the
|
||||
// OpParser.
|
||||
typedef enum { DirectMemRefOp, IndirectMemRefOp, ConstantOp } OpType;
|
||||
using OpType = enum { DirectMemRefOp, IndirectMemRefOp, ConstantOp };
|
||||
|
||||
StackMaps(AsmPrinter &AP);
|
||||
|
||||
@ -248,9 +254,10 @@ public:
|
||||
|
||||
private:
|
||||
static const char *WSMP;
|
||||
typedef SmallVector<Location, 8> LocationVec;
|
||||
typedef SmallVector<LiveOutReg, 8> LiveOutVec;
|
||||
typedef MapVector<uint64_t, uint64_t> ConstantPool;
|
||||
|
||||
using LocationVec = SmallVector<Location, 8>;
|
||||
using LiveOutVec = SmallVector<LiveOutReg, 8>;
|
||||
using ConstantPool = MapVector<uint64_t, uint64_t>;
|
||||
|
||||
struct FunctionInfo {
|
||||
uint64_t StackSize = 0;
|
||||
@ -273,8 +280,8 @@ private:
|
||||
LiveOuts(std::move(LiveOuts)) {}
|
||||
};
|
||||
|
||||
typedef MapVector<const MCSymbol *, FunctionInfo> FnInfoMap;
|
||||
typedef std::vector<CallsiteInfo> CallsiteInfoList;
|
||||
using FnInfoMap = MapVector<const MCSymbol *, FunctionInfo>;
|
||||
using CallsiteInfoList = std::vector<CallsiteInfo>;
|
||||
|
||||
AsmPrinter &AP;
|
||||
CallsiteInfoList CSInfos;
|
||||
|
@ -55,6 +55,9 @@ public:
|
||||
/// Return the MCSchedClassDesc for this instruction.
|
||||
const MCSchedClassDesc *resolveSchedClass(const MachineInstr *MI) const;
|
||||
|
||||
/// \brief TargetSubtargetInfo getter.
|
||||
const TargetSubtargetInfo *getSubtargetInfo() const { return STI; }
|
||||
|
||||
/// \brief TargetInstrInfo getter.
|
||||
const TargetInstrInfo *getInstrInfo() const { return TII; }
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
//===-- llvm/CodeGen/WinEHFuncInfo.h ----------------------------*- C++ -*-===//
|
||||
//===- llvm/CodeGen/WinEHFuncInfo.h -----------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
@ -17,28 +17,26 @@
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/PointerUnion.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/TinyPtrVector.h"
|
||||
#include "llvm/IR/Instructions.h"
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
#include <utility>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class AllocaInst;
|
||||
class BasicBlock;
|
||||
class CatchReturnInst;
|
||||
class Constant;
|
||||
class FuncletPadInst;
|
||||
class Function;
|
||||
class GlobalVariable;
|
||||
class Instruction;
|
||||
class InvokeInst;
|
||||
class IntrinsicInst;
|
||||
class LandingPadInst;
|
||||
class MCExpr;
|
||||
class MCSymbol;
|
||||
class MachineBasicBlock;
|
||||
class Value;
|
||||
class MCSymbol;
|
||||
|
||||
// The following structs respresent the .xdata tables for various
|
||||
// Windows-related EH personalities.
|
||||
|
||||
typedef PointerUnion<const BasicBlock *, MachineBasicBlock *> MBBOrBasicBlock;
|
||||
using MBBOrBasicBlock = PointerUnion<const BasicBlock *, MachineBasicBlock *>;
|
||||
|
||||
struct CxxUnwindMapEntry {
|
||||
int ToState;
|
||||
@ -99,18 +97,18 @@ struct WinEHFuncInfo {
|
||||
SmallVector<WinEHTryBlockMapEntry, 4> TryBlockMap;
|
||||
SmallVector<SEHUnwindMapEntry, 4> SEHUnwindMap;
|
||||
SmallVector<ClrEHUnwindMapEntry, 4> ClrEHUnwindMap;
|
||||
int UnwindHelpFrameIdx = INT_MAX;
|
||||
int PSPSymFrameIdx = INT_MAX;
|
||||
int UnwindHelpFrameIdx = std::numeric_limits<int>::max();
|
||||
int PSPSymFrameIdx = std::numeric_limits<int>::max();
|
||||
|
||||
int getLastStateNumber() const { return CxxUnwindMap.size() - 1; }
|
||||
|
||||
void addIPToStateRange(const InvokeInst *II, MCSymbol *InvokeBegin,
|
||||
MCSymbol *InvokeEnd);
|
||||
|
||||
int EHRegNodeFrameIndex = INT_MAX;
|
||||
int EHRegNodeEndOffset = INT_MAX;
|
||||
int EHGuardFrameIndex = INT_MAX;
|
||||
int SEHSetFrameOffset = INT_MAX;
|
||||
int EHRegNodeFrameIndex = std::numeric_limits<int>::max();
|
||||
int EHRegNodeEndOffset = std::numeric_limits<int>::max();
|
||||
int EHGuardFrameIndex = std::numeric_limits<int>::max();
|
||||
int SEHSetFrameOffset = std::numeric_limits<int>::max();
|
||||
|
||||
WinEHFuncInfo();
|
||||
};
|
||||
@ -125,5 +123,7 @@ void calculateSEHStateNumbers(const Function *ParentFn,
|
||||
WinEHFuncInfo &FuncInfo);
|
||||
|
||||
void calculateClrEHStateNumbers(const Function *Fn, WinEHFuncInfo &FuncInfo);
|
||||
}
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_CODEGEN_WINEHFUNCINFO_H
|
||||
|
@ -574,6 +574,14 @@ struct FrameData {
|
||||
IsFunctionStart = 1 << 2,
|
||||
};
|
||||
};
|
||||
|
||||
enum class CodeViewContainer { ObjectFile, Pdb };
|
||||
|
||||
inline uint32_t alignOf(CodeViewContainer Container) {
|
||||
if (Container == CodeViewContainer::ObjectFile)
|
||||
return 1;
|
||||
return 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -136,6 +136,7 @@ public:
|
||||
Error mapByteVectorTail(ArrayRef<uint8_t> &Bytes);
|
||||
Error mapByteVectorTail(std::vector<uint8_t> &Bytes);
|
||||
|
||||
Error padToAlignment(uint32_t Align);
|
||||
Error skipPadding();
|
||||
|
||||
private:
|
||||
|
@ -60,8 +60,8 @@ public:
|
||||
Error initialize(BinaryStreamReader Reader);
|
||||
Error initialize(BinaryStreamRef Stream);
|
||||
|
||||
Iterator begin() { return Checksums.begin(); }
|
||||
Iterator end() { return Checksums.end(); }
|
||||
Iterator begin() const { return Checksums.begin(); }
|
||||
Iterator end() const { return Checksums.end(); }
|
||||
|
||||
const FileChecksumArray &getArray() const { return Checksums; }
|
||||
|
||||
|
@ -74,8 +74,13 @@ private:
|
||||
|
||||
class DebugInlineeLinesSubsection final : public DebugSubsection {
|
||||
public:
|
||||
struct Entry {
|
||||
std::vector<support::ulittle32_t> ExtraFiles;
|
||||
InlineeSourceLineHeader Header;
|
||||
};
|
||||
|
||||
DebugInlineeLinesSubsection(DebugChecksumsSubsection &Checksums,
|
||||
bool HasExtraFiles);
|
||||
bool HasExtraFiles = false);
|
||||
|
||||
static bool classof(const DebugSubsection *S) {
|
||||
return S->kind() == DebugSubsectionKind::InlineeLines;
|
||||
@ -87,16 +92,18 @@ public:
|
||||
void addInlineSite(TypeIndex FuncId, StringRef FileName, uint32_t SourceLine);
|
||||
void addExtraFile(StringRef FileName);
|
||||
|
||||
bool hasExtraFiles() const { return HasExtraFiles; }
|
||||
void setHasExtraFiles(bool Has) { HasExtraFiles = Has; }
|
||||
|
||||
std::vector<Entry>::const_iterator begin() const { return Entries.begin(); }
|
||||
std::vector<Entry>::const_iterator end() const { return Entries.end(); }
|
||||
|
||||
private:
|
||||
DebugChecksumsSubsection &Checksums;
|
||||
|
||||
bool HasExtraFiles = false;
|
||||
uint32_t ExtraFileCount = 0;
|
||||
|
||||
struct Entry {
|
||||
std::vector<support::ulittle32_t> ExtraFiles;
|
||||
InlineeSourceLineHeader Header;
|
||||
};
|
||||
std::vector<Entry> Entries;
|
||||
};
|
||||
}
|
||||
|
@ -31,28 +31,32 @@ struct DebugSubsectionHeader {
|
||||
class DebugSubsectionRecord {
|
||||
public:
|
||||
DebugSubsectionRecord();
|
||||
DebugSubsectionRecord(DebugSubsectionKind Kind, BinaryStreamRef Data);
|
||||
DebugSubsectionRecord(DebugSubsectionKind Kind, BinaryStreamRef Data,
|
||||
CodeViewContainer Container);
|
||||
|
||||
static Error initialize(BinaryStreamRef Stream, DebugSubsectionRecord &Info);
|
||||
static Error initialize(BinaryStreamRef Stream, DebugSubsectionRecord &Info,
|
||||
CodeViewContainer Container);
|
||||
|
||||
uint32_t getRecordLength() const;
|
||||
DebugSubsectionKind kind() const;
|
||||
BinaryStreamRef getRecordData() const;
|
||||
|
||||
private:
|
||||
CodeViewContainer Container;
|
||||
DebugSubsectionKind Kind;
|
||||
BinaryStreamRef Data;
|
||||
};
|
||||
|
||||
class DebugSubsectionRecordBuilder {
|
||||
public:
|
||||
DebugSubsectionRecordBuilder(DebugSubsectionKind Kind, DebugSubsection &Frag);
|
||||
DebugSubsectionRecordBuilder(std::unique_ptr<DebugSubsection> Subsection,
|
||||
CodeViewContainer Container);
|
||||
uint32_t calculateSerializedLength();
|
||||
Error commit(BinaryStreamWriter &Writer);
|
||||
|
||||
private:
|
||||
DebugSubsectionKind Kind;
|
||||
DebugSubsection &Frag;
|
||||
std::unique_ptr<DebugSubsection> Subsection;
|
||||
CodeViewContainer Container;
|
||||
};
|
||||
|
||||
} // namespace codeview
|
||||
@ -62,7 +66,12 @@ template <> struct VarStreamArrayExtractor<codeview::DebugSubsectionRecord> {
|
||||
|
||||
static Error extract(BinaryStreamRef Stream, uint32_t &Length,
|
||||
codeview::DebugSubsectionRecord &Info) {
|
||||
if (auto EC = codeview::DebugSubsectionRecord::initialize(Stream, Info))
|
||||
// FIXME: We need to pass the container type through to this function, but
|
||||
// VarStreamArray doesn't easily support stateful contexts. In practice
|
||||
// this isn't super important since the subsection header describes its
|
||||
// length and we can just skip it. It's more important when writing.
|
||||
if (auto EC = codeview::DebugSubsectionRecord::initialize(
|
||||
Stream, Info, codeview::CodeViewContainer::Pdb))
|
||||
return EC;
|
||||
Length = Info.getRecordLength();
|
||||
return Error::success();
|
||||
|
@ -24,9 +24,9 @@ namespace codeview {
|
||||
class SymbolVisitorDelegate;
|
||||
class SymbolDeserializer : public SymbolVisitorCallbacks {
|
||||
struct MappingInfo {
|
||||
explicit MappingInfo(ArrayRef<uint8_t> RecordData)
|
||||
MappingInfo(ArrayRef<uint8_t> RecordData, CodeViewContainer Container)
|
||||
: Stream(RecordData, llvm::support::little), Reader(Stream),
|
||||
Mapping(Reader) {}
|
||||
Mapping(Reader, Container) {}
|
||||
|
||||
BinaryByteStream Stream;
|
||||
BinaryStreamReader Reader;
|
||||
@ -35,7 +35,9 @@ class SymbolDeserializer : public SymbolVisitorCallbacks {
|
||||
|
||||
public:
|
||||
template <typename T> static Error deserializeAs(CVSymbol Symbol, T &Record) {
|
||||
SymbolDeserializer S(nullptr);
|
||||
// If we're just deserializing one record, then don't worry about alignment
|
||||
// as there's nothing that comes after.
|
||||
SymbolDeserializer S(nullptr, CodeViewContainer::ObjectFile);
|
||||
if (auto EC = S.visitSymbolBegin(Symbol))
|
||||
return EC;
|
||||
if (auto EC = S.visitKnownRecord(Symbol, Record))
|
||||
@ -45,12 +47,13 @@ public:
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
explicit SymbolDeserializer(SymbolVisitorDelegate *Delegate)
|
||||
: Delegate(Delegate) {}
|
||||
explicit SymbolDeserializer(SymbolVisitorDelegate *Delegate,
|
||||
CodeViewContainer Container)
|
||||
: Delegate(Delegate), Container(Container) {}
|
||||
|
||||
Error visitSymbolBegin(CVSymbol &Record) override {
|
||||
assert(!Mapping && "Already in a symbol mapping!");
|
||||
Mapping = llvm::make_unique<MappingInfo>(Record.content());
|
||||
Mapping = llvm::make_unique<MappingInfo>(Record.content(), Container);
|
||||
return Mapping->Mapping.visitSymbolBegin(Record);
|
||||
}
|
||||
Error visitSymbolEnd(CVSymbol &Record) override {
|
||||
@ -78,6 +81,7 @@ private:
|
||||
}
|
||||
|
||||
SymbolVisitorDelegate *Delegate;
|
||||
CodeViewContainer Container;
|
||||
std::unique_ptr<MappingInfo> Mapping;
|
||||
};
|
||||
}
|
||||
|
@ -26,9 +26,11 @@ class TypeCollection;
|
||||
class CVSymbolDumper {
|
||||
public:
|
||||
CVSymbolDumper(ScopedPrinter &W, TypeCollection &Types,
|
||||
CodeViewContainer Container,
|
||||
std::unique_ptr<SymbolDumpDelegate> ObjDelegate,
|
||||
bool PrintRecordBytes)
|
||||
: W(W), Types(Types), ObjDelegate(std::move(ObjDelegate)),
|
||||
: W(W), Types(Types), Container(Container),
|
||||
ObjDelegate(std::move(ObjDelegate)),
|
||||
PrintRecordBytes(PrintRecordBytes) {}
|
||||
|
||||
/// Dumps one type record. Returns false if there was a type parsing error,
|
||||
@ -44,6 +46,7 @@ public:
|
||||
private:
|
||||
ScopedPrinter &W;
|
||||
TypeCollection &Types;
|
||||
CodeViewContainer Container;
|
||||
std::unique_ptr<SymbolDumpDelegate> ObjDelegate;
|
||||
|
||||
bool PrintRecordBytes;
|
||||
|
@ -20,8 +20,12 @@ class BinaryStreamWriter;
|
||||
namespace codeview {
|
||||
class SymbolRecordMapping : public SymbolVisitorCallbacks {
|
||||
public:
|
||||
explicit SymbolRecordMapping(BinaryStreamReader &Reader) : IO(Reader) {}
|
||||
explicit SymbolRecordMapping(BinaryStreamWriter &Writer) : IO(Writer) {}
|
||||
explicit SymbolRecordMapping(BinaryStreamReader &Reader,
|
||||
CodeViewContainer Container)
|
||||
: IO(Reader), Container(Container) {}
|
||||
explicit SymbolRecordMapping(BinaryStreamWriter &Writer,
|
||||
CodeViewContainer Container)
|
||||
: IO(Writer), Container(Container) {}
|
||||
|
||||
Error visitSymbolBegin(CVSymbol &Record) override;
|
||||
Error visitSymbolEnd(CVSymbol &Record) override;
|
||||
@ -35,6 +39,7 @@ private:
|
||||
Optional<SymbolKind> Kind;
|
||||
|
||||
CodeViewRecordIO IO;
|
||||
CodeViewContainer Container;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -46,17 +46,18 @@ class SymbolSerializer : public SymbolVisitorCallbacks {
|
||||
|
||||
public:
|
||||
template <typename SymType>
|
||||
static CVSymbol writeOneSymbol(SymType &Sym, BumpPtrAllocator &Storage) {
|
||||
static CVSymbol writeOneSymbol(SymType &Sym, BumpPtrAllocator &Storage,
|
||||
CodeViewContainer Container) {
|
||||
CVSymbol Result;
|
||||
Result.Type = static_cast<SymbolKind>(Sym.Kind);
|
||||
SymbolSerializer Serializer(Storage);
|
||||
SymbolSerializer Serializer(Storage, Container);
|
||||
consumeError(Serializer.visitSymbolBegin(Result));
|
||||
consumeError(Serializer.visitKnownRecord(Result, Sym));
|
||||
consumeError(Serializer.visitSymbolEnd(Result));
|
||||
return Result;
|
||||
}
|
||||
|
||||
explicit SymbolSerializer(BumpPtrAllocator &Storage);
|
||||
SymbolSerializer(BumpPtrAllocator &Storage, CodeViewContainer Container);
|
||||
|
||||
virtual Error visitSymbolBegin(CVSymbol &Record) override;
|
||||
virtual Error visitSymbolEnd(CVSymbol &Record) override;
|
||||
|
@ -44,17 +44,19 @@ class MappedBlockStream : public BinaryStream {
|
||||
public:
|
||||
static std::unique_ptr<MappedBlockStream>
|
||||
createStream(uint32_t BlockSize, const MSFStreamLayout &Layout,
|
||||
BinaryStreamRef MsfData);
|
||||
BinaryStreamRef MsfData, BumpPtrAllocator &Allocator);
|
||||
|
||||
static std::unique_ptr<MappedBlockStream>
|
||||
createIndexedStream(const MSFLayout &Layout, BinaryStreamRef MsfData,
|
||||
uint32_t StreamIndex);
|
||||
uint32_t StreamIndex, BumpPtrAllocator &Allocator);
|
||||
|
||||
static std::unique_ptr<MappedBlockStream>
|
||||
createFpmStream(const MSFLayout &Layout, BinaryStreamRef MsfData);
|
||||
createFpmStream(const MSFLayout &Layout, BinaryStreamRef MsfData,
|
||||
BumpPtrAllocator &Allocator);
|
||||
|
||||
static std::unique_ptr<MappedBlockStream>
|
||||
createDirectoryStream(const MSFLayout &Layout, BinaryStreamRef MsfData);
|
||||
createDirectoryStream(const MSFLayout &Layout, BinaryStreamRef MsfData,
|
||||
BumpPtrAllocator &Allocator);
|
||||
|
||||
llvm::support::endianness getEndian() const override {
|
||||
return llvm::support::little;
|
||||
@ -67,9 +69,7 @@ public:
|
||||
|
||||
uint32_t getLength() override;
|
||||
|
||||
uint32_t getNumBytesCopied() const;
|
||||
|
||||
llvm::BumpPtrAllocator &getAllocator() { return Pool; }
|
||||
llvm::BumpPtrAllocator &getAllocator() { return Allocator; }
|
||||
|
||||
void invalidateCache();
|
||||
|
||||
@ -79,7 +79,7 @@ public:
|
||||
|
||||
protected:
|
||||
MappedBlockStream(uint32_t BlockSize, const MSFStreamLayout &StreamLayout,
|
||||
BinaryStreamRef MsfData);
|
||||
BinaryStreamRef MsfData, BumpPtrAllocator &Allocator);
|
||||
|
||||
private:
|
||||
const MSFStreamLayout &getStreamLayout() const { return StreamLayout; }
|
||||
@ -94,7 +94,15 @@ private:
|
||||
BinaryStreamRef MsfData;
|
||||
|
||||
typedef MutableArrayRef<uint8_t> CacheEntry;
|
||||
llvm::BumpPtrAllocator Pool;
|
||||
|
||||
// We just store the allocator by reference. We use this to allocate
|
||||
// contiguous memory for things like arrays or strings that cross a block
|
||||
// boundary, and this memory is expected to outlive the stream. For example,
|
||||
// someone could create a stream, read some stuff, then close the stream, and
|
||||
// we would like outstanding references to fields to remain valid since the
|
||||
// entire file is mapped anyway. Because of that, the user must supply the
|
||||
// allocator to allocate broken records from.
|
||||
BumpPtrAllocator &Allocator;
|
||||
DenseMap<uint32_t, std::vector<CacheEntry>> CacheMap;
|
||||
};
|
||||
|
||||
@ -102,18 +110,20 @@ class WritableMappedBlockStream : public WritableBinaryStream {
|
||||
public:
|
||||
static std::unique_ptr<WritableMappedBlockStream>
|
||||
createStream(uint32_t BlockSize, const MSFStreamLayout &Layout,
|
||||
WritableBinaryStreamRef MsfData);
|
||||
WritableBinaryStreamRef MsfData, BumpPtrAllocator &Allocator);
|
||||
|
||||
static std::unique_ptr<WritableMappedBlockStream>
|
||||
createIndexedStream(const MSFLayout &Layout, WritableBinaryStreamRef MsfData,
|
||||
uint32_t StreamIndex);
|
||||
uint32_t StreamIndex, BumpPtrAllocator &Allocator);
|
||||
|
||||
static std::unique_ptr<WritableMappedBlockStream>
|
||||
createDirectoryStream(const MSFLayout &Layout,
|
||||
WritableBinaryStreamRef MsfData);
|
||||
WritableBinaryStreamRef MsfData,
|
||||
BumpPtrAllocator &Allocator);
|
||||
|
||||
static std::unique_ptr<WritableMappedBlockStream>
|
||||
createFpmStream(const MSFLayout &Layout, WritableBinaryStreamRef MsfData);
|
||||
createFpmStream(const MSFLayout &Layout, WritableBinaryStreamRef MsfData,
|
||||
BumpPtrAllocator &Allocator);
|
||||
|
||||
llvm::support::endianness getEndian() const override {
|
||||
return llvm::support::little;
|
||||
@ -139,7 +149,8 @@ public:
|
||||
protected:
|
||||
WritableMappedBlockStream(uint32_t BlockSize,
|
||||
const MSFStreamLayout &StreamLayout,
|
||||
WritableBinaryStreamRef MsfData);
|
||||
WritableBinaryStreamRef MsfData,
|
||||
BumpPtrAllocator &Allocator);
|
||||
|
||||
private:
|
||||
MappedBlockStream ReadInterface;
|
||||
|
@ -49,11 +49,8 @@ public:
|
||||
void setObjFileName(StringRef Name);
|
||||
void addSymbol(codeview::CVSymbol Symbol);
|
||||
|
||||
void addC13Fragment(std::unique_ptr<codeview::DebugLinesSubsection> Lines);
|
||||
void addC13Fragment(
|
||||
std::unique_ptr<codeview::DebugInlineeLinesSubsection> Inlinees);
|
||||
void setC13FileChecksums(
|
||||
std::unique_ptr<codeview::DebugChecksumsSubsection> Checksums);
|
||||
void
|
||||
addDebugSubsection(std::unique_ptr<codeview::DebugSubsection> Subsection);
|
||||
|
||||
uint16_t getStreamIndex() const;
|
||||
StringRef getModuleName() const { return ModuleName; }
|
||||
@ -83,10 +80,6 @@ private:
|
||||
std::vector<std::string> SourceFiles;
|
||||
std::vector<codeview::CVSymbol> Symbols;
|
||||
|
||||
std::unique_ptr<codeview::DebugChecksumsSubsection> ChecksumInfo;
|
||||
std::vector<std::unique_ptr<codeview::DebugLinesSubsection>> LineInfo;
|
||||
std::vector<std::unique_ptr<codeview::DebugInlineeLinesSubsection>> Inlinees;
|
||||
|
||||
std::vector<std::unique_ptr<codeview::DebugSubsectionRecordBuilder>>
|
||||
C13Builders;
|
||||
|
||||
|
@ -12,6 +12,7 @@
|
||||
|
||||
#include "llvm/ADT/iterator_range.h"
|
||||
#include "llvm/DebugInfo/CodeView/CVRecord.h"
|
||||
#include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h"
|
||||
#include "llvm/DebugInfo/CodeView/DebugSubsectionRecord.h"
|
||||
#include "llvm/DebugInfo/CodeView/SymbolRecord.h"
|
||||
#include "llvm/DebugInfo/MSF/MappedBlockStream.h"
|
||||
@ -25,7 +26,7 @@ class PDBFile;
|
||||
class DbiModuleDescriptor;
|
||||
|
||||
class ModuleDebugStreamRef {
|
||||
typedef codeview::DebugSubsectionArray::Iterator LinesAndChecksumsIterator;
|
||||
typedef codeview::DebugSubsectionArray::Iterator DebugSubsectionIterator;
|
||||
|
||||
public:
|
||||
ModuleDebugStreamRef(const DbiModuleDescriptor &Module,
|
||||
@ -39,12 +40,15 @@ public:
|
||||
iterator_range<codeview::CVSymbolArray::Iterator>
|
||||
symbols(bool *HadError) const;
|
||||
|
||||
llvm::iterator_range<LinesAndChecksumsIterator> linesAndChecksums() const;
|
||||
llvm::iterator_range<DebugSubsectionIterator> subsections() const;
|
||||
|
||||
bool hasLineInfo() const;
|
||||
bool hasDebugSubsections() const;
|
||||
|
||||
Error commit();
|
||||
|
||||
Expected<codeview::DebugChecksumsSubsectionRef>
|
||||
findChecksumsSubsection() const;
|
||||
|
||||
private:
|
||||
const DbiModuleDescriptor &Mod;
|
||||
|
||||
@ -57,7 +61,7 @@ private:
|
||||
BinaryStreamRef C13LinesSubstream;
|
||||
BinaryStreamRef GlobalRefsSubstream;
|
||||
|
||||
codeview::DebugSubsectionArray LinesAndChecksums;
|
||||
codeview::DebugSubsectionArray Subsections;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -45,6 +45,8 @@ public:
|
||||
|
||||
FixedStreamArray<support::ulittle32_t> name_ids() const;
|
||||
|
||||
codeview::DebugStringTableSubsectionRef getStringTable() const;
|
||||
|
||||
private:
|
||||
Error readHeader(BinaryStreamReader &Reader);
|
||||
Error readStrings(BinaryStreamReader &Reader);
|
||||
|
@ -34,8 +34,7 @@ class TpiStream {
|
||||
friend class TpiStreamBuilder;
|
||||
|
||||
public:
|
||||
TpiStream(const PDBFile &File,
|
||||
std::unique_ptr<msf::MappedBlockStream> Stream);
|
||||
TpiStream(PDBFile &File, std::unique_ptr<msf::MappedBlockStream> Stream);
|
||||
~TpiStream();
|
||||
Error reload();
|
||||
|
||||
@ -61,7 +60,7 @@ public:
|
||||
Error commit();
|
||||
|
||||
private:
|
||||
const PDBFile &Pdb;
|
||||
PDBFile &Pdb;
|
||||
std::unique_ptr<msf::MappedBlockStream> Stream;
|
||||
|
||||
std::unique_ptr<codeview::LazyRandomTypeCollection> Types;
|
||||
|
@ -86,6 +86,10 @@ namespace llvm {
|
||||
/// Construct any deferred debug info descriptors.
|
||||
void finalize();
|
||||
|
||||
/// Finalize a specific subprogram - no new variables may be added to this
|
||||
/// subprogram afterwards.
|
||||
void finalizeSubprogram(DISubprogram *SP);
|
||||
|
||||
/// A CompileUnit provides an anchor for all debugging
|
||||
/// information generated during this instance of compilation.
|
||||
/// \param Lang Source programming language, eg. dwarf::DW_LANG_C99
|
||||
|
@ -90,12 +90,6 @@ namespace llvm {
|
||||
DenseMap<const MDNode *, MDNode *> &Cache,
|
||||
bool ReplaceLast = false);
|
||||
|
||||
/// Reparent all debug locations referenced by \c I that belong to \c OrigSP
|
||||
/// to become (possibly indirect) children of \c NewSP.
|
||||
static void reparentDebugInfo(Instruction &I, DISubprogram *OrigSP,
|
||||
DISubprogram *NewSP,
|
||||
DenseMap<const MDNode *, MDNode *> &Cache);
|
||||
|
||||
unsigned getLine() const;
|
||||
unsigned getCol() const;
|
||||
MDNode *getScope() const;
|
||||
|
@ -134,16 +134,18 @@ public:
|
||||
/// be renamed or references something that can't be renamed).
|
||||
unsigned NotEligibleToImport : 1;
|
||||
|
||||
/// Indicate that the global value must be considered a live root for
|
||||
/// index-based liveness analysis. Used for special LLVM values such as
|
||||
/// llvm.global_ctors that the linker does not know about.
|
||||
unsigned LiveRoot : 1;
|
||||
/// In per-module summary, indicate that the global value must be considered
|
||||
/// a live root for index-based liveness analysis. Used for special LLVM
|
||||
/// values such as llvm.global_ctors that the linker does not know about.
|
||||
///
|
||||
/// In combined summary, indicate that the global value is live.
|
||||
unsigned Live : 1;
|
||||
|
||||
/// Convenience Constructors
|
||||
explicit GVFlags(GlobalValue::LinkageTypes Linkage,
|
||||
bool NotEligibleToImport, bool LiveRoot)
|
||||
bool NotEligibleToImport, bool Live)
|
||||
: Linkage(Linkage), NotEligibleToImport(NotEligibleToImport),
|
||||
LiveRoot(LiveRoot) {}
|
||||
Live(Live) {}
|
||||
};
|
||||
|
||||
private:
|
||||
@ -172,6 +174,8 @@ private:
|
||||
/// are listed in the derived FunctionSummary object.
|
||||
std::vector<ValueInfo> RefEdgeList;
|
||||
|
||||
bool isLive() const { return Flags.Live; }
|
||||
|
||||
protected:
|
||||
GlobalValueSummary(SummaryKind K, GVFlags Flags, std::vector<ValueInfo> Refs)
|
||||
: Kind(K), Flags(Flags), RefEdgeList(std::move(Refs)) {}
|
||||
@ -213,19 +217,17 @@ public:
|
||||
/// Return true if this global value can't be imported.
|
||||
bool notEligibleToImport() const { return Flags.NotEligibleToImport; }
|
||||
|
||||
/// Return true if this global value must be considered a root for live
|
||||
/// value analysis on the index.
|
||||
bool liveRoot() const { return Flags.LiveRoot; }
|
||||
|
||||
/// Flag that this global value must be considered a root for live
|
||||
/// value analysis on the index.
|
||||
void setLiveRoot() { Flags.LiveRoot = true; }
|
||||
void setLive(bool Live) { Flags.Live = Live; }
|
||||
|
||||
/// Flag that this global value cannot be imported.
|
||||
void setNotEligibleToImport() { Flags.NotEligibleToImport = true; }
|
||||
|
||||
/// Return the list of values referenced by this global value definition.
|
||||
ArrayRef<ValueInfo> refs() const { return RefEdgeList; }
|
||||
|
||||
friend class ModuleSummaryIndex;
|
||||
friend void computeDeadSymbols(class ModuleSummaryIndex &,
|
||||
const DenseSet<GlobalValue::GUID> &);
|
||||
};
|
||||
|
||||
/// \brief Alias summary information.
|
||||
@ -535,6 +537,11 @@ private:
|
||||
/// GUIDs, it will be mapped to 0.
|
||||
std::map<GlobalValue::GUID, GlobalValue::GUID> OidGuidMap;
|
||||
|
||||
/// Indicates that summary-based GlobalValue GC has run, and values with
|
||||
/// GVFlags::Live==false are really dead. Otherwise, all values must be
|
||||
/// considered live.
|
||||
bool WithGlobalValueDeadStripping = false;
|
||||
|
||||
// YAML I/O support.
|
||||
friend yaml::MappingTraits<ModuleSummaryIndex>;
|
||||
|
||||
@ -550,6 +557,17 @@ public:
|
||||
const_gvsummary_iterator end() const { return GlobalValueMap.end(); }
|
||||
size_t size() const { return GlobalValueMap.size(); }
|
||||
|
||||
bool withGlobalValueDeadStripping() const {
|
||||
return WithGlobalValueDeadStripping;
|
||||
}
|
||||
void setWithGlobalValueDeadStripping() {
|
||||
WithGlobalValueDeadStripping = true;
|
||||
}
|
||||
|
||||
bool isGlobalValueLive(const GlobalValueSummary *GVS) const {
|
||||
return !WithGlobalValueDeadStripping || GVS->isLive();
|
||||
}
|
||||
|
||||
/// Return a ValueInfo for GUID if it exists, otherwise return ValueInfo().
|
||||
ValueInfo getValueInfo(GlobalValue::GUID GUID) const {
|
||||
auto I = GlobalValueMap.find(GUID);
|
||||
|
@ -128,6 +128,8 @@ template <> struct MappingTraits<TypeIdSummary> {
|
||||
};
|
||||
|
||||
struct FunctionSummaryYaml {
|
||||
unsigned Linkage;
|
||||
bool NotEligibleToImport, Live;
|
||||
std::vector<uint64_t> TypeTests;
|
||||
std::vector<FunctionSummary::VFuncId> TypeTestAssumeVCalls,
|
||||
TypeCheckedLoadVCalls;
|
||||
@ -168,6 +170,9 @@ namespace yaml {
|
||||
|
||||
template <> struct MappingTraits<FunctionSummaryYaml> {
|
||||
static void mapping(IO &io, FunctionSummaryYaml& summary) {
|
||||
io.mapOptional("Linkage", summary.Linkage);
|
||||
io.mapOptional("NotEligibleToImport", summary.NotEligibleToImport);
|
||||
io.mapOptional("Live", summary.Live);
|
||||
io.mapOptional("TypeTests", summary.TypeTests);
|
||||
io.mapOptional("TypeTestAssumeVCalls", summary.TypeTestAssumeVCalls);
|
||||
io.mapOptional("TypeCheckedLoadVCalls", summary.TypeCheckedLoadVCalls);
|
||||
@ -199,12 +204,12 @@ template <> struct CustomMappingTraits<GlobalValueSummaryMapTy> {
|
||||
}
|
||||
auto &Elem = V[KeyInt];
|
||||
for (auto &FSum : FSums) {
|
||||
GlobalValueSummary::GVFlags GVFlags(GlobalValue::ExternalLinkage, false,
|
||||
false);
|
||||
Elem.SummaryList.push_back(llvm::make_unique<FunctionSummary>(
|
||||
GVFlags, 0, ArrayRef<ValueInfo>{},
|
||||
ArrayRef<FunctionSummary::EdgeTy>{}, std::move(FSum.TypeTests),
|
||||
std::move(FSum.TypeTestAssumeVCalls),
|
||||
GlobalValueSummary::GVFlags(
|
||||
static_cast<GlobalValue::LinkageTypes>(FSum.Linkage),
|
||||
FSum.NotEligibleToImport, FSum.Live),
|
||||
0, ArrayRef<ValueInfo>{}, ArrayRef<FunctionSummary::EdgeTy>{},
|
||||
std::move(FSum.TypeTests), std::move(FSum.TypeTestAssumeVCalls),
|
||||
std::move(FSum.TypeCheckedLoadVCalls),
|
||||
std::move(FSum.TypeTestAssumeConstVCalls),
|
||||
std::move(FSum.TypeCheckedLoadConstVCalls)));
|
||||
@ -216,8 +221,10 @@ template <> struct CustomMappingTraits<GlobalValueSummaryMapTy> {
|
||||
for (auto &Sum : P.second.SummaryList) {
|
||||
if (auto *FSum = dyn_cast<FunctionSummary>(Sum.get()))
|
||||
FSums.push_back(FunctionSummaryYaml{
|
||||
FSum->type_tests(), FSum->type_test_assume_vcalls(),
|
||||
FSum->type_checked_load_vcalls(),
|
||||
FSum->flags().Linkage,
|
||||
static_cast<bool>(FSum->flags().NotEligibleToImport),
|
||||
static_cast<bool>(FSum->flags().Live), FSum->type_tests(),
|
||||
FSum->type_test_assume_vcalls(), FSum->type_checked_load_vcalls(),
|
||||
FSum->type_test_assume_const_vcalls(),
|
||||
FSum->type_checked_load_const_vcalls()});
|
||||
}
|
||||
@ -231,6 +238,8 @@ template <> struct MappingTraits<ModuleSummaryIndex> {
|
||||
static void mapping(IO &io, ModuleSummaryIndex& index) {
|
||||
io.mapOptional("GlobalValueMap", index.GlobalValueMap);
|
||||
io.mapOptional("TypeIdMap", index.TypeIdMap);
|
||||
io.mapOptional("WithGlobalValueDeadStripping",
|
||||
index.WithGlobalValueDeadStripping);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -228,24 +228,24 @@ public:
|
||||
return cast<ConstantInt>(NumVMSArgs)->getZExtValue();
|
||||
}
|
||||
|
||||
typename CallSiteTy::arg_iterator vm_state_begin() const {
|
||||
typename CallSiteTy::arg_iterator deopt_begin() const {
|
||||
auto I = gc_transition_args_end() + 1;
|
||||
assert((getCallSite().arg_end() - I) >= 0);
|
||||
return I;
|
||||
}
|
||||
typename CallSiteTy::arg_iterator vm_state_end() const {
|
||||
auto I = vm_state_begin() + getNumTotalVMSArgs();
|
||||
typename CallSiteTy::arg_iterator deopt_end() const {
|
||||
auto I = deopt_begin() + getNumTotalVMSArgs();
|
||||
assert((getCallSite().arg_end() - I) >= 0);
|
||||
return I;
|
||||
}
|
||||
|
||||
/// range adapter for vm state arguments
|
||||
iterator_range<arg_iterator> vm_state_args() const {
|
||||
return make_range(vm_state_begin(), vm_state_end());
|
||||
iterator_range<arg_iterator> deopt_operands() const {
|
||||
return make_range(deopt_begin(), deopt_end());
|
||||
}
|
||||
|
||||
typename CallSiteTy::arg_iterator gc_args_begin() const {
|
||||
return vm_state_end();
|
||||
return deopt_end();
|
||||
}
|
||||
typename CallSiteTy::arg_iterator gc_args_end() const {
|
||||
return getCallSite().arg_end();
|
||||
@ -289,8 +289,8 @@ public:
|
||||
(void)arg_end();
|
||||
(void)gc_transition_args_begin();
|
||||
(void)gc_transition_args_end();
|
||||
(void)vm_state_begin();
|
||||
(void)vm_state_end();
|
||||
(void)deopt_begin();
|
||||
(void)deopt_end();
|
||||
(void)gc_args_begin();
|
||||
(void)gc_args_end();
|
||||
}
|
||||
|
@ -86,7 +86,6 @@ void initializeCFGOnlyPrinterLegacyPassPass(PassRegistry&);
|
||||
void initializeCFGOnlyViewerLegacyPassPass(PassRegistry&);
|
||||
void initializeCFGPrinterLegacyPassPass(PassRegistry&);
|
||||
void initializeCFGSimplifyPassPass(PassRegistry&);
|
||||
void initializeLateCFGSimplifyPassPass(PassRegistry&);
|
||||
void initializeCFGViewerLegacyPassPass(PassRegistry&);
|
||||
void initializeCFLAndersAAWrapperPassPass(PassRegistry&);
|
||||
void initializeCFLSteensAAWrapperPassPass(PassRegistry&);
|
||||
@ -144,8 +143,8 @@ void initializeGCMachineCodeAnalysisPass(PassRegistry&);
|
||||
void initializeGCModuleInfoPass(PassRegistry&);
|
||||
void initializeGCOVProfilerLegacyPassPass(PassRegistry&);
|
||||
void initializeGVNHoistLegacyPassPass(PassRegistry&);
|
||||
void initializeGVNSinkLegacyPassPass(PassRegistry&);
|
||||
void initializeGVNLegacyPassPass(PassRegistry&);
|
||||
void initializeGVNSinkLegacyPassPass(PassRegistry&);
|
||||
void initializeGlobalDCELegacyPassPass(PassRegistry&);
|
||||
void initializeGlobalMergePass(PassRegistry&);
|
||||
void initializeGlobalOptLegacyPassPass(PassRegistry&);
|
||||
@ -175,13 +174,14 @@ void initializeIntervalPartitionPass(PassRegistry&);
|
||||
void initializeJumpThreadingPass(PassRegistry&);
|
||||
void initializeLCSSAVerificationPassPass(PassRegistry&);
|
||||
void initializeLCSSAWrapperPassPass(PassRegistry&);
|
||||
void initializeLateCFGSimplifyPassPass(PassRegistry&);
|
||||
void initializeLazyBlockFrequencyInfoPassPass(PassRegistry&);
|
||||
void initializeLazyBranchProbabilityInfoPassPass(PassRegistry&);
|
||||
void initializeLazyMachineBlockFrequencyInfoPassPass(PassRegistry&);
|
||||
void initializeLazyValueInfoPrinterPass(PassRegistry&);
|
||||
void initializeLazyValueInfoWrapperPassPass(PassRegistry&);
|
||||
void initializeLegacyLICMPassPass(PassRegistry&);
|
||||
void initializeLegacyLoopSinkPassPass(PassRegistry&);
|
||||
void initializeLazyValueInfoPrinterPass(PassRegistry&);
|
||||
void initializeLegalizerPass(PassRegistry&);
|
||||
void initializeLibCallsShrinkWrapLegacyPassPass(PassRegistry&);
|
||||
void initializeLintPass(PassRegistry&);
|
||||
@ -195,8 +195,8 @@ void initializeLiveVariablesPass(PassRegistry&);
|
||||
void initializeLoadCombinePass(PassRegistry&);
|
||||
void initializeLoadStoreVectorizerPass(PassRegistry&);
|
||||
void initializeLoaderPassPass(PassRegistry&);
|
||||
void initializeLocalizerPass(PassRegistry&);
|
||||
void initializeLocalStackSlotPassPass(PassRegistry&);
|
||||
void initializeLocalizerPass(PassRegistry&);
|
||||
void initializeLoopAccessLegacyAnalysisPass(PassRegistry&);
|
||||
void initializeLoopDataPrefetchLegacyPassPass(PassRegistry&);
|
||||
void initializeLoopDeletionLegacyPassPass(PassRegistry&);
|
||||
@ -304,6 +304,7 @@ void initializeProcessImplicitDefsPass(PassRegistry&);
|
||||
void initializeProfileSummaryInfoWrapperPassPass(PassRegistry&);
|
||||
void initializePromoteLegacyPassPass(PassRegistry&);
|
||||
void initializePruneEHPass(PassRegistry&);
|
||||
void initializeRABasicPass(PassRegistry&);
|
||||
void initializeRAGreedyPass(PassRegistry&);
|
||||
void initializeReassociateLegacyPassPass(PassRegistry&);
|
||||
void initializeRegBankSelectPass(PassRegistry&);
|
||||
@ -327,8 +328,9 @@ void initializeSafeStackLegacyPassPass(PassRegistry&);
|
||||
void initializeSampleProfileLoaderLegacyPassPass(PassRegistry&);
|
||||
void initializeSanitizerCoverageModulePass(PassRegistry&);
|
||||
void initializeScalarEvolutionWrapperPassPass(PassRegistry&);
|
||||
void initializeScalarizerPass(PassRegistry&);
|
||||
void initializeScalarizeMaskedMemIntrinPass(PassRegistry&);
|
||||
void initializeScalarizerPass(PassRegistry&);
|
||||
void initializeScavengerTestPass(PassRegistry&);
|
||||
void initializeScopedNoAliasAAWrapperPassPass(PassRegistry&);
|
||||
void initializeSeparateConstOffsetFromGEPPass(PassRegistry&);
|
||||
void initializeShadowStackGCLoweringPass(PassRegistry&);
|
||||
|
@ -46,6 +46,9 @@ struct Config {
|
||||
unsigned OptLevel = 2;
|
||||
bool DisableVerify = false;
|
||||
|
||||
/// Use the new pass manager
|
||||
bool UseNewPM = false;
|
||||
|
||||
/// Disable entirely the optimizer, including importing for ThinLTO
|
||||
bool CodeGenOnly = false;
|
||||
|
||||
|
@ -17,12 +17,20 @@
|
||||
|
||||
#include "llvm/DebugInfo/CodeView/CodeView.h"
|
||||
#include "llvm/DebugInfo/CodeView/DebugSubsection.h"
|
||||
#include "llvm/DebugInfo/CodeView/DebugSubsectionRecord.h"
|
||||
#include "llvm/ObjectYAML/YAML.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
namespace codeview {
|
||||
class DebugStringTableSubsection;
|
||||
class DebugStringTableSubsectionRef;
|
||||
class DebugChecksumsSubsectionRef;
|
||||
}
|
||||
namespace CodeViewYAML {
|
||||
|
||||
namespace detail {
|
||||
struct C13FragmentBase;
|
||||
struct YAMLSubsectionBase;
|
||||
}
|
||||
|
||||
struct SourceLineEntry {
|
||||
@ -74,18 +82,24 @@ struct InlineeInfo {
|
||||
std::vector<InlineeSite> Sites;
|
||||
};
|
||||
|
||||
struct SourceFileInfo {
|
||||
std::vector<SourceFileChecksumEntry> FileChecksums;
|
||||
std::vector<SourceLineInfo> LineFragments;
|
||||
std::vector<InlineeInfo> Inlinees;
|
||||
struct YAMLDebugSubsection {
|
||||
static Expected<YAMLDebugSubsection>
|
||||
fromCodeViewSubection(const codeview::DebugStringTableSubsectionRef &Strings,
|
||||
const codeview::DebugChecksumsSubsectionRef &Checksums,
|
||||
const codeview::DebugSubsectionRecord &SS);
|
||||
|
||||
std::shared_ptr<detail::YAMLSubsectionBase> Subsection;
|
||||
};
|
||||
|
||||
struct C13DebugSection {
|
||||
std::vector<detail::C13FragmentBase> Fragments;
|
||||
};
|
||||
Expected<std::vector<std::unique_ptr<codeview::DebugSubsection>>>
|
||||
convertSubsectionList(ArrayRef<YAMLDebugSubsection> Subsections,
|
||||
codeview::DebugStringTableSubsection &Strings);
|
||||
|
||||
} // namespace CodeViewYAML
|
||||
} // namespace llvm
|
||||
|
||||
LLVM_YAML_DECLARE_MAPPING_TRAITS(CodeViewYAML::SourceFileInfo)
|
||||
LLVM_YAML_DECLARE_MAPPING_TRAITS(CodeViewYAML::YAMLDebugSubsection)
|
||||
|
||||
LLVM_YAML_IS_SEQUENCE_VECTOR(CodeViewYAML::YAMLDebugSubsection)
|
||||
|
||||
#endif
|
||||
|
@ -28,7 +28,9 @@ struct SymbolRecordBase;
|
||||
struct SymbolRecord {
|
||||
std::shared_ptr<detail::SymbolRecordBase> Symbol;
|
||||
|
||||
codeview::CVSymbol toCodeViewSymbol(BumpPtrAllocator &Allocator) const;
|
||||
codeview::CVSymbol
|
||||
toCodeViewSymbol(BumpPtrAllocator &Allocator,
|
||||
codeview::CodeViewContainer Container) const;
|
||||
static Expected<SymbolRecord> fromCodeViewSymbol(codeview::CVSymbol Symbol);
|
||||
};
|
||||
|
||||
|
@ -1361,10 +1361,6 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isTemplateArg(StringRef Name) const {
|
||||
return isTemplateArg(StringInit::get(Name));
|
||||
}
|
||||
|
||||
const RecordVal *getValue(const Init *Name) const {
|
||||
for (const RecordVal &Val : Values)
|
||||
if (Val.Name == Name) return &Val;
|
||||
@ -1388,10 +1384,6 @@ public:
|
||||
TemplateArgs.push_back(Name);
|
||||
}
|
||||
|
||||
void addTemplateArg(StringRef Name) {
|
||||
addTemplateArg(StringInit::get(Name));
|
||||
}
|
||||
|
||||
void addValue(const RecordVal &RV) {
|
||||
assert(getValue(RV.getNameInit()) == nullptr && "Value already added!");
|
||||
Values.push_back(RV);
|
||||
|
@ -81,15 +81,11 @@ public:
|
||||
/// \p ExportLists contains for each Module the set of globals (GUID) that will
|
||||
/// be imported by another module, or referenced by such a function. I.e. this
|
||||
/// is the set of globals that need to be promoted/renamed appropriately.
|
||||
///
|
||||
/// \p DeadSymbols (optional) contains a list of GUID that are deemed "dead" and
|
||||
/// will be ignored for the purpose of importing.
|
||||
void ComputeCrossModuleImport(
|
||||
const ModuleSummaryIndex &Index,
|
||||
const StringMap<GVSummaryMapTy> &ModuleToDefinedGVSummaries,
|
||||
StringMap<FunctionImporter::ImportMapTy> &ImportLists,
|
||||
StringMap<FunctionImporter::ExportSetTy> &ExportLists,
|
||||
const DenseSet<GlobalValue::GUID> *DeadSymbols = nullptr);
|
||||
StringMap<FunctionImporter::ExportSetTy> &ExportLists);
|
||||
|
||||
/// Compute all the imports for the given module using the Index.
|
||||
///
|
||||
@ -102,9 +98,9 @@ void ComputeCrossModuleImportForModule(
|
||||
/// Compute all the symbols that are "dead": i.e these that can't be reached
|
||||
/// in the graph from any of the given symbols listed in
|
||||
/// \p GUIDPreservedSymbols.
|
||||
DenseSet<GlobalValue::GUID>
|
||||
computeDeadSymbols(const ModuleSummaryIndex &Index,
|
||||
const DenseSet<GlobalValue::GUID> &GUIDPreservedSymbols);
|
||||
void computeDeadSymbols(
|
||||
ModuleSummaryIndex &Index,
|
||||
const DenseSet<GlobalValue::GUID> &GUIDPreservedSymbols);
|
||||
|
||||
/// Compute the set of summaries needed for a ThinLTO backend compilation of
|
||||
/// \p ModulePath.
|
||||
|
@ -177,6 +177,7 @@ struct SanitizerCoverageOptions {
|
||||
bool Use8bitCounters = false;
|
||||
bool TracePC = false;
|
||||
bool TracePCGuard = false;
|
||||
bool Inline8bitCounters = false;
|
||||
bool NoPrune = false;
|
||||
|
||||
SanitizerCoverageOptions() = default;
|
||||
|
@ -36,6 +36,7 @@ class BasicBlock;
|
||||
class BlockFrequencyInfo;
|
||||
class CallInst;
|
||||
class CallGraph;
|
||||
class DebugInfoFinder;
|
||||
class DominatorTree;
|
||||
class Function;
|
||||
class Instruction;
|
||||
@ -110,7 +111,8 @@ struct ClonedCodeInfo {
|
||||
///
|
||||
BasicBlock *CloneBasicBlock(const BasicBlock *BB, ValueToValueMapTy &VMap,
|
||||
const Twine &NameSuffix = "", Function *F = nullptr,
|
||||
ClonedCodeInfo *CodeInfo = nullptr);
|
||||
ClonedCodeInfo *CodeInfo = nullptr,
|
||||
DebugInfoFinder *DIFinder = nullptr);
|
||||
|
||||
/// CloneFunction - Return a copy of the specified function and add it to that
|
||||
/// function's module. Also, any references specified in the VMap are changed
|
||||
|
@ -1170,7 +1170,9 @@ Constant *llvm::ConstantFoldCompareInstOperands(unsigned Predicate,
|
||||
const DataLayout &DL,
|
||||
const TargetLibraryInfo *TLI) {
|
||||
// fold: icmp (inttoptr x), null -> icmp x, 0
|
||||
// fold: icmp null, (inttoptr x) -> icmp 0, x
|
||||
// fold: icmp (ptrtoint x), 0 -> icmp x, null
|
||||
// fold: icmp 0, (ptrtoint x) -> icmp null, x
|
||||
// fold: icmp (inttoptr x), (inttoptr y) -> icmp trunc/zext x, trunc/zext y
|
||||
// fold: icmp (ptrtoint x), (ptrtoint y) -> icmp x, y
|
||||
//
|
||||
@ -1240,6 +1242,11 @@ Constant *llvm::ConstantFoldCompareInstOperands(unsigned Predicate,
|
||||
Predicate == ICmpInst::ICMP_EQ ? Instruction::And : Instruction::Or;
|
||||
return ConstantFoldBinaryOpOperands(OpC, LHS, RHS, DL);
|
||||
}
|
||||
} else if (isa<ConstantExpr>(Ops1)) {
|
||||
// If RHS is a constant expression, but the left side isn't, swap the
|
||||
// operands and try again.
|
||||
Predicate = ICmpInst::getSwappedPredicate((ICmpInst::Predicate)Predicate);
|
||||
return ConstantFoldCompareInstOperands(Predicate, Ops1, Ops0, DL, TLI);
|
||||
}
|
||||
|
||||
return ConstantExpr::getCompare(Predicate, Ops0, Ops1);
|
||||
|
@ -43,7 +43,7 @@ static cl::opt<unsigned>
|
||||
// The percent threshold for the direct-call target (this call site vs the
|
||||
// total call count) for it to be considered as the promotion target.
|
||||
static cl::opt<unsigned>
|
||||
ICPPercentThreshold("icp-percent-threshold", cl::init(33), cl::Hidden,
|
||||
ICPPercentThreshold("icp-percent-threshold", cl::init(30), cl::Hidden,
|
||||
cl::ZeroOrMore,
|
||||
cl::desc("The percentage threshold for the promotion"));
|
||||
|
||||
|
@ -54,11 +54,6 @@ static cl::opt<int>
|
||||
cl::init(45),
|
||||
cl::desc("Threshold for inlining cold callsites"));
|
||||
|
||||
static cl::opt<bool>
|
||||
EnableGenericSwitchCost("inline-generic-switch-cost", cl::Hidden,
|
||||
cl::init(false),
|
||||
cl::desc("Enable generic switch cost model"));
|
||||
|
||||
// We introduce this threshold to help performance of instrumentation based
|
||||
// PGO before we actually hook up inliner with analysis passes such as BPI and
|
||||
// BFI.
|
||||
@ -1015,83 +1010,68 @@ bool CallAnalyzer::visitSwitchInst(SwitchInst &SI) {
|
||||
if (isa<ConstantInt>(V))
|
||||
return true;
|
||||
|
||||
if (EnableGenericSwitchCost) {
|
||||
// Assume the most general case where the swith is lowered into
|
||||
// either a jump table, bit test, or a balanced binary tree consisting of
|
||||
// case clusters without merging adjacent clusters with the same
|
||||
// destination. We do not consider the switches that are lowered with a mix
|
||||
// of jump table/bit test/binary search tree. The cost of the switch is
|
||||
// proportional to the size of the tree or the size of jump table range.
|
||||
|
||||
// Exit early for a large switch, assuming one case needs at least one
|
||||
// instruction.
|
||||
// FIXME: This is not true for a bit test, but ignore such case for now to
|
||||
// save compile-time.
|
||||
int64_t CostLowerBound =
|
||||
std::min((int64_t)INT_MAX,
|
||||
(int64_t)SI.getNumCases() * InlineConstants::InstrCost + Cost);
|
||||
|
||||
if (CostLowerBound > Threshold) {
|
||||
Cost = CostLowerBound;
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned JumpTableSize = 0;
|
||||
unsigned NumCaseCluster =
|
||||
TTI.getEstimatedNumberOfCaseClusters(SI, JumpTableSize);
|
||||
|
||||
// If suitable for a jump table, consider the cost for the table size and
|
||||
// branch to destination.
|
||||
if (JumpTableSize) {
|
||||
int64_t JTCost = (int64_t)JumpTableSize * InlineConstants::InstrCost +
|
||||
4 * InlineConstants::InstrCost;
|
||||
Cost = std::min((int64_t)INT_MAX, JTCost + Cost);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Considering forming a binary search, we should find the number of nodes
|
||||
// which is same as the number of comparisons when lowered. For a given
|
||||
// number of clusters, n, we can define a recursive function, f(n), to find
|
||||
// the number of nodes in the tree. The recursion is :
|
||||
// f(n) = 1 + f(n/2) + f (n - n/2), when n > 3,
|
||||
// and f(n) = n, when n <= 3.
|
||||
// This will lead a binary tree where the leaf should be either f(2) or f(3)
|
||||
// when n > 3. So, the number of comparisons from leaves should be n, while
|
||||
// the number of non-leaf should be :
|
||||
// 2^(log2(n) - 1) - 1
|
||||
// = 2^log2(n) * 2^-1 - 1
|
||||
// = n / 2 - 1.
|
||||
// Considering comparisons from leaf and non-leaf nodes, we can estimate the
|
||||
// number of comparisons in a simple closed form :
|
||||
// n + n / 2 - 1 = n * 3 / 2 - 1
|
||||
if (NumCaseCluster <= 3) {
|
||||
// Suppose a comparison includes one compare and one conditional branch.
|
||||
Cost += NumCaseCluster * 2 * InlineConstants::InstrCost;
|
||||
return false;
|
||||
}
|
||||
int64_t ExpectedNumberOfCompare = 3 * (uint64_t)NumCaseCluster / 2 - 1;
|
||||
uint64_t SwitchCost =
|
||||
ExpectedNumberOfCompare * 2 * InlineConstants::InstrCost;
|
||||
Cost = std::min((uint64_t)INT_MAX, SwitchCost + Cost);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Use a simple switch cost model where we accumulate a cost proportional to
|
||||
// the number of distinct successor blocks. This fan-out in the CFG cannot
|
||||
// be represented for free even if we can represent the core switch as a
|
||||
// jumptable that takes a single instruction.
|
||||
///
|
||||
// Assume the most general case where the swith is lowered into
|
||||
// either a jump table, bit test, or a balanced binary tree consisting of
|
||||
// case clusters without merging adjacent clusters with the same
|
||||
// destination. We do not consider the switches that are lowered with a mix
|
||||
// of jump table/bit test/binary search tree. The cost of the switch is
|
||||
// proportional to the size of the tree or the size of jump table range.
|
||||
//
|
||||
// NB: We convert large switches which are just used to initialize large phi
|
||||
// nodes to lookup tables instead in simplify-cfg, so this shouldn't prevent
|
||||
// inlining those. It will prevent inlining in cases where the optimization
|
||||
// does not (yet) fire.
|
||||
SmallPtrSet<BasicBlock *, 8> SuccessorBlocks;
|
||||
SuccessorBlocks.insert(SI.getDefaultDest());
|
||||
for (auto Case : SI.cases())
|
||||
SuccessorBlocks.insert(Case.getCaseSuccessor());
|
||||
// Add cost corresponding to the number of distinct destinations. The first
|
||||
// we model as free because of fallthrough.
|
||||
Cost += (SuccessorBlocks.size() - 1) * InlineConstants::InstrCost;
|
||||
|
||||
// Exit early for a large switch, assuming one case needs at least one
|
||||
// instruction.
|
||||
// FIXME: This is not true for a bit test, but ignore such case for now to
|
||||
// save compile-time.
|
||||
int64_t CostLowerBound =
|
||||
std::min((int64_t)INT_MAX,
|
||||
(int64_t)SI.getNumCases() * InlineConstants::InstrCost + Cost);
|
||||
|
||||
if (CostLowerBound > Threshold) {
|
||||
Cost = CostLowerBound;
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned JumpTableSize = 0;
|
||||
unsigned NumCaseCluster =
|
||||
TTI.getEstimatedNumberOfCaseClusters(SI, JumpTableSize);
|
||||
|
||||
// If suitable for a jump table, consider the cost for the table size and
|
||||
// branch to destination.
|
||||
if (JumpTableSize) {
|
||||
int64_t JTCost = (int64_t)JumpTableSize * InlineConstants::InstrCost +
|
||||
4 * InlineConstants::InstrCost;
|
||||
Cost = std::min((int64_t)INT_MAX, JTCost + Cost);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Considering forming a binary search, we should find the number of nodes
|
||||
// which is same as the number of comparisons when lowered. For a given
|
||||
// number of clusters, n, we can define a recursive function, f(n), to find
|
||||
// the number of nodes in the tree. The recursion is :
|
||||
// f(n) = 1 + f(n/2) + f (n - n/2), when n > 3,
|
||||
// and f(n) = n, when n <= 3.
|
||||
// This will lead a binary tree where the leaf should be either f(2) or f(3)
|
||||
// when n > 3. So, the number of comparisons from leaves should be n, while
|
||||
// the number of non-leaf should be :
|
||||
// 2^(log2(n) - 1) - 1
|
||||
// = 2^log2(n) * 2^-1 - 1
|
||||
// = n / 2 - 1.
|
||||
// Considering comparisons from leaf and non-leaf nodes, we can estimate the
|
||||
// number of comparisons in a simple closed form :
|
||||
// n + n / 2 - 1 = n * 3 / 2 - 1
|
||||
if (NumCaseCluster <= 3) {
|
||||
// Suppose a comparison includes one compare and one conditional branch.
|
||||
Cost += NumCaseCluster * 2 * InlineConstants::InstrCost;
|
||||
return false;
|
||||
}
|
||||
int64_t ExpectedNumberOfCompare = 3 * (uint64_t)NumCaseCluster / 2 - 1;
|
||||
uint64_t SwitchCost =
|
||||
ExpectedNumberOfCompare * 2 * InlineConstants::InstrCost;
|
||||
Cost = std::min((uint64_t)INT_MAX, SwitchCost + Cost);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -662,13 +662,13 @@ namespace {
|
||||
bool solveBlockValuePHINode(LVILatticeVal &BBLV, PHINode *PN, BasicBlock *BB);
|
||||
bool solveBlockValueSelect(LVILatticeVal &BBLV, SelectInst *S,
|
||||
BasicBlock *BB);
|
||||
bool solveBlockValueBinaryOp(LVILatticeVal &BBLV, Instruction *BBI,
|
||||
bool solveBlockValueBinaryOp(LVILatticeVal &BBLV, BinaryOperator *BBI,
|
||||
BasicBlock *BB);
|
||||
bool solveBlockValueCast(LVILatticeVal &BBLV, Instruction *BBI,
|
||||
bool solveBlockValueCast(LVILatticeVal &BBLV, CastInst *CI,
|
||||
BasicBlock *BB);
|
||||
void intersectAssumeOrGuardBlockValueConstantRange(Value *Val,
|
||||
LVILatticeVal &BBLV,
|
||||
Instruction *BBI);
|
||||
Instruction *BBI);
|
||||
|
||||
void solve();
|
||||
|
||||
@ -849,12 +849,12 @@ bool LazyValueInfoImpl::solveBlockValueImpl(LVILatticeVal &Res,
|
||||
return true;
|
||||
}
|
||||
if (BBI->getType()->isIntegerTy()) {
|
||||
if (isa<CastInst>(BBI))
|
||||
return solveBlockValueCast(Res, BBI, BB);
|
||||
|
||||
if (auto *CI = dyn_cast<CastInst>(BBI))
|
||||
return solveBlockValueCast(Res, CI, BB);
|
||||
|
||||
BinaryOperator *BO = dyn_cast<BinaryOperator>(BBI);
|
||||
if (BO && isa<ConstantInt>(BO->getOperand(1)))
|
||||
return solveBlockValueBinaryOp(Res, BBI, BB);
|
||||
return solveBlockValueBinaryOp(Res, BO, BB);
|
||||
}
|
||||
|
||||
DEBUG(dbgs() << " compute BB '" << BB->getName()
|
||||
@ -1168,9 +1168,9 @@ bool LazyValueInfoImpl::solveBlockValueSelect(LVILatticeVal &BBLV,
|
||||
}
|
||||
|
||||
bool LazyValueInfoImpl::solveBlockValueCast(LVILatticeVal &BBLV,
|
||||
Instruction *BBI,
|
||||
BasicBlock *BB) {
|
||||
if (!BBI->getOperand(0)->getType()->isSized()) {
|
||||
CastInst *CI,
|
||||
BasicBlock *BB) {
|
||||
if (!CI->getOperand(0)->getType()->isSized()) {
|
||||
// Without knowing how wide the input is, we can't analyze it in any useful
|
||||
// way.
|
||||
BBLV = LVILatticeVal::getOverdefined();
|
||||
@ -1180,7 +1180,7 @@ bool LazyValueInfoImpl::solveBlockValueCast(LVILatticeVal &BBLV,
|
||||
// Filter out casts we don't know how to reason about before attempting to
|
||||
// recurse on our operand. This can cut a long search short if we know we're
|
||||
// not going to be able to get any useful information anways.
|
||||
switch (BBI->getOpcode()) {
|
||||
switch (CI->getOpcode()) {
|
||||
case Instruction::Trunc:
|
||||
case Instruction::SExt:
|
||||
case Instruction::ZExt:
|
||||
@ -1197,44 +1197,43 @@ bool LazyValueInfoImpl::solveBlockValueCast(LVILatticeVal &BBLV,
|
||||
// Figure out the range of the LHS. If that fails, we still apply the
|
||||
// transfer rule on the full set since we may be able to locally infer
|
||||
// interesting facts.
|
||||
if (!hasBlockValue(BBI->getOperand(0), BB))
|
||||
if (pushBlockValue(std::make_pair(BB, BBI->getOperand(0))))
|
||||
if (!hasBlockValue(CI->getOperand(0), BB))
|
||||
if (pushBlockValue(std::make_pair(BB, CI->getOperand(0))))
|
||||
// More work to do before applying this transfer rule.
|
||||
return false;
|
||||
|
||||
const unsigned OperandBitWidth =
|
||||
DL.getTypeSizeInBits(BBI->getOperand(0)->getType());
|
||||
DL.getTypeSizeInBits(CI->getOperand(0)->getType());
|
||||
ConstantRange LHSRange = ConstantRange(OperandBitWidth);
|
||||
if (hasBlockValue(BBI->getOperand(0), BB)) {
|
||||
LVILatticeVal LHSVal = getBlockValue(BBI->getOperand(0), BB);
|
||||
intersectAssumeOrGuardBlockValueConstantRange(BBI->getOperand(0), LHSVal,
|
||||
BBI);
|
||||
if (hasBlockValue(CI->getOperand(0), BB)) {
|
||||
LVILatticeVal LHSVal = getBlockValue(CI->getOperand(0), BB);
|
||||
intersectAssumeOrGuardBlockValueConstantRange(CI->getOperand(0), LHSVal,
|
||||
CI);
|
||||
if (LHSVal.isConstantRange())
|
||||
LHSRange = LHSVal.getConstantRange();
|
||||
}
|
||||
|
||||
const unsigned ResultBitWidth =
|
||||
cast<IntegerType>(BBI->getType())->getBitWidth();
|
||||
const unsigned ResultBitWidth = CI->getType()->getIntegerBitWidth();
|
||||
|
||||
// NOTE: We're currently limited by the set of operations that ConstantRange
|
||||
// can evaluate symbolically. Enhancing that set will allows us to analyze
|
||||
// more definitions.
|
||||
auto CastOp = (Instruction::CastOps) BBI->getOpcode();
|
||||
BBLV = LVILatticeVal::getRange(LHSRange.castOp(CastOp, ResultBitWidth));
|
||||
BBLV = LVILatticeVal::getRange(LHSRange.castOp(CI->getOpcode(),
|
||||
ResultBitWidth));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LazyValueInfoImpl::solveBlockValueBinaryOp(LVILatticeVal &BBLV,
|
||||
Instruction *BBI,
|
||||
BinaryOperator *BO,
|
||||
BasicBlock *BB) {
|
||||
|
||||
assert(BBI->getOperand(0)->getType()->isSized() &&
|
||||
assert(BO->getOperand(0)->getType()->isSized() &&
|
||||
"all operands to binary operators are sized");
|
||||
|
||||
// Filter out operators we don't know how to reason about before attempting to
|
||||
// recurse on our operand(s). This can cut a long search short if we know
|
||||
// we're not going to be able to get any useful information anways.
|
||||
switch (BBI->getOpcode()) {
|
||||
// we're not going to be able to get any useful information anyways.
|
||||
switch (BO->getOpcode()) {
|
||||
case Instruction::Add:
|
||||
case Instruction::Sub:
|
||||
case Instruction::Mul:
|
||||
@ -1256,29 +1255,29 @@ bool LazyValueInfoImpl::solveBlockValueBinaryOp(LVILatticeVal &BBLV,
|
||||
// Figure out the range of the LHS. If that fails, use a conservative range,
|
||||
// but apply the transfer rule anyways. This lets us pick up facts from
|
||||
// expressions like "and i32 (call i32 @foo()), 32"
|
||||
if (!hasBlockValue(BBI->getOperand(0), BB))
|
||||
if (pushBlockValue(std::make_pair(BB, BBI->getOperand(0))))
|
||||
if (!hasBlockValue(BO->getOperand(0), BB))
|
||||
if (pushBlockValue(std::make_pair(BB, BO->getOperand(0))))
|
||||
// More work to do before applying this transfer rule.
|
||||
return false;
|
||||
|
||||
const unsigned OperandBitWidth =
|
||||
DL.getTypeSizeInBits(BBI->getOperand(0)->getType());
|
||||
DL.getTypeSizeInBits(BO->getOperand(0)->getType());
|
||||
ConstantRange LHSRange = ConstantRange(OperandBitWidth);
|
||||
if (hasBlockValue(BBI->getOperand(0), BB)) {
|
||||
LVILatticeVal LHSVal = getBlockValue(BBI->getOperand(0), BB);
|
||||
intersectAssumeOrGuardBlockValueConstantRange(BBI->getOperand(0), LHSVal,
|
||||
BBI);
|
||||
if (hasBlockValue(BO->getOperand(0), BB)) {
|
||||
LVILatticeVal LHSVal = getBlockValue(BO->getOperand(0), BB);
|
||||
intersectAssumeOrGuardBlockValueConstantRange(BO->getOperand(0), LHSVal,
|
||||
BO);
|
||||
if (LHSVal.isConstantRange())
|
||||
LHSRange = LHSVal.getConstantRange();
|
||||
}
|
||||
|
||||
ConstantInt *RHS = cast<ConstantInt>(BBI->getOperand(1));
|
||||
ConstantInt *RHS = cast<ConstantInt>(BO->getOperand(1));
|
||||
ConstantRange RHSRange = ConstantRange(RHS->getValue());
|
||||
|
||||
// NOTE: We're currently limited by the set of operations that ConstantRange
|
||||
// can evaluate symbolically. Enhancing that set will allows us to analyze
|
||||
// more definitions.
|
||||
auto BinOp = (Instruction::BinaryOps) BBI->getOpcode();
|
||||
Instruction::BinaryOps BinOp = BO->getOpcode();
|
||||
BBLV = LVILatticeVal::getRange(LHSRange.binaryOp(BinOp, RHSRange));
|
||||
return true;
|
||||
}
|
||||
|
@ -275,7 +275,7 @@ computeFunctionSummary(ModuleSummaryIndex &Index, const Module &M,
|
||||
// FIXME: refactor this to use the same code that inliner is using.
|
||||
F.isVarArg();
|
||||
GlobalValueSummary::GVFlags Flags(F.getLinkage(), NotEligibleForImport,
|
||||
/* LiveRoot = */ false);
|
||||
/* Live = */ false);
|
||||
auto FuncSummary = llvm::make_unique<FunctionSummary>(
|
||||
Flags, NumInsts, RefEdges.takeVector(), CallGraphEdges.takeVector(),
|
||||
TypeTests.takeVector(), TypeTestAssumeVCalls.takeVector(),
|
||||
@ -295,7 +295,7 @@ computeVariableSummary(ModuleSummaryIndex &Index, const GlobalVariable &V,
|
||||
findRefEdges(Index, &V, RefEdges, Visited);
|
||||
bool NonRenamableLocal = isNonRenamableLocal(V);
|
||||
GlobalValueSummary::GVFlags Flags(V.getLinkage(), NonRenamableLocal,
|
||||
/* LiveRoot = */ false);
|
||||
/* Live = */ false);
|
||||
auto GVarSummary =
|
||||
llvm::make_unique<GlobalVarSummary>(Flags, RefEdges.takeVector());
|
||||
if (NonRenamableLocal)
|
||||
@ -308,7 +308,7 @@ computeAliasSummary(ModuleSummaryIndex &Index, const GlobalAlias &A,
|
||||
DenseSet<GlobalValue::GUID> &CantBePromoted) {
|
||||
bool NonRenamableLocal = isNonRenamableLocal(A);
|
||||
GlobalValueSummary::GVFlags Flags(A.getLinkage(), NonRenamableLocal,
|
||||
/* LiveRoot = */ false);
|
||||
/* Live = */ false);
|
||||
auto AS = llvm::make_unique<AliasSummary>(Flags, ArrayRef<ValueInfo>{});
|
||||
auto *Aliasee = A.getBaseObject();
|
||||
auto *AliaseeSummary = Index.getGlobalValueSummary(*Aliasee);
|
||||
@ -323,7 +323,7 @@ computeAliasSummary(ModuleSummaryIndex &Index, const GlobalAlias &A,
|
||||
static void setLiveRoot(ModuleSummaryIndex &Index, StringRef Name) {
|
||||
if (ValueInfo VI = Index.getValueInfo(GlobalValue::getGUID(Name)))
|
||||
for (auto &Summary : VI.getSummaryList())
|
||||
Summary->setLiveRoot();
|
||||
Summary->setLive(true);
|
||||
}
|
||||
|
||||
ModuleSummaryIndex llvm::buildModuleSummaryIndex(
|
||||
@ -423,8 +423,8 @@ ModuleSummaryIndex llvm::buildModuleSummaryIndex(
|
||||
return;
|
||||
assert(GV->isDeclaration() && "Def in module asm already has definition");
|
||||
GlobalValueSummary::GVFlags GVFlags(GlobalValue::InternalLinkage,
|
||||
/* NotEligibleToImport */ true,
|
||||
/* LiveRoot */ true);
|
||||
/* NotEligibleToImport = */ true,
|
||||
/* Live = */ true);
|
||||
CantBePromoted.insert(GlobalValue::getGUID(Name));
|
||||
// Create the appropriate summary type.
|
||||
if (isa<Function>(GV)) {
|
||||
|
@ -55,7 +55,7 @@ bool OrderedBasicBlock::comesBefore(const Instruction *A,
|
||||
assert(II != IE && "Instruction not found?");
|
||||
assert((Inst == A || Inst == B) && "Should find A or B");
|
||||
LastInstFound = II;
|
||||
return Inst == A;
|
||||
return Inst != B;
|
||||
}
|
||||
|
||||
/// \brief Find out whether \p A dominates \p B, meaning whether \p A
|
||||
|
@ -15,6 +15,7 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
#include "llvm/Analysis/RegionPass.h"
|
||||
#include "llvm/Analysis/RegionIterator.h"
|
||||
#include "llvm/IR/OptBisect.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/Timer.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
@ -280,3 +281,18 @@ Pass *RegionPass::createPrinterPass(raw_ostream &O,
|
||||
const std::string &Banner) const {
|
||||
return new PrintRegionPass(Banner, O);
|
||||
}
|
||||
|
||||
bool RegionPass::skipRegion(Region &R) const {
|
||||
Function &F = *R.getEntry()->getParent();
|
||||
if (!F.getContext().getOptBisect().shouldRunPass(this, R))
|
||||
return true;
|
||||
|
||||
if (F.hasFnAttribute(Attribute::OptimizeNone)) {
|
||||
// Report this only once per function.
|
||||
if (R.getEntry() == &F.getEntryBlock())
|
||||
DEBUG(dbgs() << "Skipping pass '" << getPassName()
|
||||
<< "' on function " << F.getName() << "\n");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -865,11 +865,11 @@ static GlobalValueSummary::GVFlags getDecodedGVSummaryFlags(uint64_t RawFlags,
|
||||
auto Linkage = GlobalValue::LinkageTypes(RawFlags & 0xF); // 4 bits
|
||||
RawFlags = RawFlags >> 4;
|
||||
bool NotEligibleToImport = (RawFlags & 0x1) || Version < 3;
|
||||
// The LiveRoot flag wasn't introduced until version 3. For dead stripping
|
||||
// The Live flag wasn't introduced until version 3. For dead stripping
|
||||
// to work correctly on earlier versions, we must conservatively treat all
|
||||
// values as live.
|
||||
bool LiveRoot = (RawFlags & 0x2) || Version < 3;
|
||||
return GlobalValueSummary::GVFlags(Linkage, NotEligibleToImport, LiveRoot);
|
||||
bool Live = (RawFlags & 0x2) || Version < 3;
|
||||
return GlobalValueSummary::GVFlags(Linkage, NotEligibleToImport, Live);
|
||||
}
|
||||
|
||||
static GlobalValue::VisibilityTypes getDecodedVisibility(unsigned Val) {
|
||||
|
@ -351,7 +351,8 @@ public:
|
||||
/// Calls the callback for each value GUID and summary to be written to
|
||||
/// bitcode. This hides the details of whether they are being pulled from the
|
||||
/// entire index or just those in a provided ModuleToSummariesForIndex map.
|
||||
void forEachSummary(std::function<void(GVInfo)> Callback) {
|
||||
template<typename Functor>
|
||||
void forEachSummary(Functor Callback) {
|
||||
if (ModuleToSummariesForIndex) {
|
||||
for (auto &M : *ModuleToSummariesForIndex)
|
||||
for (auto &Summary : M.second)
|
||||
@ -363,6 +364,29 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
/// Calls the callback for each entry in the modulePaths StringMap that
|
||||
/// should be written to the module path string table. This hides the details
|
||||
/// of whether they are being pulled from the entire index or just those in a
|
||||
/// provided ModuleToSummariesForIndex map.
|
||||
template <typename Functor> void forEachModule(Functor Callback) {
|
||||
if (ModuleToSummariesForIndex) {
|
||||
for (const auto &M : *ModuleToSummariesForIndex) {
|
||||
const auto &MPI = Index.modulePaths().find(M.first);
|
||||
if (MPI == Index.modulePaths().end()) {
|
||||
// This should only happen if the bitcode file was empty, in which
|
||||
// case we shouldn't be importing (the ModuleToSummariesForIndex
|
||||
// would only include the module we are writing and index for).
|
||||
assert(ModuleToSummariesForIndex->size() == 1);
|
||||
continue;
|
||||
}
|
||||
Callback(*MPI);
|
||||
}
|
||||
} else {
|
||||
for (const auto &MPSE : Index.modulePaths())
|
||||
Callback(MPSE);
|
||||
}
|
||||
}
|
||||
|
||||
/// Main entry point for writing a combined index to bitcode.
|
||||
void write();
|
||||
|
||||
@ -370,14 +394,6 @@ private:
|
||||
void writeModStrings();
|
||||
void writeCombinedGlobalValueSummary();
|
||||
|
||||
/// Indicates whether the provided \p ModulePath should be written into
|
||||
/// the module string table, e.g. if full index written or if it is in
|
||||
/// the provided subset.
|
||||
bool doIncludeModule(StringRef ModulePath) {
|
||||
return !ModuleToSummariesForIndex ||
|
||||
ModuleToSummariesForIndex->count(ModulePath);
|
||||
}
|
||||
|
||||
Optional<unsigned> getValueId(GlobalValue::GUID ValGUID) {
|
||||
auto VMI = GUIDToValueIdMap.find(ValGUID);
|
||||
if (VMI == GUIDToValueIdMap.end())
|
||||
@ -864,7 +880,7 @@ static uint64_t getEncodedGVSummaryFlags(GlobalValueSummary::GVFlags Flags) {
|
||||
uint64_t RawFlags = 0;
|
||||
|
||||
RawFlags |= Flags.NotEligibleToImport; // bool
|
||||
RawFlags |= (Flags.LiveRoot << 1);
|
||||
RawFlags |= (Flags.Live << 1);
|
||||
// Linkage don't need to be remapped at that time for the summary. Any future
|
||||
// change to the getEncodedLinkage() function will need to be taken into
|
||||
// account here as well.
|
||||
@ -968,19 +984,18 @@ void ModuleBitcodeWriter::writeValueSymbolTableForwardDecl() {
|
||||
enum StringEncoding { SE_Char6, SE_Fixed7, SE_Fixed8 };
|
||||
|
||||
/// Determine the encoding to use for the given string name and length.
|
||||
static StringEncoding getStringEncoding(const char *Str, unsigned StrLen) {
|
||||
static StringEncoding getStringEncoding(StringRef Str) {
|
||||
bool isChar6 = true;
|
||||
for (const char *C = Str, *E = C + StrLen; C != E; ++C) {
|
||||
for (char C : Str) {
|
||||
if (isChar6)
|
||||
isChar6 = BitCodeAbbrevOp::isChar6(*C);
|
||||
if ((unsigned char)*C & 128)
|
||||
isChar6 = BitCodeAbbrevOp::isChar6(C);
|
||||
if ((unsigned char)C & 128)
|
||||
// don't bother scanning the rest.
|
||||
return SE_Fixed8;
|
||||
}
|
||||
if (isChar6)
|
||||
return SE_Char6;
|
||||
else
|
||||
return SE_Fixed7;
|
||||
return SE_Fixed7;
|
||||
}
|
||||
|
||||
/// Emit top-level description of module, including target triple, inline asm,
|
||||
@ -1073,8 +1088,7 @@ void ModuleBitcodeWriter::writeModuleInfo() {
|
||||
SmallVector<unsigned, 64> Vals;
|
||||
// Emit the module's source file name.
|
||||
{
|
||||
StringEncoding Bits = getStringEncoding(M.getSourceFileName().data(),
|
||||
M.getSourceFileName().size());
|
||||
StringEncoding Bits = getStringEncoding(M.getSourceFileName());
|
||||
BitCodeAbbrevOp AbbrevOpToUse = BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 8);
|
||||
if (Bits == SE_Char6)
|
||||
AbbrevOpToUse = BitCodeAbbrevOp(BitCodeAbbrevOp::Char6);
|
||||
@ -2790,8 +2804,7 @@ void ModuleBitcodeWriter::writeFunctionLevelValueSymbolTable(
|
||||
|
||||
for (const ValueName &Name : VST) {
|
||||
// Figure out the encoding to use for the name.
|
||||
StringEncoding Bits =
|
||||
getStringEncoding(Name.getKeyData(), Name.getKeyLength());
|
||||
StringEncoding Bits = getStringEncoding(Name.getKey());
|
||||
|
||||
unsigned AbbrevToUse = VST_ENTRY_8_ABBREV;
|
||||
NameVals.push_back(VE.getValueID(Name.getValue()));
|
||||
@ -3149,41 +3162,33 @@ void IndexBitcodeWriter::writeModStrings() {
|
||||
unsigned AbbrevHash = Stream.EmitAbbrev(std::move(Abbv));
|
||||
|
||||
SmallVector<unsigned, 64> Vals;
|
||||
for (const auto &MPSE : Index.modulePaths()) {
|
||||
if (!doIncludeModule(MPSE.getKey()))
|
||||
continue;
|
||||
StringEncoding Bits =
|
||||
getStringEncoding(MPSE.getKey().data(), MPSE.getKey().size());
|
||||
unsigned AbbrevToUse = Abbrev8Bit;
|
||||
if (Bits == SE_Char6)
|
||||
AbbrevToUse = Abbrev6Bit;
|
||||
else if (Bits == SE_Fixed7)
|
||||
AbbrevToUse = Abbrev7Bit;
|
||||
forEachModule(
|
||||
[&](const StringMapEntry<std::pair<uint64_t, ModuleHash>> &MPSE) {
|
||||
StringRef Key = MPSE.getKey();
|
||||
const auto &Value = MPSE.getValue();
|
||||
StringEncoding Bits = getStringEncoding(Key);
|
||||
unsigned AbbrevToUse = Abbrev8Bit;
|
||||
if (Bits == SE_Char6)
|
||||
AbbrevToUse = Abbrev6Bit;
|
||||
else if (Bits == SE_Fixed7)
|
||||
AbbrevToUse = Abbrev7Bit;
|
||||
|
||||
Vals.push_back(MPSE.getValue().first);
|
||||
Vals.push_back(Value.first);
|
||||
Vals.append(Key.begin(), Key.end());
|
||||
|
||||
for (const auto P : MPSE.getKey())
|
||||
Vals.push_back((unsigned char)P);
|
||||
// Emit the finished record.
|
||||
Stream.EmitRecord(bitc::MST_CODE_ENTRY, Vals, AbbrevToUse);
|
||||
|
||||
// Emit the finished record.
|
||||
Stream.EmitRecord(bitc::MST_CODE_ENTRY, Vals, AbbrevToUse);
|
||||
// Emit an optional hash for the module now
|
||||
const auto &Hash = Value.second;
|
||||
if (llvm::any_of(Hash, [](uint32_t H) { return H; })) {
|
||||
Vals.assign(Hash.begin(), Hash.end());
|
||||
// Emit the hash record.
|
||||
Stream.EmitRecord(bitc::MST_CODE_HASH, Vals, AbbrevHash);
|
||||
}
|
||||
|
||||
Vals.clear();
|
||||
// Emit an optional hash for the module now
|
||||
auto &Hash = MPSE.getValue().second;
|
||||
bool AllZero = true; // Detect if the hash is empty, and do not generate it
|
||||
for (auto Val : Hash) {
|
||||
if (Val)
|
||||
AllZero = false;
|
||||
Vals.push_back(Val);
|
||||
}
|
||||
if (!AllZero) {
|
||||
// Emit the hash record.
|
||||
Stream.EmitRecord(bitc::MST_CODE_HASH, Vals, AbbrevHash);
|
||||
}
|
||||
|
||||
Vals.clear();
|
||||
}
|
||||
Vals.clear();
|
||||
});
|
||||
Stream.ExitBlock();
|
||||
}
|
||||
|
||||
|
@ -194,6 +194,10 @@ void llvm::calculateDbgValueHistory(const MachineFunction *MF,
|
||||
// some variables.
|
||||
for (const MachineOperand &MO : MI.operands()) {
|
||||
if (MO.isReg() && MO.isDef() && MO.getReg()) {
|
||||
// Ignore call instructions that claim to clobber SP. The AArch64
|
||||
// backend does this for aggregate function arguments.
|
||||
if (MI.isCall() && MO.getReg() == SP)
|
||||
continue;
|
||||
// If this is a virtual register, only clobber it since it doesn't
|
||||
// have aliases.
|
||||
if (TRI->isVirtualRegister(MO.getReg()))
|
||||
|
@ -77,6 +77,7 @@ void llvm::initializeCodeGen(PassRegistry &Registry) {
|
||||
initializePostRASchedulerPass(Registry);
|
||||
initializePreISelIntrinsicLoweringLegacyPassPass(Registry);
|
||||
initializeProcessImplicitDefsPass(Registry);
|
||||
initializeRABasicPass(Registry);
|
||||
initializeRAGreedyPass(Registry);
|
||||
initializeRegisterCoalescerPass(Registry);
|
||||
initializeRenameIndependentSubregsPass(Registry);
|
||||
|
@ -556,6 +556,10 @@ bool GlobalMerge::doInitialization(Module &M) {
|
||||
if (GV.isDeclaration() || GV.isThreadLocal() || GV.hasSection())
|
||||
continue;
|
||||
|
||||
// It's not safe to merge globals that may be preempted
|
||||
if (TM && !TM->shouldAssumeDSOLocal(M, &GV))
|
||||
continue;
|
||||
|
||||
if (!(MergeExternalGlobals && GV.hasExternalLinkage()) &&
|
||||
!GV.hasInternalLinkage())
|
||||
continue;
|
||||
|
@ -198,13 +198,12 @@ void LivePhysRegs::addLiveOutsNoPristines(const MachineBasicBlock &MBB) {
|
||||
}
|
||||
|
||||
void LivePhysRegs::addLiveOuts(const MachineBasicBlock &MBB) {
|
||||
const MachineFunction &MF = *MBB.getParent();
|
||||
if (!MBB.succ_empty()) {
|
||||
const MachineFunction &MF = *MBB.getParent();
|
||||
addPristines(*this, MF);
|
||||
addLiveOutsNoPristines(MBB);
|
||||
} else if (MBB.isReturnBlock()) {
|
||||
// For the return block: Add all callee saved registers.
|
||||
const MachineFunction &MF = *MBB.getParent();
|
||||
const MachineFrameInfo &MFI = MF.getFrameInfo();
|
||||
if (MFI.isCalleeSavedInfoValid())
|
||||
addCalleeSavedRegs(*this, MF);
|
||||
|
@ -12,11 +12,13 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/CodeGen/LiveRegUnits.h"
|
||||
|
||||
#include "llvm/CodeGen/MachineBasicBlock.h"
|
||||
#include "llvm/CodeGen/MachineFrameInfo.h"
|
||||
#include "llvm/CodeGen/MachineFunction.h"
|
||||
#include "llvm/CodeGen/MachineInstrBundle.h"
|
||||
#include "llvm/CodeGen/MachineOperand.h"
|
||||
#include "llvm/CodeGen/MachineRegisterInfo.h"
|
||||
#include "llvm/MC/MCRegisterInfo.h"
|
||||
#include "llvm/Target/TargetRegisterInfo.h"
|
||||
|
||||
@ -81,46 +83,50 @@ void LiveRegUnits::accumulateBackward(const MachineInstr &MI) {
|
||||
}
|
||||
|
||||
/// Add live-in registers of basic block \p MBB to \p LiveUnits.
|
||||
static void addLiveIns(LiveRegUnits &LiveUnits, const MachineBasicBlock &MBB) {
|
||||
static void addBlockLiveIns(LiveRegUnits &LiveUnits,
|
||||
const MachineBasicBlock &MBB) {
|
||||
for (const auto &LI : MBB.liveins())
|
||||
LiveUnits.addRegMasked(LI.PhysReg, LI.LaneMask);
|
||||
}
|
||||
|
||||
static void addLiveOuts(LiveRegUnits &LiveUnits, const MachineBasicBlock &MBB) {
|
||||
// To get the live-outs we simply merge the live-ins of all successors.
|
||||
for (const MachineBasicBlock *Succ : MBB.successors())
|
||||
addLiveIns(LiveUnits, *Succ);
|
||||
/// Adds all callee saved registers to \p LiveUnits.
|
||||
static void addCalleeSavedRegs(LiveRegUnits &LiveUnits,
|
||||
const MachineFunction &MF) {
|
||||
const MachineRegisterInfo &MRI = MF.getRegInfo();
|
||||
for (const MCPhysReg *CSR = MRI.getCalleeSavedRegs(); CSR && *CSR; ++CSR)
|
||||
LiveUnits.addReg(*CSR);
|
||||
}
|
||||
|
||||
/// Add pristine registers to the given \p LiveUnits. This function removes
|
||||
/// actually saved callee save registers when \p InPrologueEpilogue is false.
|
||||
static void removeSavedRegs(LiveRegUnits &LiveUnits, const MachineFunction &MF,
|
||||
const MachineFrameInfo &MFI,
|
||||
const TargetRegisterInfo &TRI) {
|
||||
/// Adds pristine registers to the given \p LiveUnits. Pristine registers are
|
||||
/// callee saved registers that are unused in the function.
|
||||
static void addPristines(LiveRegUnits &LiveUnits, const MachineFunction &MF) {
|
||||
const MachineFrameInfo &MFI = MF.getFrameInfo();
|
||||
if (!MFI.isCalleeSavedInfoValid())
|
||||
return;
|
||||
/// Add all callee saved regs, then remove the ones that are saved+restored.
|
||||
addCalleeSavedRegs(LiveUnits, MF);
|
||||
/// Remove the ones that are not saved/restored; they are pristine.
|
||||
for (const CalleeSavedInfo &Info : MFI.getCalleeSavedInfo())
|
||||
LiveUnits.removeReg(Info.getReg());
|
||||
}
|
||||
|
||||
void LiveRegUnits::addLiveOuts(const MachineBasicBlock &MBB) {
|
||||
const MachineFunction &MF = *MBB.getParent();
|
||||
const MachineFrameInfo &MFI = MF.getFrameInfo();
|
||||
if (MFI.isCalleeSavedInfoValid()) {
|
||||
for (const MCPhysReg *I = TRI->getCalleeSavedRegs(&MF); *I; ++I)
|
||||
addReg(*I);
|
||||
if (!MBB.isReturnBlock())
|
||||
removeSavedRegs(*this, MF, MFI, *TRI);
|
||||
if (!MBB.succ_empty()) {
|
||||
addPristines(*this, MF);
|
||||
// To get the live-outs we simply merge the live-ins of all successors.
|
||||
for (const MachineBasicBlock *Succ : MBB.successors())
|
||||
addBlockLiveIns(*this, *Succ);
|
||||
} else if (MBB.isReturnBlock()) {
|
||||
// For the return block: Add all callee saved registers.
|
||||
const MachineFrameInfo &MFI = MF.getFrameInfo();
|
||||
if (MFI.isCalleeSavedInfoValid())
|
||||
addCalleeSavedRegs(*this, MF);
|
||||
}
|
||||
::addLiveOuts(*this, MBB);
|
||||
}
|
||||
|
||||
void LiveRegUnits::addLiveIns(const MachineBasicBlock &MBB) {
|
||||
const MachineFunction &MF = *MBB.getParent();
|
||||
const MachineFrameInfo &MFI = MF.getFrameInfo();
|
||||
if (MFI.isCalleeSavedInfoValid()) {
|
||||
for (const MCPhysReg *I = TRI->getCalleeSavedRegs(&MF); *I; ++I)
|
||||
addReg(*I);
|
||||
if (&MBB != &MF.front())
|
||||
removeSavedRegs(*this, MF, MFI, *TRI);
|
||||
}
|
||||
::addLiveIns(*this, MBB);
|
||||
addPristines(*this, MF);
|
||||
addBlockLiveIns(*this, MBB);
|
||||
}
|
||||
|
@ -1,7 +1,19 @@
|
||||
#include "llvm/CodeGen/MachineRegionInfo.h"
|
||||
//===- lib/Codegen/MachineRegionInfo.cpp ----------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/ADT/Statistic.h"
|
||||
#include "llvm/Analysis/RegionInfoImpl.h"
|
||||
#include "llvm/CodeGen/MachinePostDominators.h"
|
||||
#include "llvm/CodeGen/MachineRegionInfo.h"
|
||||
#include "llvm/Pass.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
|
||||
#define DEBUG_TYPE "machine-region-info"
|
||||
|
||||
@ -11,36 +23,29 @@ STATISTIC(numMachineRegions, "The # of machine regions");
|
||||
STATISTIC(numMachineSimpleRegions, "The # of simple machine regions");
|
||||
|
||||
namespace llvm {
|
||||
|
||||
template class RegionBase<RegionTraits<MachineFunction>>;
|
||||
template class RegionNodeBase<RegionTraits<MachineFunction>>;
|
||||
template class RegionInfoBase<RegionTraits<MachineFunction>>;
|
||||
}
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// MachineRegion implementation
|
||||
//
|
||||
|
||||
MachineRegion::MachineRegion(MachineBasicBlock *Entry, MachineBasicBlock *Exit,
|
||||
MachineRegionInfo* RI,
|
||||
MachineDominatorTree *DT, MachineRegion *Parent) :
|
||||
RegionBase<RegionTraits<MachineFunction>>(Entry, Exit, RI, DT, Parent) {
|
||||
RegionBase<RegionTraits<MachineFunction>>(Entry, Exit, RI, DT, Parent) {}
|
||||
|
||||
}
|
||||
|
||||
MachineRegion::~MachineRegion() { }
|
||||
MachineRegion::~MachineRegion() = default;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// MachineRegionInfo implementation
|
||||
//
|
||||
|
||||
MachineRegionInfo::MachineRegionInfo() :
|
||||
RegionInfoBase<RegionTraits<MachineFunction>>() {
|
||||
MachineRegionInfo::MachineRegionInfo() = default;
|
||||
|
||||
}
|
||||
|
||||
MachineRegionInfo::~MachineRegionInfo() {
|
||||
|
||||
}
|
||||
MachineRegionInfo::~MachineRegionInfo() = default;
|
||||
|
||||
void MachineRegionInfo::updateStatistics(MachineRegion *R) {
|
||||
++numMachineRegions;
|
||||
@ -73,9 +78,7 @@ MachineRegionInfoPass::MachineRegionInfoPass() : MachineFunctionPass(ID) {
|
||||
initializeMachineRegionInfoPassPass(*PassRegistry::getPassRegistry());
|
||||
}
|
||||
|
||||
MachineRegionInfoPass::~MachineRegionInfoPass() {
|
||||
|
||||
}
|
||||
MachineRegionInfoPass::~MachineRegionInfoPass() = default;
|
||||
|
||||
bool MachineRegionInfoPass::runOnMachineFunction(MachineFunction &F) {
|
||||
releaseMemory();
|
||||
@ -137,8 +140,9 @@ INITIALIZE_PASS_END(MachineRegionInfoPass, DEBUG_TYPE,
|
||||
// the link time optimization.
|
||||
|
||||
namespace llvm {
|
||||
FunctionPass *createMachineRegionInfoPass() {
|
||||
return new MachineRegionInfoPass();
|
||||
}
|
||||
|
||||
FunctionPass *createMachineRegionInfoPass() {
|
||||
return new MachineRegionInfoPass();
|
||||
}
|
||||
|
||||
} // end namespace llvm
|
||||
|
@ -36,6 +36,7 @@
|
||||
#include "llvm/CodeGen/MachineFunctionPass.h"
|
||||
#include "llvm/CodeGen/MachineMemOperand.h"
|
||||
#include "llvm/CodeGen/MachineRegisterInfo.h"
|
||||
#include "llvm/CodeGen/StackMaps.h"
|
||||
#include "llvm/IR/BasicBlock.h"
|
||||
#include "llvm/IR/InlineAsm.h"
|
||||
#include "llvm/IR/Instructions.h"
|
||||
@ -909,17 +910,43 @@ void MachineVerifier::visitMachineInstrBefore(const MachineInstr *MI) {
|
||||
}
|
||||
}
|
||||
|
||||
// Generic loads and stores must have a single MachineMemOperand
|
||||
// describing that access.
|
||||
if ((MI->getOpcode() == TargetOpcode::G_LOAD ||
|
||||
MI->getOpcode() == TargetOpcode::G_STORE) &&
|
||||
!MI->hasOneMemOperand())
|
||||
report("Generic instruction accessing memory must have one mem operand",
|
||||
MI);
|
||||
|
||||
StringRef ErrorInfo;
|
||||
if (!TII->verifyInstruction(*MI, ErrorInfo))
|
||||
report(ErrorInfo.data(), MI);
|
||||
|
||||
// Verify properties of various specific instruction types
|
||||
switch(MI->getOpcode()) {
|
||||
default:
|
||||
break;
|
||||
case TargetOpcode::G_LOAD:
|
||||
case TargetOpcode::G_STORE:
|
||||
// Generic loads and stores must have a single MachineMemOperand
|
||||
// describing that access.
|
||||
if (!MI->hasOneMemOperand())
|
||||
report("Generic instruction accessing memory must have one mem operand",
|
||||
MI);
|
||||
break;
|
||||
case TargetOpcode::STATEPOINT:
|
||||
if (!MI->getOperand(StatepointOpers::IDPos).isImm() ||
|
||||
!MI->getOperand(StatepointOpers::NBytesPos).isImm() ||
|
||||
!MI->getOperand(StatepointOpers::NCallArgsPos).isImm())
|
||||
report("meta operands to STATEPOINT not constant!", MI);
|
||||
break;
|
||||
|
||||
auto VerifyStackMapConstant = [&](unsigned Offset) {
|
||||
if (!MI->getOperand(Offset).isImm() ||
|
||||
MI->getOperand(Offset).getImm() != StackMaps::ConstantOp ||
|
||||
!MI->getOperand(Offset + 1).isImm())
|
||||
report("stack map constant to STATEPOINT not well formed!", MI);
|
||||
};
|
||||
const unsigned VarStart = StatepointOpers(MI).getVarIdx();
|
||||
VerifyStackMapConstant(VarStart + StatepointOpers::CCOffset);
|
||||
VerifyStackMapConstant(VarStart + StatepointOpers::FlagsOffset);
|
||||
VerifyStackMapConstant(VarStart + StatepointOpers::NumDeoptOperandsOffset);
|
||||
|
||||
// TODO: verify we have properly encoded deopt arguments
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -54,8 +54,6 @@ static void doSpillCalleeSavedRegs(MachineFunction &MF, RegScavenger *RS,
|
||||
const MBBVector &SaveBlocks,
|
||||
const MBBVector &RestoreBlocks);
|
||||
|
||||
static void doScavengeFrameVirtualRegs(MachineFunction &MF, RegScavenger *RS);
|
||||
|
||||
namespace {
|
||||
class PEI : public MachineFunctionPass {
|
||||
public:
|
||||
@ -84,7 +82,7 @@ private:
|
||||
const MBBVector &SaveBlocks,
|
||||
const MBBVector &RestoreBlocks)>
|
||||
SpillCalleeSavedRegisters;
|
||||
std::function<void(MachineFunction &MF, RegScavenger *RS)>
|
||||
std::function<void(MachineFunction &MF, RegScavenger &RS)>
|
||||
ScavengeFrameVirtualRegs;
|
||||
|
||||
bool UsesCalleeSaves = false;
|
||||
@ -142,7 +140,6 @@ MachineFunctionPass *llvm::createPrologEpilogInserterPass() {
|
||||
return new PEI();
|
||||
}
|
||||
|
||||
STATISTIC(NumScavengedRegs, "Number of frame index regs scavenged");
|
||||
STATISTIC(NumBytesStackSpace,
|
||||
"Number of bytes used for stack in all functions");
|
||||
|
||||
@ -168,10 +165,10 @@ bool PEI::runOnMachineFunction(MachineFunction &Fn) {
|
||||
SpillCalleeSavedRegisters = [](MachineFunction &, RegScavenger *,
|
||||
unsigned &, unsigned &, const MBBVector &,
|
||||
const MBBVector &) {};
|
||||
ScavengeFrameVirtualRegs = [](MachineFunction &, RegScavenger *) {};
|
||||
ScavengeFrameVirtualRegs = [](MachineFunction &, RegScavenger &) {};
|
||||
} else {
|
||||
SpillCalleeSavedRegisters = doSpillCalleeSavedRegs;
|
||||
ScavengeFrameVirtualRegs = doScavengeFrameVirtualRegs;
|
||||
ScavengeFrameVirtualRegs = scavengeFrameVirtualRegs;
|
||||
UsesCalleeSaves = true;
|
||||
}
|
||||
}
|
||||
@ -222,7 +219,7 @@ bool PEI::runOnMachineFunction(MachineFunction &Fn) {
|
||||
// post-pass, scavenge the virtual registers that frame index elimination
|
||||
// inserted.
|
||||
if (TRI->requiresRegisterScavenging(Fn) && FrameIndexVirtualScavenging) {
|
||||
ScavengeFrameVirtualRegs(Fn, RS);
|
||||
ScavengeFrameVirtualRegs(Fn, *RS);
|
||||
|
||||
// Clear any vregs created by virtual scavenging.
|
||||
Fn.getRegInfo().clearVirtRegs();
|
||||
@ -1153,92 +1150,3 @@ void PEI::replaceFrameIndices(MachineBasicBlock *BB, MachineFunction &Fn,
|
||||
RS->forward(MI);
|
||||
}
|
||||
}
|
||||
|
||||
/// doScavengeFrameVirtualRegs - Replace all frame index virtual registers
|
||||
/// with physical registers. Use the register scavenger to find an
|
||||
/// appropriate register to use.
|
||||
///
|
||||
/// FIXME: Iterating over the instruction stream is unnecessary. We can simply
|
||||
/// iterate over the vreg use list, which at this point only contains machine
|
||||
/// operands for which eliminateFrameIndex need a new scratch reg.
|
||||
static void
|
||||
doScavengeFrameVirtualRegs(MachineFunction &MF, RegScavenger *RS) {
|
||||
// Run through the instructions and find any virtual registers.
|
||||
MachineRegisterInfo &MRI = MF.getRegInfo();
|
||||
for (MachineBasicBlock &MBB : MF) {
|
||||
RS->enterBasicBlock(MBB);
|
||||
|
||||
int SPAdj = 0;
|
||||
|
||||
// The instruction stream may change in the loop, so check MBB.end()
|
||||
// directly.
|
||||
for (MachineBasicBlock::iterator I = MBB.begin(); I != MBB.end(); ) {
|
||||
// We might end up here again with a NULL iterator if we scavenged a
|
||||
// register for which we inserted spill code for definition by what was
|
||||
// originally the first instruction in MBB.
|
||||
if (I == MachineBasicBlock::iterator(nullptr))
|
||||
I = MBB.begin();
|
||||
|
||||
const MachineInstr &MI = *I;
|
||||
MachineBasicBlock::iterator J = std::next(I);
|
||||
MachineBasicBlock::iterator P =
|
||||
I == MBB.begin() ? MachineBasicBlock::iterator(nullptr)
|
||||
: std::prev(I);
|
||||
|
||||
// RS should process this instruction before we might scavenge at this
|
||||
// location. This is because we might be replacing a virtual register
|
||||
// defined by this instruction, and if so, registers killed by this
|
||||
// instruction are available, and defined registers are not.
|
||||
RS->forward(I);
|
||||
|
||||
for (const MachineOperand &MO : MI.operands()) {
|
||||
if (!MO.isReg())
|
||||
continue;
|
||||
unsigned Reg = MO.getReg();
|
||||
if (!TargetRegisterInfo::isVirtualRegister(Reg))
|
||||
continue;
|
||||
|
||||
// When we first encounter a new virtual register, it
|
||||
// must be a definition.
|
||||
assert(MO.isDef() && "frame index virtual missing def!");
|
||||
// Scavenge a new scratch register
|
||||
const TargetRegisterClass *RC = MRI.getRegClass(Reg);
|
||||
unsigned ScratchReg = RS->scavengeRegister(RC, J, SPAdj);
|
||||
|
||||
++NumScavengedRegs;
|
||||
|
||||
// Replace this reference to the virtual register with the
|
||||
// scratch register.
|
||||
assert(ScratchReg && "Missing scratch register!");
|
||||
MRI.replaceRegWith(Reg, ScratchReg);
|
||||
|
||||
// Because this instruction was processed by the RS before this
|
||||
// register was allocated, make sure that the RS now records the
|
||||
// register as being used.
|
||||
RS->setRegUsed(ScratchReg);
|
||||
}
|
||||
|
||||
// If the scavenger needed to use one of its spill slots, the
|
||||
// spill code will have been inserted in between I and J. This is a
|
||||
// problem because we need the spill code before I: Move I to just
|
||||
// prior to J.
|
||||
if (I != std::prev(J)) {
|
||||
MBB.splice(J, &MBB, I);
|
||||
|
||||
// Before we move I, we need to prepare the RS to visit I again.
|
||||
// Specifically, RS will assert if it sees uses of registers that
|
||||
// it believes are undefined. Because we have already processed
|
||||
// register kills in I, when it visits I again, it will believe that
|
||||
// those registers are undefined. To avoid this situation, unprocess
|
||||
// the instruction I.
|
||||
assert(RS->getCurrentPosition() == I &&
|
||||
"The register scavenger has an unexpected position");
|
||||
I = P;
|
||||
RS->unprocess(P);
|
||||
} else
|
||||
++I;
|
||||
}
|
||||
}
|
||||
|
||||
MF.getProperties().set(MachineFunctionProperties::Property::NoVRegs);
|
||||
}
|
||||
|
@ -58,8 +58,9 @@ namespace {
|
||||
/// whenever a register is unavailable. This is not practical in production but
|
||||
/// provides a useful baseline both for measuring other allocators and comparing
|
||||
/// the speed of the basic algorithm against other styles of allocators.
|
||||
class RABasic : public MachineFunctionPass, public RegAllocBase
|
||||
{
|
||||
class RABasic : public MachineFunctionPass,
|
||||
public RegAllocBase,
|
||||
private LiveRangeEdit::Delegate {
|
||||
// context
|
||||
MachineFunction *MF;
|
||||
|
||||
@ -72,6 +73,9 @@ class RABasic : public MachineFunctionPass, public RegAllocBase
|
||||
// selectOrSplit().
|
||||
BitVector UsableRegs;
|
||||
|
||||
bool LRE_CanEraseVirtReg(unsigned) override;
|
||||
void LRE_WillShrinkVirtReg(unsigned) override;
|
||||
|
||||
public:
|
||||
RABasic();
|
||||
|
||||
@ -121,17 +125,46 @@ char RABasic::ID = 0;
|
||||
|
||||
} // end anonymous namespace
|
||||
|
||||
char &llvm::RABasicID = RABasic::ID;
|
||||
|
||||
INITIALIZE_PASS_BEGIN(RABasic, "regallocbasic", "Basic Register Allocator",
|
||||
false, false)
|
||||
INITIALIZE_PASS_DEPENDENCY(LiveDebugVariables)
|
||||
INITIALIZE_PASS_DEPENDENCY(SlotIndexes)
|
||||
INITIALIZE_PASS_DEPENDENCY(LiveIntervals)
|
||||
INITIALIZE_PASS_DEPENDENCY(RegisterCoalescer)
|
||||
INITIALIZE_PASS_DEPENDENCY(MachineScheduler)
|
||||
INITIALIZE_PASS_DEPENDENCY(LiveStacks)
|
||||
INITIALIZE_PASS_DEPENDENCY(MachineDominatorTree)
|
||||
INITIALIZE_PASS_DEPENDENCY(MachineLoopInfo)
|
||||
INITIALIZE_PASS_DEPENDENCY(VirtRegMap)
|
||||
INITIALIZE_PASS_DEPENDENCY(LiveRegMatrix)
|
||||
INITIALIZE_PASS_END(RABasic, "regallocbasic", "Basic Register Allocator", false,
|
||||
false)
|
||||
|
||||
bool RABasic::LRE_CanEraseVirtReg(unsigned VirtReg) {
|
||||
if (VRM->hasPhys(VirtReg)) {
|
||||
LiveInterval &LI = LIS->getInterval(VirtReg);
|
||||
Matrix->unassign(LI);
|
||||
aboutToRemoveInterval(LI);
|
||||
return true;
|
||||
}
|
||||
// Unassigned virtreg is probably in the priority queue.
|
||||
// RegAllocBase will erase it after dequeueing.
|
||||
return false;
|
||||
}
|
||||
|
||||
void RABasic::LRE_WillShrinkVirtReg(unsigned VirtReg) {
|
||||
if (!VRM->hasPhys(VirtReg))
|
||||
return;
|
||||
|
||||
// Register is assigned, put it back on the queue for reassignment.
|
||||
LiveInterval &LI = LIS->getInterval(VirtReg);
|
||||
Matrix->unassign(LI);
|
||||
enqueue(&LI);
|
||||
}
|
||||
|
||||
RABasic::RABasic(): MachineFunctionPass(ID) {
|
||||
initializeLiveDebugVariablesPass(*PassRegistry::getPassRegistry());
|
||||
initializeLiveIntervalsPass(*PassRegistry::getPassRegistry());
|
||||
initializeSlotIndexesPass(*PassRegistry::getPassRegistry());
|
||||
initializeRegisterCoalescerPass(*PassRegistry::getPassRegistry());
|
||||
initializeMachineSchedulerPass(*PassRegistry::getPassRegistry());
|
||||
initializeLiveStacksPass(*PassRegistry::getPassRegistry());
|
||||
initializeMachineDominatorTreePass(*PassRegistry::getPassRegistry());
|
||||
initializeMachineLoopInfoPass(*PassRegistry::getPassRegistry());
|
||||
initializeVirtRegMapPass(*PassRegistry::getPassRegistry());
|
||||
initializeLiveRegMatrixPass(*PassRegistry::getPassRegistry());
|
||||
}
|
||||
|
||||
void RABasic::getAnalysisUsage(AnalysisUsage &AU) const {
|
||||
@ -200,7 +233,7 @@ bool RABasic::spillInterferences(LiveInterval &VirtReg, unsigned PhysReg,
|
||||
Matrix->unassign(Spill);
|
||||
|
||||
// Spill the extracted interval.
|
||||
LiveRangeEdit LRE(&Spill, SplitVRegs, *MF, *LIS, VRM, nullptr, &DeadRemats);
|
||||
LiveRangeEdit LRE(&Spill, SplitVRegs, *MF, *LIS, VRM, this, &DeadRemats);
|
||||
spiller().spill(LRE);
|
||||
}
|
||||
return true;
|
||||
@ -259,7 +292,7 @@ unsigned RABasic::selectOrSplit(LiveInterval &VirtReg,
|
||||
DEBUG(dbgs() << "spilling: " << VirtReg << '\n');
|
||||
if (!VirtReg.isSpillable())
|
||||
return ~0u;
|
||||
LiveRangeEdit LRE(&VirtReg, SplitVRegs, *MF, *LIS, VRM, nullptr, &DeadRemats);
|
||||
LiveRangeEdit LRE(&VirtReg, SplitVRegs, *MF, *LIS, VRM, this, &DeadRemats);
|
||||
spiller().spill(LRE);
|
||||
|
||||
// The live virtual register requesting allocation was spilled, so tell
|
||||
|
@ -49,9 +49,11 @@
|
||||
#include "llvm/CodeGen/MachineDominators.h"
|
||||
#include "llvm/CodeGen/MachineFunction.h"
|
||||
#include "llvm/CodeGen/MachineFunctionPass.h"
|
||||
#include "llvm/CodeGen/MachineInstr.h"
|
||||
#include "llvm/CodeGen/MachineLoopInfo.h"
|
||||
#include "llvm/CodeGen/MachineRegisterInfo.h"
|
||||
#include "llvm/CodeGen/PBQP/Graph.h"
|
||||
#include "llvm/CodeGen/PBQP/Math.h"
|
||||
#include "llvm/CodeGen/PBQP/Solution.h"
|
||||
#include "llvm/CodeGen/PBQPRAConstraint.h"
|
||||
#include "llvm/CodeGen/RegAllocPBQP.h"
|
||||
@ -139,13 +141,13 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
typedef std::map<const LiveInterval*, unsigned> LI2NodeMap;
|
||||
typedef std::vector<const LiveInterval*> Node2LIMap;
|
||||
typedef std::vector<unsigned> AllowedSet;
|
||||
typedef std::vector<AllowedSet> AllowedSetMap;
|
||||
typedef std::pair<unsigned, unsigned> RegPair;
|
||||
typedef std::map<RegPair, PBQP::PBQPNum> CoalesceMap;
|
||||
typedef std::set<unsigned> RegSet;
|
||||
using LI2NodeMap = std::map<const LiveInterval *, unsigned>;
|
||||
using Node2LIMap = std::vector<const LiveInterval *>;
|
||||
using AllowedSet = std::vector<unsigned>;
|
||||
using AllowedSetMap = std::vector<AllowedSet>;
|
||||
using RegPair = std::pair<unsigned, unsigned>;
|
||||
using CoalesceMap = std::map<RegPair, PBQP::PBQPNum>;
|
||||
using RegSet = std::set<unsigned>;
|
||||
|
||||
char *customPassID;
|
||||
|
||||
@ -212,12 +214,12 @@ public:
|
||||
/// @brief Add interference edges between overlapping vregs.
|
||||
class Interference : public PBQPRAConstraint {
|
||||
private:
|
||||
typedef const PBQP::RegAlloc::AllowedRegVector* AllowedRegVecPtr;
|
||||
typedef std::pair<AllowedRegVecPtr, AllowedRegVecPtr> IKey;
|
||||
typedef DenseMap<IKey, PBQPRAGraph::MatrixPtr> IMatrixCache;
|
||||
typedef DenseSet<IKey> DisjointAllowedRegsCache;
|
||||
typedef std::pair<PBQP::GraphBase::NodeId, PBQP::GraphBase::NodeId> IEdgeKey;
|
||||
typedef DenseSet<IEdgeKey> IEdgeCache;
|
||||
using AllowedRegVecPtr = const PBQP::RegAlloc::AllowedRegVector *;
|
||||
using IKey = std::pair<AllowedRegVecPtr, AllowedRegVecPtr>;
|
||||
using IMatrixCache = DenseMap<IKey, PBQPRAGraph::MatrixPtr>;
|
||||
using DisjointAllowedRegsCache = DenseSet<IKey>;
|
||||
using IEdgeKey = std::pair<PBQP::GraphBase::NodeId, PBQP::GraphBase::NodeId>;
|
||||
using IEdgeCache = DenseSet<IEdgeKey>;
|
||||
|
||||
bool haveDisjointAllowedRegs(const PBQPRAGraph &G, PBQPRAGraph::NodeId NId,
|
||||
PBQPRAGraph::NodeId MId,
|
||||
@ -252,8 +254,8 @@ private:
|
||||
// for the fast interference graph construction algorithm. The last is there
|
||||
// to save us from looking up node ids via the VRegToNode map in the graph
|
||||
// metadata.
|
||||
typedef std::tuple<LiveInterval*, size_t, PBQP::GraphBase::NodeId>
|
||||
IntervalInfo;
|
||||
using IntervalInfo =
|
||||
std::tuple<LiveInterval*, size_t, PBQP::GraphBase::NodeId>;
|
||||
|
||||
static SlotIndex getStartPoint(const IntervalInfo &I) {
|
||||
return std::get<0>(I)->segments[std::get<1>(I)].start;
|
||||
@ -320,9 +322,10 @@ public:
|
||||
// Cache known disjoint allowed registers pairs
|
||||
DisjointAllowedRegsCache D;
|
||||
|
||||
typedef std::set<IntervalInfo, decltype(&lowestEndPoint)> IntervalSet;
|
||||
typedef std::priority_queue<IntervalInfo, std::vector<IntervalInfo>,
|
||||
decltype(&lowestStartPoint)> IntervalQueue;
|
||||
using IntervalSet = std::set<IntervalInfo, decltype(&lowestEndPoint)>;
|
||||
using IntervalQueue =
|
||||
std::priority_queue<IntervalInfo, std::vector<IntervalInfo>,
|
||||
decltype(&lowestStartPoint)>;
|
||||
IntervalSet Active(lowestEndPoint);
|
||||
IntervalQueue Inactive(lowestStartPoint);
|
||||
|
||||
@ -658,7 +661,6 @@ void RegAllocPBQP::spillVReg(unsigned VReg,
|
||||
SmallVectorImpl<unsigned> &NewIntervals,
|
||||
MachineFunction &MF, LiveIntervals &LIS,
|
||||
VirtRegMap &VRM, Spiller &VRegSpiller) {
|
||||
|
||||
VRegsToAlloc.erase(VReg);
|
||||
LiveRangeEdit LRE(&LIS.getInterval(VReg), NewIntervals, MF, LIS, &VRM,
|
||||
nullptr, &DeadRemats);
|
||||
|
@ -15,18 +15,23 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/CodeGen/RegisterScavenging.h"
|
||||
|
||||
#include "llvm/ADT/BitVector.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/CodeGen/RegisterScavenging.h"
|
||||
#include "llvm/ADT/Statistic.h"
|
||||
#include "llvm/CodeGen/MachineBasicBlock.h"
|
||||
#include "llvm/CodeGen/MachineFrameInfo.h"
|
||||
#include "llvm/CodeGen/MachineFunction.h"
|
||||
#include "llvm/CodeGen/MachineInstr.h"
|
||||
#include "llvm/CodeGen/MachineOperand.h"
|
||||
#include "llvm/CodeGen/MachineRegisterInfo.h"
|
||||
#include "llvm/MC/MCRegisterInfo.h"
|
||||
#include "llvm/PassSupport.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/Target/TargetFrameLowering.h"
|
||||
#include "llvm/Target/TargetInstrInfo.h"
|
||||
#include "llvm/Target/TargetRegisterInfo.h"
|
||||
#include "llvm/Target/TargetSubtargetInfo.h"
|
||||
@ -39,6 +44,8 @@ using namespace llvm;
|
||||
|
||||
#define DEBUG_TYPE "reg-scavenging"
|
||||
|
||||
STATISTIC(NumScavengedRegs, "Number of frame index regs scavenged");
|
||||
|
||||
void RegScavenger::setRegUsed(unsigned Reg, LaneBitmask LaneMask) {
|
||||
LiveUnits.addRegMasked(Reg, LaneMask);
|
||||
}
|
||||
@ -469,3 +476,120 @@ unsigned RegScavenger::scavengeRegister(const TargetRegisterClass *RC,
|
||||
|
||||
return SReg;
|
||||
}
|
||||
|
||||
void llvm::scavengeFrameVirtualRegs(MachineFunction &MF, RegScavenger &RS) {
|
||||
// FIXME: Iterating over the instruction stream is unnecessary. We can simply
|
||||
// iterate over the vreg use list, which at this point only contains machine
|
||||
// operands for which eliminateFrameIndex need a new scratch reg.
|
||||
|
||||
// Run through the instructions and find any virtual registers.
|
||||
MachineRegisterInfo &MRI = MF.getRegInfo();
|
||||
for (MachineBasicBlock &MBB : MF) {
|
||||
RS.enterBasicBlock(MBB);
|
||||
|
||||
int SPAdj = 0;
|
||||
|
||||
// The instruction stream may change in the loop, so check MBB.end()
|
||||
// directly.
|
||||
for (MachineBasicBlock::iterator I = MBB.begin(); I != MBB.end(); ) {
|
||||
// We might end up here again with a NULL iterator if we scavenged a
|
||||
// register for which we inserted spill code for definition by what was
|
||||
// originally the first instruction in MBB.
|
||||
if (I == MachineBasicBlock::iterator(nullptr))
|
||||
I = MBB.begin();
|
||||
|
||||
const MachineInstr &MI = *I;
|
||||
MachineBasicBlock::iterator J = std::next(I);
|
||||
MachineBasicBlock::iterator P =
|
||||
I == MBB.begin() ? MachineBasicBlock::iterator(nullptr)
|
||||
: std::prev(I);
|
||||
|
||||
// RS should process this instruction before we might scavenge at this
|
||||
// location. This is because we might be replacing a virtual register
|
||||
// defined by this instruction, and if so, registers killed by this
|
||||
// instruction are available, and defined registers are not.
|
||||
RS.forward(I);
|
||||
|
||||
for (const MachineOperand &MO : MI.operands()) {
|
||||
if (!MO.isReg())
|
||||
continue;
|
||||
unsigned Reg = MO.getReg();
|
||||
if (!TargetRegisterInfo::isVirtualRegister(Reg))
|
||||
continue;
|
||||
|
||||
// When we first encounter a new virtual register, it
|
||||
// must be a definition.
|
||||
assert(MO.isDef() && "frame index virtual missing def!");
|
||||
// Scavenge a new scratch register
|
||||
const TargetRegisterClass *RC = MRI.getRegClass(Reg);
|
||||
unsigned ScratchReg = RS.scavengeRegister(RC, J, SPAdj);
|
||||
|
||||
++NumScavengedRegs;
|
||||
|
||||
// Replace this reference to the virtual register with the
|
||||
// scratch register.
|
||||
assert(ScratchReg && "Missing scratch register!");
|
||||
MRI.replaceRegWith(Reg, ScratchReg);
|
||||
|
||||
// Because this instruction was processed by the RS before this
|
||||
// register was allocated, make sure that the RS now records the
|
||||
// register as being used.
|
||||
RS.setRegUsed(ScratchReg);
|
||||
}
|
||||
|
||||
// If the scavenger needed to use one of its spill slots, the
|
||||
// spill code will have been inserted in between I and J. This is a
|
||||
// problem because we need the spill code before I: Move I to just
|
||||
// prior to J.
|
||||
if (I != std::prev(J)) {
|
||||
MBB.splice(J, &MBB, I);
|
||||
|
||||
// Before we move I, we need to prepare the RS to visit I again.
|
||||
// Specifically, RS will assert if it sees uses of registers that
|
||||
// it believes are undefined. Because we have already processed
|
||||
// register kills in I, when it visits I again, it will believe that
|
||||
// those registers are undefined. To avoid this situation, unprocess
|
||||
// the instruction I.
|
||||
assert(RS.getCurrentPosition() == I &&
|
||||
"The register scavenger has an unexpected position");
|
||||
I = P;
|
||||
RS.unprocess(P);
|
||||
} else
|
||||
++I;
|
||||
}
|
||||
}
|
||||
|
||||
MRI.clearVirtRegs();
|
||||
MF.getProperties().set(MachineFunctionProperties::Property::NoVRegs);
|
||||
}
|
||||
|
||||
namespace {
|
||||
/// This class runs register scavenging independ of the PrologEpilogInserter.
|
||||
/// This is used in for testing.
|
||||
class ScavengerTest : public MachineFunctionPass {
|
||||
public:
|
||||
static char ID;
|
||||
ScavengerTest() : MachineFunctionPass(ID) {}
|
||||
bool runOnMachineFunction(MachineFunction &MF) {
|
||||
const TargetSubtargetInfo &STI = MF.getSubtarget();
|
||||
const TargetFrameLowering &TFL = *STI.getFrameLowering();
|
||||
|
||||
RegScavenger RS;
|
||||
// Let's hope that calling those outside of PrologEpilogueInserter works
|
||||
// well enough to initialize the scavenger with some emergency spillslots
|
||||
// for the target.
|
||||
BitVector SavedRegs;
|
||||
TFL.determineCalleeSaves(MF, SavedRegs, &RS);
|
||||
TFL.processFunctionBeforeFrameFinalized(MF, &RS);
|
||||
|
||||
// Let's scavenge the current function
|
||||
scavengeFrameVirtualRegs(MF, RS);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
char ScavengerTest::ID;
|
||||
|
||||
} // end anonymous namespace
|
||||
|
||||
INITIALIZE_PASS(ScavengerTest, "scavenger-test",
|
||||
"Scavenge virtual registers inside basic blocks", false, false)
|
||||
|
@ -12,32 +12,54 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/CodeGen/ScheduleDAGInstrs.h"
|
||||
#include "llvm/ADT/IntEqClasses.h"
|
||||
#include "llvm/ADT/iterator_range.h"
|
||||
#include "llvm/ADT/MapVector.h"
|
||||
#include "llvm/ADT/SmallPtrSet.h"
|
||||
#include "llvm/ADT/SmallSet.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/SparseSet.h"
|
||||
#include "llvm/Analysis/AliasAnalysis.h"
|
||||
#include "llvm/Analysis/ValueTracking.h"
|
||||
#include "llvm/CodeGen/LiveIntervalAnalysis.h"
|
||||
#include "llvm/CodeGen/MachineFunctionPass.h"
|
||||
#include "llvm/CodeGen/LivePhysRegs.h"
|
||||
#include "llvm/CodeGen/MachineBasicBlock.h"
|
||||
#include "llvm/CodeGen/MachineFunction.h"
|
||||
#include "llvm/CodeGen/MachineFrameInfo.h"
|
||||
#include "llvm/CodeGen/MachineInstrBuilder.h"
|
||||
#include "llvm/CodeGen/MachineInstr.h"
|
||||
#include "llvm/CodeGen/MachineInstrBundle.h"
|
||||
#include "llvm/CodeGen/MachineMemOperand.h"
|
||||
#include "llvm/CodeGen/MachineOperand.h"
|
||||
#include "llvm/CodeGen/MachineRegisterInfo.h"
|
||||
#include "llvm/CodeGen/PseudoSourceValue.h"
|
||||
#include "llvm/CodeGen/RegisterPressure.h"
|
||||
#include "llvm/CodeGen/ScheduleDAG.h"
|
||||
#include "llvm/CodeGen/ScheduleDAGInstrs.h"
|
||||
#include "llvm/CodeGen/ScheduleDFS.h"
|
||||
#include "llvm/CodeGen/SlotIndexes.h"
|
||||
#include "llvm/IR/Constants.h"
|
||||
#include "llvm/IR/Function.h"
|
||||
#include "llvm/IR/Type.h"
|
||||
#include "llvm/IR/Instruction.h"
|
||||
#include "llvm/IR/Instructions.h"
|
||||
#include "llvm/IR/Operator.h"
|
||||
#include "llvm/IR/Type.h"
|
||||
#include "llvm/IR/Value.h"
|
||||
#include "llvm/MC/LaneBitmask.h"
|
||||
#include "llvm/MC/MCRegisterInfo.h"
|
||||
#include "llvm/Support/Casting.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Support/Format.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/Target/TargetInstrInfo.h"
|
||||
#include "llvm/Target/TargetMachine.h"
|
||||
#include "llvm/Target/TargetRegisterInfo.h"
|
||||
#include "llvm/Target/TargetSubtargetInfo.h"
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <iterator>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
@ -90,11 +112,9 @@ ScheduleDAGInstrs::ScheduleDAGInstrs(MachineFunction &mf,
|
||||
const MachineLoopInfo *mli,
|
||||
bool RemoveKillFlags)
|
||||
: ScheduleDAG(mf), MLI(mli), MFI(mf.getFrameInfo()),
|
||||
RemoveKillFlags(RemoveKillFlags), CanHandleTerminators(false),
|
||||
TrackLaneMasks(false), AAForDep(nullptr), BarrierChain(nullptr),
|
||||
RemoveKillFlags(RemoveKillFlags),
|
||||
UnknownValue(UndefValue::get(
|
||||
Type::getVoidTy(mf.getFunction()->getContext()))),
|
||||
FirstDbgValue(nullptr) {
|
||||
Type::getVoidTy(mf.getFunction()->getContext()))) {
|
||||
DbgValues.clear();
|
||||
|
||||
const TargetSubtargetInfo &ST = mf.getSubtarget();
|
||||
@ -126,7 +146,7 @@ static const Value *getUnderlyingObjectFromInt(const Value *V) {
|
||||
return V;
|
||||
}
|
||||
assert(V->getType()->isIntegerTy() && "Unexpected operand type!");
|
||||
} while (1);
|
||||
} while (true);
|
||||
}
|
||||
|
||||
/// This is a wrapper around GetUnderlyingObjects and adds support for basic
|
||||
@ -563,7 +583,7 @@ void ScheduleDAGInstrs::initSUnits() {
|
||||
// which is contained within a basic block.
|
||||
SUnits.reserve(NumRegionInstrs);
|
||||
|
||||
for (MachineInstr &MI : llvm::make_range(RegionBegin, RegionEnd)) {
|
||||
for (MachineInstr &MI : make_range(RegionBegin, RegionEnd)) {
|
||||
if (MI.isDebugValue())
|
||||
continue;
|
||||
|
||||
@ -606,13 +626,13 @@ void ScheduleDAGInstrs::initSUnits() {
|
||||
|
||||
class ScheduleDAGInstrs::Value2SUsMap : public MapVector<ValueType, SUList> {
|
||||
/// Current total number of SUs in map.
|
||||
unsigned NumNodes;
|
||||
unsigned NumNodes = 0;
|
||||
|
||||
/// 1 for loads, 0 for stores. (see comment in SUList)
|
||||
unsigned TrueMemOrderLatency;
|
||||
|
||||
public:
|
||||
Value2SUsMap(unsigned lat = 0) : NumNodes(0), TrueMemOrderLatency(lat) {}
|
||||
Value2SUsMap(unsigned lat = 0) : TrueMemOrderLatency(lat) {}
|
||||
|
||||
/// To keep NumNodes up to date, insert() is used instead of
|
||||
/// this operator w/ push_back().
|
||||
@ -630,7 +650,7 @@ public:
|
||||
void inline clearList(ValueType V) {
|
||||
iterator Itr = find(V);
|
||||
if (Itr != end()) {
|
||||
assert (NumNodes >= Itr->second.size());
|
||||
assert(NumNodes >= Itr->second.size());
|
||||
NumNodes -= Itr->second.size();
|
||||
|
||||
Itr->second.clear();
|
||||
@ -646,7 +666,7 @@ public:
|
||||
unsigned inline size() const { return NumNodes; }
|
||||
|
||||
/// Counts the number of SUs in this map after a reduction.
|
||||
void reComputeSize(void) {
|
||||
void reComputeSize() {
|
||||
NumNodes = 0;
|
||||
for (auto &I : *this)
|
||||
NumNodes += I.second.size();
|
||||
@ -676,7 +696,7 @@ void ScheduleDAGInstrs::addChainDependencies(SUnit *SU,
|
||||
}
|
||||
|
||||
void ScheduleDAGInstrs::addBarrierChain(Value2SUsMap &map) {
|
||||
assert (BarrierChain != nullptr);
|
||||
assert(BarrierChain != nullptr);
|
||||
|
||||
for (auto &I : map) {
|
||||
SUList &sus = I.second;
|
||||
@ -687,7 +707,7 @@ void ScheduleDAGInstrs::addBarrierChain(Value2SUsMap &map) {
|
||||
}
|
||||
|
||||
void ScheduleDAGInstrs::insertBarrierChain(Value2SUsMap &map) {
|
||||
assert (BarrierChain != nullptr);
|
||||
assert(BarrierChain != nullptr);
|
||||
|
||||
// Go through all lists of SUs.
|
||||
for (Value2SUsMap::iterator I = map.begin(), EE = map.end(); I != EE;) {
|
||||
@ -1028,7 +1048,7 @@ void ScheduleDAGInstrs::reduceHugeMemNodeMaps(Value2SUsMap &stores,
|
||||
// The N last elements in NodeNums will be removed, and the SU with
|
||||
// the lowest NodeNum of them will become the new BarrierChain to
|
||||
// let the not yet seen SUs have a dependency to the removed SUs.
|
||||
assert (N <= NodeNums.size());
|
||||
assert(N <= NodeNums.size());
|
||||
SUnit *newBarrierChain = &SUnits[*(NodeNums.end() - N)];
|
||||
if (BarrierChain) {
|
||||
// The aliasing and non-aliasing maps reduce independently of each
|
||||
@ -1156,6 +1176,7 @@ std::string ScheduleDAGInstrs::getDAGName() const {
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
namespace llvm {
|
||||
|
||||
/// Internal state used to compute SchedDFSResult.
|
||||
class SchedDFSImpl {
|
||||
SchedDFSResult &R;
|
||||
@ -1163,16 +1184,16 @@ class SchedDFSImpl {
|
||||
/// Join DAG nodes into equivalence classes by their subtree.
|
||||
IntEqClasses SubtreeClasses;
|
||||
/// List PredSU, SuccSU pairs that represent data edges between subtrees.
|
||||
std::vector<std::pair<const SUnit*, const SUnit*> > ConnectionPairs;
|
||||
std::vector<std::pair<const SUnit *, const SUnit*>> ConnectionPairs;
|
||||
|
||||
struct RootData {
|
||||
unsigned NodeID;
|
||||
unsigned ParentNodeID; ///< Parent node (member of the parent subtree).
|
||||
unsigned SubInstrCount; ///< Instr count in this tree only, not children.
|
||||
unsigned SubInstrCount = 0; ///< Instr count in this tree only, not
|
||||
/// children.
|
||||
|
||||
RootData(unsigned id): NodeID(id),
|
||||
ParentNodeID(SchedDFSResult::InvalidSubtreeID),
|
||||
SubInstrCount(0) {}
|
||||
ParentNodeID(SchedDFSResult::InvalidSubtreeID) {}
|
||||
|
||||
unsigned getSparseSetIndex() const { return NodeID; }
|
||||
};
|
||||
@ -1340,12 +1361,15 @@ protected:
|
||||
} while (FromTree != SchedDFSResult::InvalidSubtreeID);
|
||||
}
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
namespace {
|
||||
|
||||
/// Manage the stack used by a reverse depth-first search over the DAG.
|
||||
class SchedDAGReverseDFS {
|
||||
std::vector<std::pair<const SUnit*, SUnit::const_pred_iterator> > DFSStack;
|
||||
std::vector<std::pair<const SUnit *, SUnit::const_pred_iterator>> DFSStack;
|
||||
|
||||
public:
|
||||
bool isComplete() const { return DFSStack.empty(); }
|
||||
|
||||
@ -1367,7 +1391,8 @@ public:
|
||||
return getCurr()->Preds.end();
|
||||
}
|
||||
};
|
||||
} // anonymous
|
||||
|
||||
} // end anonymous namespace
|
||||
|
||||
static bool hasDataSucc(const SUnit *SU) {
|
||||
for (const SDep &SuccDep : SU->Succs) {
|
||||
@ -1392,7 +1417,7 @@ void SchedDFSResult::compute(ArrayRef<SUnit> SUnits) {
|
||||
SchedDAGReverseDFS DFS;
|
||||
Impl.visitPreorder(&SU);
|
||||
DFS.follow(&SU);
|
||||
for (;;) {
|
||||
while (true) {
|
||||
// Traverse the leftmost path as far as possible.
|
||||
while (DFS.getPred() != DFS.getPredEnd()) {
|
||||
const SDep &PredDep = *DFS.getPred();
|
||||
@ -1457,4 +1482,5 @@ raw_ostream &operator<<(raw_ostream &OS, const ILPValue &Val) {
|
||||
}
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif
|
||||
|
@ -225,6 +225,7 @@ SDValue VectorLegalizer::LegalizeOp(SDValue Op) {
|
||||
}
|
||||
return TranslateLegalizeResults(Op, Lowered);
|
||||
}
|
||||
LLVM_FALLTHROUGH;
|
||||
case TargetLowering::Expand:
|
||||
Changed = true;
|
||||
return LegalizeOp(ExpandLoad(Op));
|
||||
|
@ -1,4 +1,4 @@
|
||||
//===-- SelectionDAG.cpp - Implement the SelectionDAG data structures -----===//
|
||||
//===- SelectionDAG.cpp - Implement the SelectionDAG data structures ------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
@ -11,29 +11,46 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/CodeGen/SelectionDAG.h"
|
||||
#include "SDNodeDbgValue.h"
|
||||
#include "llvm/ADT/APFloat.h"
|
||||
#include "llvm/ADT/APInt.h"
|
||||
#include "llvm/ADT/APSInt.h"
|
||||
#include "llvm/ADT/SetVector.h"
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/BitVector.h"
|
||||
#include "llvm/ADT/FoldingSet.h"
|
||||
#include "llvm/ADT/None.h"
|
||||
#include "llvm/ADT/SmallPtrSet.h"
|
||||
#include "llvm/ADT/SmallSet.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/StringExtras.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/ADT/Triple.h"
|
||||
#include "llvm/ADT/Twine.h"
|
||||
#include "llvm/Analysis/ValueTracking.h"
|
||||
#include "llvm/CodeGen/ISDOpcodes.h"
|
||||
#include "llvm/CodeGen/MachineBasicBlock.h"
|
||||
#include "llvm/CodeGen/MachineConstantPool.h"
|
||||
#include "llvm/CodeGen/MachineFrameInfo.h"
|
||||
#include "llvm/CodeGen/MachineModuleInfo.h"
|
||||
#include "llvm/CodeGen/MachineFunction.h"
|
||||
#include "llvm/CodeGen/MachineMemOperand.h"
|
||||
#include "llvm/CodeGen/MachineValueType.h"
|
||||
#include "llvm/CodeGen/RuntimeLibcalls.h"
|
||||
#include "llvm/CodeGen/SelectionDAG.h"
|
||||
#include "llvm/CodeGen/SelectionDAGNodes.h"
|
||||
#include "llvm/CodeGen/SelectionDAGTargetInfo.h"
|
||||
#include "llvm/IR/CallingConv.h"
|
||||
#include "llvm/CodeGen/ValueTypes.h"
|
||||
#include "llvm/IR/Constant.h"
|
||||
#include "llvm/IR/Constants.h"
|
||||
#include "llvm/IR/DataLayout.h"
|
||||
#include "llvm/IR/DebugInfo.h"
|
||||
#include "llvm/IR/DebugInfoMetadata.h"
|
||||
#include "llvm/IR/DebugLoc.h"
|
||||
#include "llvm/IR/DerivedTypes.h"
|
||||
#include "llvm/IR/Function.h"
|
||||
#include "llvm/IR/GlobalAlias.h"
|
||||
#include "llvm/IR/GlobalVariable.h"
|
||||
#include "llvm/IR/Intrinsics.h"
|
||||
#include "llvm/IR/GlobalValue.h"
|
||||
#include "llvm/IR/Metadata.h"
|
||||
#include "llvm/IR/Type.h"
|
||||
#include "llvm/IR/Value.h"
|
||||
#include "llvm/Support/Casting.h"
|
||||
#include "llvm/Support/CodeGen.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Support/KnownBits.h"
|
||||
@ -41,16 +58,20 @@
|
||||
#include "llvm/Support/MathExtras.h"
|
||||
#include "llvm/Support/Mutex.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/Target/TargetInstrInfo.h"
|
||||
#include "llvm/Target/TargetIntrinsicInfo.h"
|
||||
#include "llvm/Target/TargetLowering.h"
|
||||
#include "llvm/Target/TargetMachine.h"
|
||||
#include "llvm/Target/TargetOptions.h"
|
||||
#include "llvm/Target/TargetRegisterInfo.h"
|
||||
#include "llvm/Target/TargetSubtargetInfo.h"
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <limits>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
@ -269,7 +290,6 @@ ISD::CondCode ISD::getSetCCInverse(ISD::CondCode Op, bool isInteger) {
|
||||
return ISD::CondCode(Operation);
|
||||
}
|
||||
|
||||
|
||||
/// For an integer comparison, return 1 if the comparison is a signed operation
|
||||
/// and 2 if the result is an unsigned comparison. Return zero if the operation
|
||||
/// does not depend on the sign of the input (setne and seteq).
|
||||
@ -338,7 +358,6 @@ ISD::CondCode ISD::getSetCCAndOperation(ISD::CondCode Op1, ISD::CondCode Op2,
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// AddNodeIDOpcode - Add the node opcode to the NodeID data.
|
||||
///
|
||||
static void AddNodeIDOpcode(FoldingSetNodeID &ID, unsigned OpC) {
|
||||
ID.AddInteger(OpC);
|
||||
}
|
||||
@ -350,7 +369,6 @@ static void AddNodeIDValueTypes(FoldingSetNodeID &ID, SDVTList VTList) {
|
||||
}
|
||||
|
||||
/// AddNodeIDOperands - Various routines for adding operands to the NodeID data.
|
||||
///
|
||||
static void AddNodeIDOperands(FoldingSetNodeID &ID,
|
||||
ArrayRef<SDValue> Ops) {
|
||||
for (auto& Op : Ops) {
|
||||
@ -360,7 +378,6 @@ static void AddNodeIDOperands(FoldingSetNodeID &ID,
|
||||
}
|
||||
|
||||
/// AddNodeIDOperands - Various routines for adding operands to the NodeID data.
|
||||
///
|
||||
static void AddNodeIDOperands(FoldingSetNodeID &ID,
|
||||
ArrayRef<SDUse> Ops) {
|
||||
for (auto& Op : Ops) {
|
||||
@ -392,10 +409,9 @@ static void AddNodeIDCustom(FoldingSetNodeID &ID, const SDNode *N) {
|
||||
break;
|
||||
}
|
||||
case ISD::TargetConstantFP:
|
||||
case ISD::ConstantFP: {
|
||||
case ISD::ConstantFP:
|
||||
ID.AddPointer(cast<ConstantFPSDNode>(N)->getConstantFPValue());
|
||||
break;
|
||||
}
|
||||
case ISD::TargetGlobalAddress:
|
||||
case ISD::GlobalAddress:
|
||||
case ISD::TargetGlobalTLSAddress:
|
||||
@ -770,7 +786,6 @@ bool SelectionDAG::RemoveNodeFromCSEMaps(SDNode *N) {
|
||||
/// maps and modified in place. Add it back to the CSE maps, unless an identical
|
||||
/// node already exists, in which case transfer all its users to the existing
|
||||
/// node. This transfer can potentially trigger recursive merging.
|
||||
///
|
||||
void
|
||||
SelectionDAG::AddModifiedNodeToCSEMaps(SDNode *N) {
|
||||
// For node types that aren't CSE'd, just act as if no identical node
|
||||
@ -835,7 +850,6 @@ SDNode *SelectionDAG::FindModifiedNodeSlot(SDNode *N,
|
||||
return Node;
|
||||
}
|
||||
|
||||
|
||||
/// FindModifiedNodeSlot - Find a slot for the specified node if its operands
|
||||
/// were replaced with those specified. If this node is never memoized,
|
||||
/// return null, otherwise return a pointer to the slot it would take. If a
|
||||
@ -864,10 +878,9 @@ unsigned SelectionDAG::getEVTAlignment(EVT VT) const {
|
||||
|
||||
// EntryNode could meaningfully have debug info if we can find it...
|
||||
SelectionDAG::SelectionDAG(const TargetMachine &tm, CodeGenOpt::Level OL)
|
||||
: TM(tm), TSI(nullptr), TLI(nullptr), OptLevel(OL),
|
||||
: TM(tm), OptLevel(OL),
|
||||
EntryNode(ISD::EntryToken, 0, DebugLoc(), getVTList(MVT::Other)),
|
||||
Root(getEntryNode()), NewNodesMustHaveLegalTypes(false),
|
||||
UpdateListeners(nullptr) {
|
||||
Root(getEntryNode()) {
|
||||
InsertNode(&EntryNode);
|
||||
DbgInfo = new SDDbgInfo();
|
||||
}
|
||||
@ -1038,7 +1051,6 @@ SDValue SelectionDAG::getZeroExtendVectorInReg(SDValue Op, const SDLoc &DL,
|
||||
}
|
||||
|
||||
/// getNOT - Create a bitwise NOT operation as (XOR Val, -1).
|
||||
///
|
||||
SDValue SelectionDAG::getNOT(const SDLoc &DL, SDValue Val, EVT VT) {
|
||||
EVT EltVT = VT.getScalarType();
|
||||
SDValue NegOne =
|
||||
@ -1317,7 +1329,6 @@ SDValue SelectionDAG::getConstantPool(const Constant *C, EVT VT,
|
||||
return SDValue(N, 0);
|
||||
}
|
||||
|
||||
|
||||
SDValue SelectionDAG::getConstantPool(MachineConstantPoolValue *C, EVT VT,
|
||||
unsigned Alignment, int Offset,
|
||||
bool isTarget,
|
||||
@ -1451,7 +1462,7 @@ SDValue SelectionDAG::getVectorShuffle(EVT VT, const SDLoc &dl, SDValue N1,
|
||||
// Validate that all indices in Mask are within the range of the elements
|
||||
// input to the shuffle.
|
||||
int NElts = Mask.size();
|
||||
assert(all_of(Mask, [&](int M) { return M < (NElts * 2); }) &&
|
||||
assert(llvm::all_of(Mask, [&](int M) { return M < (NElts * 2); }) &&
|
||||
"Index out of range");
|
||||
|
||||
// Copy the mask so we can do any needed cleanup.
|
||||
@ -2918,7 +2929,7 @@ unsigned SelectionDAG::ComputeNumSignBits(SDValue Op, const APInt &DemandedElts,
|
||||
else
|
||||
DemandedRHS.setBit((unsigned)M % NumElts);
|
||||
}
|
||||
Tmp = UINT_MAX;
|
||||
Tmp = std::numeric_limits<unsigned>::max();
|
||||
if (!!DemandedLHS)
|
||||
Tmp = ComputeNumSignBits(Op.getOperand(0), DemandedLHS, Depth + 1);
|
||||
if (!!DemandedRHS) {
|
||||
@ -3122,7 +3133,7 @@ unsigned SelectionDAG::ComputeNumSignBits(SDValue Op, const APInt &DemandedElts,
|
||||
unsigned EltIdx = CEltNo->getZExtValue();
|
||||
|
||||
// If we demand the inserted element then get its sign bits.
|
||||
Tmp = UINT_MAX;
|
||||
Tmp = std::numeric_limits<unsigned>::max();
|
||||
if (DemandedElts[EltIdx]) {
|
||||
// TODO - handle implicit truncation of inserted elements.
|
||||
if (InVal.getScalarValueSizeInBits() != VTBits)
|
||||
@ -3188,7 +3199,7 @@ unsigned SelectionDAG::ComputeNumSignBits(SDValue Op, const APInt &DemandedElts,
|
||||
case ISD::CONCAT_VECTORS:
|
||||
// Determine the minimum number of sign bits across all demanded
|
||||
// elts of the input vectors. Early out if the result is already 1.
|
||||
Tmp = UINT_MAX;
|
||||
Tmp = std::numeric_limits<unsigned>::max();
|
||||
EVT SubVectorVT = Op.getOperand(0).getValueType();
|
||||
unsigned NumSubVectorElts = SubVectorVT.getVectorNumElements();
|
||||
unsigned NumSubVectors = Op.getNumOperands();
|
||||
@ -3327,7 +3338,7 @@ bool SelectionDAG::haveNoCommonBitsSet(SDValue A, SDValue B) const {
|
||||
|
||||
static SDValue FoldCONCAT_VECTORS(const SDLoc &DL, EVT VT,
|
||||
ArrayRef<SDValue> Ops,
|
||||
llvm::SelectionDAG &DAG) {
|
||||
SelectionDAG &DAG) {
|
||||
assert(!Ops.empty() && "Can't concatenate an empty list of vectors!");
|
||||
assert(llvm::all_of(Ops,
|
||||
[Ops](SDValue Op) {
|
||||
@ -3836,8 +3847,9 @@ bool SelectionDAG::isUndef(unsigned Opcode, ArrayRef<SDValue> Ops) {
|
||||
return true;
|
||||
|
||||
return ISD::isBuildVectorOfConstantSDNodes(Divisor.getNode()) &&
|
||||
any_of(Divisor->op_values(),
|
||||
[](SDValue V) { return V.isUndef() || isNullConstant(V); });
|
||||
llvm::any_of(Divisor->op_values(),
|
||||
[](SDValue V) { return V.isUndef() ||
|
||||
isNullConstant(V); });
|
||||
// TODO: Handle signed overflow.
|
||||
}
|
||||
// TODO: Handle oversized shifts.
|
||||
@ -3948,8 +3960,8 @@ SDValue SelectionDAG::FoldConstantVectorArithmetic(unsigned Opcode,
|
||||
// All operands must be vector types with the same number of elements as
|
||||
// the result type and must be either UNDEF or a build vector of constant
|
||||
// or UNDEF scalars.
|
||||
if (!all_of(Ops, IsConstantBuildVectorOrUndef) ||
|
||||
!all_of(Ops, IsScalarOrSameVectorSize))
|
||||
if (!llvm::all_of(Ops, IsConstantBuildVectorOrUndef) ||
|
||||
!llvm::all_of(Ops, IsScalarOrSameVectorSize))
|
||||
return SDValue();
|
||||
|
||||
// If we are comparing vectors, then the result needs to be a i1 boolean
|
||||
@ -5550,7 +5562,7 @@ SDValue SelectionDAG::getMemIntrinsicNode(unsigned Opcode, const SDLoc &dl,
|
||||
Opcode == ISD::PREFETCH ||
|
||||
Opcode == ISD::LIFETIME_START ||
|
||||
Opcode == ISD::LIFETIME_END ||
|
||||
(Opcode <= INT_MAX &&
|
||||
((int)Opcode <= std::numeric_limits<int>::max() &&
|
||||
(int)Opcode >= ISD::FIRST_TARGET_MEMORY_OPCODE)) &&
|
||||
"Opcode is not a memory-accessing opcode!");
|
||||
|
||||
@ -5884,7 +5896,6 @@ SDValue SelectionDAG::getMaskedLoad(EVT VT, const SDLoc &dl, SDValue Chain,
|
||||
SDValue Ptr, SDValue Mask, SDValue Src0,
|
||||
EVT MemVT, MachineMemOperand *MMO,
|
||||
ISD::LoadExtType ExtTy, bool isExpanding) {
|
||||
|
||||
SDVTList VTs = getVTList(VT, MVT::Other);
|
||||
SDValue Ops[] = { Chain, Ptr, Mask, Src0 };
|
||||
FoldingSetNodeID ID;
|
||||
@ -6038,13 +6049,12 @@ SDValue SelectionDAG::getNode(unsigned Opcode, const SDLoc &DL, EVT VT,
|
||||
|
||||
switch (Opcode) {
|
||||
default: break;
|
||||
case ISD::CONCAT_VECTORS: {
|
||||
case ISD::CONCAT_VECTORS:
|
||||
// Attempt to fold CONCAT_VECTORS into BUILD_VECTOR or UNDEF.
|
||||
if (SDValue V = FoldCONCAT_VECTORS(DL, VT, Ops, *this))
|
||||
return V;
|
||||
break;
|
||||
}
|
||||
case ISD::SELECT_CC: {
|
||||
case ISD::SELECT_CC:
|
||||
assert(NumOps == 5 && "SELECT_CC takes 5 operands!");
|
||||
assert(Ops[0].getValueType() == Ops[1].getValueType() &&
|
||||
"LHS and RHS of condition must have same type!");
|
||||
@ -6053,14 +6063,12 @@ SDValue SelectionDAG::getNode(unsigned Opcode, const SDLoc &DL, EVT VT,
|
||||
assert(Ops[2].getValueType() == VT &&
|
||||
"select_cc node must be of same type as true and false value!");
|
||||
break;
|
||||
}
|
||||
case ISD::BR_CC: {
|
||||
case ISD::BR_CC:
|
||||
assert(NumOps == 5 && "BR_CC takes 5 operands!");
|
||||
assert(Ops[2].getValueType() == Ops[3].getValueType() &&
|
||||
"LHS/RHS of comparison should match types!");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Memoize nodes.
|
||||
SDNode *N;
|
||||
@ -6599,7 +6607,6 @@ SDNode* SelectionDAG::mutateStrictFPToFP(SDNode *Node) {
|
||||
return Res;
|
||||
}
|
||||
|
||||
|
||||
/// getMachineNode - These are used for target selectors to create a new node
|
||||
/// with specified return type(s), MachineInstr opcode, and operands.
|
||||
///
|
||||
@ -6812,7 +6819,7 @@ public:
|
||||
: SelectionDAG::DAGUpdateListener(d), UI(ui), UE(ue) {}
|
||||
};
|
||||
|
||||
}
|
||||
} // end anonymous namespace
|
||||
|
||||
/// ReplaceAllUsesWith - Modify anything using 'From' to use 'To' instead.
|
||||
/// This can cause recursive merging of nodes in the DAG.
|
||||
@ -6858,7 +6865,6 @@ void SelectionDAG::ReplaceAllUsesWith(SDValue FromN, SDValue To) {
|
||||
AddModifiedNodeToCSEMaps(User);
|
||||
}
|
||||
|
||||
|
||||
// If we just RAUW'd the root, take note.
|
||||
if (FromN == getRoot())
|
||||
setRoot(To);
|
||||
@ -7028,6 +7034,7 @@ void SelectionDAG::ReplaceAllUsesOfValueWith(SDValue From, SDValue To){
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
/// UseMemo - This class is used by SelectionDAG::ReplaceAllUsesOfValuesWith
|
||||
/// to record information about a use.
|
||||
struct UseMemo {
|
||||
@ -7040,7 +7047,8 @@ namespace {
|
||||
bool operator<(const UseMemo &L, const UseMemo &R) {
|
||||
return (intptr_t)L.User < (intptr_t)R.User;
|
||||
}
|
||||
}
|
||||
|
||||
} // end anonymous namespace
|
||||
|
||||
/// ReplaceAllUsesOfValuesWith - Replace any uses of From with To, leaving
|
||||
/// uses of other values produced by From.getNode() alone. The same value
|
||||
@ -7106,7 +7114,6 @@ void SelectionDAG::ReplaceAllUsesOfValuesWith(const SDValue *From,
|
||||
/// based on their topological order. It returns the maximum id and a vector
|
||||
/// of the SDNodes* in assigned order by reference.
|
||||
unsigned SelectionDAG::AssignTopologicalOrder() {
|
||||
|
||||
unsigned DAGSize = 0;
|
||||
|
||||
// SortedPos tracks the progress of the algorithm. Nodes before it are
|
||||
@ -7333,6 +7340,7 @@ void SDNode::Profile(FoldingSetNodeID &ID) const {
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
struct EVTArray {
|
||||
std::vector<EVT> VTs;
|
||||
|
||||
@ -7342,11 +7350,12 @@ namespace {
|
||||
VTs.push_back(MVT((MVT::SimpleValueType)i));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static ManagedStatic<std::set<EVT, EVT::compareRawBits> > EVTs;
|
||||
} // end anonymous namespace
|
||||
|
||||
static ManagedStatic<std::set<EVT, EVT::compareRawBits>> EVTs;
|
||||
static ManagedStatic<EVTArray> SimpleVTArray;
|
||||
static ManagedStatic<sys::SmartMutex<true> > VTMutex;
|
||||
static ManagedStatic<sys::SmartMutex<true>> VTMutex;
|
||||
|
||||
/// getValueTypeList - Return a pointer to the specified value type.
|
||||
///
|
||||
@ -7380,7 +7389,6 @@ bool SDNode::hasNUsesOfValue(unsigned NUses, unsigned Value) const {
|
||||
return NUses == 0;
|
||||
}
|
||||
|
||||
|
||||
/// hasAnyUseOfValue - Return true if there are any use of the indicated
|
||||
/// value. This method ignores uses of other values defined by this operation.
|
||||
bool SDNode::hasAnyUseOfValue(unsigned Value) const {
|
||||
@ -7393,9 +7401,7 @@ bool SDNode::hasAnyUseOfValue(unsigned Value) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/// isOnlyUserOf - Return true if this node is the only use of N.
|
||||
///
|
||||
bool SDNode::isOnlyUserOf(const SDNode *N) const {
|
||||
bool Seen = false;
|
||||
for (SDNode::use_iterator I = N->use_begin(), E = N->use_end(); I != E; ++I) {
|
||||
@ -7425,7 +7431,6 @@ bool SDNode::areOnlyUsersOf(ArrayRef<const SDNode *> Nodes, const SDNode *N) {
|
||||
}
|
||||
|
||||
/// isOperand - Return true if this node is an operand of N.
|
||||
///
|
||||
bool SDValue::isOperandOf(const SDNode *N) const {
|
||||
for (const SDValue &Op : N->op_values())
|
||||
if (*this == Op)
|
||||
@ -7475,7 +7480,7 @@ bool SDValue::reachesChainWithoutSideEffects(SDValue Dest,
|
||||
}
|
||||
// Next, try a deep search: check whether every operand of the TokenFactor
|
||||
// reaches Dest.
|
||||
return all_of((*this)->ops(), [=](SDValue Op) {
|
||||
return llvm::all_of((*this)->ops(), [=](SDValue Op) {
|
||||
return Op.reachesChainWithoutSideEffects(Dest, Depth - 1);
|
||||
});
|
||||
}
|
||||
@ -7627,7 +7632,6 @@ bool SelectionDAG::areNonVolatileConsecutiveLoads(LoadSDNode *LD,
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/// InferPtrAlignment - Infer alignment of a load / store address. Return 0 if
|
||||
/// it cannot be inferred.
|
||||
unsigned SelectionDAG::InferPtrAlignment(SDValue Ptr) const {
|
||||
@ -7718,7 +7722,6 @@ unsigned GlobalAddressSDNode::getAddressSpace() const {
|
||||
return getGlobal()->getType()->getAddressSpace();
|
||||
}
|
||||
|
||||
|
||||
Type *ConstantPoolSDNode::getType() const {
|
||||
if (isMachineConstantPoolEntry())
|
||||
return Val.MachineCPVal->getType();
|
||||
|
@ -2022,7 +2022,7 @@ static SDNode *findGlueUse(SDNode *N) {
|
||||
}
|
||||
|
||||
/// findNonImmUse - Return true if "Use" is a non-immediate use of "Def".
|
||||
/// This function recursively traverses up the operand chain, ignoring
|
||||
/// This function iteratively traverses up the operand chain, ignoring
|
||||
/// certain nodes.
|
||||
static bool findNonImmUse(SDNode *Use, SDNode* Def, SDNode *ImmedUse,
|
||||
SDNode *Root, SmallPtrSetImpl<SDNode*> &Visited,
|
||||
@ -2035,30 +2035,36 @@ static bool findNonImmUse(SDNode *Use, SDNode* Def, SDNode *ImmedUse,
|
||||
// The Use may be -1 (unassigned) if it is a newly allocated node. This can
|
||||
// happen because we scan down to newly selected nodes in the case of glue
|
||||
// uses.
|
||||
if ((Use->getNodeId() < Def->getNodeId() && Use->getNodeId() != -1))
|
||||
return false;
|
||||
std::vector<SDNode *> WorkList;
|
||||
WorkList.push_back(Use);
|
||||
|
||||
// Don't revisit nodes if we already scanned it and didn't fail, we know we
|
||||
// won't fail if we scan it again.
|
||||
if (!Visited.insert(Use).second)
|
||||
return false;
|
||||
|
||||
for (const SDValue &Op : Use->op_values()) {
|
||||
// Ignore chain uses, they are validated by HandleMergeInputChains.
|
||||
if (Op.getValueType() == MVT::Other && IgnoreChains)
|
||||
while (!WorkList.empty()) {
|
||||
Use = WorkList.back();
|
||||
WorkList.pop_back();
|
||||
if (Use->getNodeId() < Def->getNodeId() && Use->getNodeId() != -1)
|
||||
continue;
|
||||
|
||||
SDNode *N = Op.getNode();
|
||||
if (N == Def) {
|
||||
if (Use == ImmedUse || Use == Root)
|
||||
continue; // We are not looking for immediate use.
|
||||
assert(N != Root);
|
||||
return true;
|
||||
}
|
||||
// Don't revisit nodes if we already scanned it and didn't fail, we know we
|
||||
// won't fail if we scan it again.
|
||||
if (!Visited.insert(Use).second)
|
||||
continue;
|
||||
|
||||
// Traverse up the operand chain.
|
||||
if (findNonImmUse(N, Def, ImmedUse, Root, Visited, IgnoreChains))
|
||||
return true;
|
||||
for (const SDValue &Op : Use->op_values()) {
|
||||
// Ignore chain uses, they are validated by HandleMergeInputChains.
|
||||
if (Op.getValueType() == MVT::Other && IgnoreChains)
|
||||
continue;
|
||||
|
||||
SDNode *N = Op.getNode();
|
||||
if (N == Def) {
|
||||
if (Use == ImmedUse || Use == Root)
|
||||
continue; // We are not looking for immediate use.
|
||||
assert(N != Root);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Traverse up the operand chain.
|
||||
WorkList.push_back(N);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -818,7 +818,7 @@ SelectionDAGBuilder::LowerStatepoint(ImmutableStatepoint ISP,
|
||||
SI.GCTransitionArgs =
|
||||
ArrayRef<const Use>(ISP.gc_args_begin(), ISP.gc_args_end());
|
||||
SI.ID = ISP.getID();
|
||||
SI.DeoptState = ArrayRef<const Use>(ISP.vm_state_begin(), ISP.vm_state_end());
|
||||
SI.DeoptState = ArrayRef<const Use>(ISP.deopt_begin(), ISP.deopt_end());
|
||||
SI.StatepointFlags = ISP.getFlags();
|
||||
SI.NumPatchBytes = ISP.getNumPatchBytes();
|
||||
SI.EHPadBB = EHPadBB;
|
||||
|
@ -1493,8 +1493,7 @@ SDValue TargetLowering::SimplifySetCC(EVT VT, SDValue N0, SDValue N1,
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure that the constant occurs on the RHS, and fold constant
|
||||
// comparisons.
|
||||
// Ensure that the constant occurs on the RHS and fold constant comparisons.
|
||||
ISD::CondCode SwappedCC = ISD::getSetCCSwappedOperands(Cond);
|
||||
if (isa<ConstantSDNode>(N0.getNode()) &&
|
||||
(DCI.isBeforeLegalizeOps() ||
|
||||
@ -1638,14 +1637,13 @@ SDValue TargetLowering::SimplifySetCC(EVT VT, SDValue N0, SDValue N1,
|
||||
return DAG.getSetCC(dl, VT, TopSetCC.getOperand(0),
|
||||
TopSetCC.getOperand(1),
|
||||
InvCond);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If the LHS is '(and load, const)', the RHS is 0,
|
||||
// the test is for equality or unsigned, and all 1 bits of the const are
|
||||
// in the same partial word, see if we can shorten the load.
|
||||
// If the LHS is '(and load, const)', the RHS is 0, the test is for
|
||||
// equality or unsigned, and all 1 bits of the const are in the same
|
||||
// partial word, see if we can shorten the load.
|
||||
if (DCI.isBeforeLegalize() &&
|
||||
!ISD::isSignedIntSetCC(Cond) &&
|
||||
N0.getOpcode() == ISD::AND && C1 == 0 &&
|
||||
@ -1669,10 +1667,10 @@ SDValue TargetLowering::SimplifySetCC(EVT VT, SDValue N0, SDValue N1,
|
||||
APInt newMask = APInt::getLowBitsSet(maskWidth, width);
|
||||
for (unsigned offset=0; offset<origWidth/width; offset++) {
|
||||
if ((newMask & Mask) == Mask) {
|
||||
if (!DAG.getDataLayout().isLittleEndian())
|
||||
bestOffset = (origWidth/width - offset - 1) * (width/8);
|
||||
else
|
||||
if (DAG.getDataLayout().isLittleEndian())
|
||||
bestOffset = (uint64_t)offset * (width/8);
|
||||
else
|
||||
bestOffset = (origWidth/width - offset - 1) * (width/8);
|
||||
bestMask = Mask.lshr(offset * (width/8) * 8);
|
||||
bestWidth = width;
|
||||
break;
|
||||
@ -1713,10 +1711,12 @@ SDValue TargetLowering::SimplifySetCC(EVT VT, SDValue N0, SDValue N1,
|
||||
switch (Cond) {
|
||||
case ISD::SETUGT:
|
||||
case ISD::SETUGE:
|
||||
case ISD::SETEQ: return DAG.getConstant(0, dl, VT);
|
||||
case ISD::SETEQ:
|
||||
return DAG.getConstant(0, dl, VT);
|
||||
case ISD::SETULT:
|
||||
case ISD::SETULE:
|
||||
case ISD::SETNE: return DAG.getConstant(1, dl, VT);
|
||||
case ISD::SETNE:
|
||||
return DAG.getConstant(1, dl, VT);
|
||||
case ISD::SETGT:
|
||||
case ISD::SETGE:
|
||||
// True if the sign bit of C1 is set.
|
||||
@ -1816,9 +1816,9 @@ SDValue TargetLowering::SimplifySetCC(EVT VT, SDValue N0, SDValue N1,
|
||||
BitWidth-1))) {
|
||||
// Okay, get the un-inverted input value.
|
||||
SDValue Val;
|
||||
if (N0.getOpcode() == ISD::XOR)
|
||||
if (N0.getOpcode() == ISD::XOR) {
|
||||
Val = N0.getOperand(0);
|
||||
else {
|
||||
} else {
|
||||
assert(N0.getOpcode() == ISD::AND &&
|
||||
N0.getOperand(0).getOpcode() == ISD::XOR);
|
||||
// ((X^1)&1)^1 -> X & 1
|
||||
@ -1883,7 +1883,10 @@ SDValue TargetLowering::SimplifySetCC(EVT VT, SDValue N0, SDValue N1,
|
||||
|
||||
// Canonicalize GE/LE comparisons to use GT/LT comparisons.
|
||||
if (Cond == ISD::SETGE || Cond == ISD::SETUGE) {
|
||||
if (C1 == MinVal) return DAG.getConstant(1, dl, VT); // X >= MIN --> true
|
||||
// X >= MIN --> true
|
||||
if (C1 == MinVal)
|
||||
return DAG.getConstant(1, dl, VT);
|
||||
|
||||
// X >= C0 --> X > (C0 - 1)
|
||||
APInt C = C1 - 1;
|
||||
ISD::CondCode NewCC = (Cond == ISD::SETGE) ? ISD::SETGT : ISD::SETUGT;
|
||||
@ -1898,7 +1901,10 @@ SDValue TargetLowering::SimplifySetCC(EVT VT, SDValue N0, SDValue N1,
|
||||
}
|
||||
|
||||
if (Cond == ISD::SETLE || Cond == ISD::SETULE) {
|
||||
if (C1 == MaxVal) return DAG.getConstant(1, dl, VT); // X <= MAX --> true
|
||||
// X <= MAX --> true
|
||||
if (C1 == MaxVal)
|
||||
return DAG.getConstant(1, dl, VT);
|
||||
|
||||
// X <= C0 --> X < (C0 + 1)
|
||||
APInt C = C1 + 1;
|
||||
ISD::CondCode NewCC = (Cond == ISD::SETLE) ? ISD::SETLT : ISD::SETULT;
|
||||
|
@ -1456,6 +1456,7 @@ void TargetLoweringBase::computeRegisterProperties(
|
||||
}
|
||||
if (IsLegalWiderType)
|
||||
break;
|
||||
LLVM_FALLTHROUGH;
|
||||
}
|
||||
case TypeWidenVector: {
|
||||
// Try to widen the vector.
|
||||
@ -1473,6 +1474,7 @@ void TargetLoweringBase::computeRegisterProperties(
|
||||
}
|
||||
if (IsLegalWiderType)
|
||||
break;
|
||||
LLVM_FALLTHROUGH;
|
||||
}
|
||||
case TypeSplitVector:
|
||||
case TypeScalarizeVector: {
|
||||
|
@ -27,6 +27,14 @@ Error CodeViewRecordIO::beginRecord(Optional<uint32_t> MaxLength) {
|
||||
Error CodeViewRecordIO::endRecord() {
|
||||
assert(!Limits.empty() && "Not in a record!");
|
||||
Limits.pop_back();
|
||||
// We would like to assert that we actually read / wrote all the bytes that we
|
||||
// expected to for this record, but unfortunately we can't do this. Some
|
||||
// producers such as MASM over-allocate for certain types of records and
|
||||
// commit the extraneous data, so when reading we can't be sure every byte
|
||||
// will have been read. And when writing we over-allocate temporarily since
|
||||
// we don't know how big the record is until we're finished writing it, so
|
||||
// even though we don't commit the extraneous data, we still can't guarantee
|
||||
// we're at the end of the allocated data.
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
@ -49,6 +57,12 @@ uint32_t CodeViewRecordIO::maxFieldLength() const {
|
||||
return *Min;
|
||||
}
|
||||
|
||||
Error CodeViewRecordIO::padToAlignment(uint32_t Align) {
|
||||
if (isReading())
|
||||
return Reader->padToAlignment(Align);
|
||||
return Writer->padToAlignment(Align);
|
||||
}
|
||||
|
||||
Error CodeViewRecordIO::skipPadding() {
|
||||
assert(!isWriting() && "Cannot skip padding while writing!");
|
||||
|
||||
|
@ -72,7 +72,7 @@ Error DebugStringTableSubsection::commit(BinaryStreamWriter &Writer) const {
|
||||
uint32_t DebugStringTableSubsection::size() const { return Strings.size(); }
|
||||
|
||||
uint32_t DebugStringTableSubsection::getStringId(StringRef S) const {
|
||||
auto P = Strings.find(S);
|
||||
assert(P != Strings.end());
|
||||
return P->second;
|
||||
auto Iter = Strings.find(S);
|
||||
assert(Iter != Strings.end());
|
||||
return Iter->second;
|
||||
}
|
||||
|
@ -16,14 +16,17 @@ using namespace llvm;
|
||||
using namespace llvm::codeview;
|
||||
|
||||
DebugSubsectionRecord::DebugSubsectionRecord()
|
||||
: Kind(DebugSubsectionKind::None) {}
|
||||
: Container(CodeViewContainer::ObjectFile),
|
||||
Kind(DebugSubsectionKind::None) {}
|
||||
|
||||
DebugSubsectionRecord::DebugSubsectionRecord(DebugSubsectionKind Kind,
|
||||
BinaryStreamRef Data)
|
||||
: Kind(Kind), Data(Data) {}
|
||||
BinaryStreamRef Data,
|
||||
CodeViewContainer Container)
|
||||
: Container(Container), Kind(Kind), Data(Data) {}
|
||||
|
||||
Error DebugSubsectionRecord::initialize(BinaryStreamRef Stream,
|
||||
DebugSubsectionRecord &Info) {
|
||||
DebugSubsectionRecord &Info,
|
||||
CodeViewContainer Container) {
|
||||
const DebugSubsectionHeader *Header;
|
||||
BinaryStreamReader Reader(Stream);
|
||||
if (auto EC = Reader.readObject(Header))
|
||||
@ -41,13 +44,14 @@ Error DebugSubsectionRecord::initialize(BinaryStreamRef Stream,
|
||||
}
|
||||
if (auto EC = Reader.readStreamRef(Info.Data, Header->Length))
|
||||
return EC;
|
||||
Info.Container = Container;
|
||||
Info.Kind = Kind;
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
uint32_t DebugSubsectionRecord::getRecordLength() const {
|
||||
uint32_t Result = sizeof(DebugSubsectionHeader) + Data.getLength();
|
||||
assert(Result % 4 == 0);
|
||||
assert(Result % alignOf(Container) == 0);
|
||||
return Result;
|
||||
}
|
||||
|
||||
@ -56,25 +60,29 @@ DebugSubsectionKind DebugSubsectionRecord::kind() const { return Kind; }
|
||||
BinaryStreamRef DebugSubsectionRecord::getRecordData() const { return Data; }
|
||||
|
||||
DebugSubsectionRecordBuilder::DebugSubsectionRecordBuilder(
|
||||
DebugSubsectionKind Kind, DebugSubsection &Frag)
|
||||
: Kind(Kind), Frag(Frag) {}
|
||||
std::unique_ptr<DebugSubsection> Subsection, CodeViewContainer Container)
|
||||
: Subsection(std::move(Subsection)), Container(Container) {}
|
||||
|
||||
uint32_t DebugSubsectionRecordBuilder::calculateSerializedLength() {
|
||||
uint32_t Size = sizeof(DebugSubsectionHeader) +
|
||||
alignTo(Frag.calculateSerializedSize(), 4);
|
||||
uint32_t Size =
|
||||
sizeof(DebugSubsectionHeader) +
|
||||
alignTo(Subsection->calculateSerializedSize(), alignOf(Container));
|
||||
return Size;
|
||||
}
|
||||
|
||||
Error DebugSubsectionRecordBuilder::commit(BinaryStreamWriter &Writer) {
|
||||
assert(Writer.getOffset() % alignOf(Container) == 0 &&
|
||||
"Debug Subsection not properly aligned");
|
||||
|
||||
DebugSubsectionHeader Header;
|
||||
Header.Kind = uint32_t(Kind);
|
||||
Header.Kind = uint32_t(Subsection->kind());
|
||||
Header.Length = calculateSerializedLength() - sizeof(DebugSubsectionHeader);
|
||||
|
||||
if (auto EC = Writer.writeObject(Header))
|
||||
return EC;
|
||||
if (auto EC = Frag.commit(Writer))
|
||||
if (auto EC = Subsection->commit(Writer))
|
||||
return EC;
|
||||
if (auto EC = Writer.padToAlignment(4))
|
||||
if (auto EC = Writer.padToAlignment(alignOf(Container)))
|
||||
return EC;
|
||||
|
||||
return Error::success();
|
||||
|
@ -668,7 +668,7 @@ Error CVSymbolDumperImpl::visitUnknownSymbol(CVSymbol &CVR) {
|
||||
|
||||
Error CVSymbolDumper::dump(CVRecord<SymbolKind> &Record) {
|
||||
SymbolVisitorCallbackPipeline Pipeline;
|
||||
SymbolDeserializer Deserializer(ObjDelegate.get());
|
||||
SymbolDeserializer Deserializer(ObjDelegate.get(), Container);
|
||||
CVSymbolDumperImpl Dumper(Types, ObjDelegate.get(), W, PrintRecordBytes);
|
||||
|
||||
Pipeline.addCallbackToPipeline(Deserializer);
|
||||
@ -679,7 +679,7 @@ Error CVSymbolDumper::dump(CVRecord<SymbolKind> &Record) {
|
||||
|
||||
Error CVSymbolDumper::dump(const CVSymbolArray &Symbols) {
|
||||
SymbolVisitorCallbackPipeline Pipeline;
|
||||
SymbolDeserializer Deserializer(ObjDelegate.get());
|
||||
SymbolDeserializer Deserializer(ObjDelegate.get(), Container);
|
||||
CVSymbolDumperImpl Dumper(Types, ObjDelegate.get(), W, PrintRecordBytes);
|
||||
|
||||
Pipeline.addCallbackToPipeline(Deserializer);
|
||||
|
@ -40,6 +40,7 @@ Error SymbolRecordMapping::visitSymbolBegin(CVSymbol &Record) {
|
||||
}
|
||||
|
||||
Error SymbolRecordMapping::visitSymbolEnd(CVSymbol &Record) {
|
||||
error(IO.padToAlignment(alignOf(Container)));
|
||||
error(IO.endRecord());
|
||||
return Error::success();
|
||||
}
|
||||
|
@ -12,9 +12,11 @@
|
||||
using namespace llvm;
|
||||
using namespace llvm::codeview;
|
||||
|
||||
SymbolSerializer::SymbolSerializer(BumpPtrAllocator &Allocator)
|
||||
: Storage(Allocator), RecordBuffer(MaxRecordLength), Stream(RecordBuffer, llvm::support::little),
|
||||
Writer(Stream), Mapping(Writer) { }
|
||||
SymbolSerializer::SymbolSerializer(BumpPtrAllocator &Allocator,
|
||||
CodeViewContainer Container)
|
||||
: Storage(Allocator), RecordBuffer(MaxRecordLength),
|
||||
Stream(RecordBuffer, llvm::support::little), Writer(Stream),
|
||||
Mapping(Writer, Container) {}
|
||||
|
||||
Error SymbolSerializer::visitSymbolBegin(CVSymbol &Record) {
|
||||
assert(!CurrentSymbol.hasValue() && "Already in a symbol mapping!");
|
||||
|
@ -47,42 +47,46 @@ static Interval intersect(const Interval &I1, const Interval &I2) {
|
||||
|
||||
MappedBlockStream::MappedBlockStream(uint32_t BlockSize,
|
||||
const MSFStreamLayout &Layout,
|
||||
BinaryStreamRef MsfData)
|
||||
: BlockSize(BlockSize), StreamLayout(Layout), MsfData(MsfData) {}
|
||||
BinaryStreamRef MsfData,
|
||||
BumpPtrAllocator &Allocator)
|
||||
: BlockSize(BlockSize), StreamLayout(Layout), MsfData(MsfData),
|
||||
Allocator(Allocator) {}
|
||||
|
||||
std::unique_ptr<MappedBlockStream>
|
||||
MappedBlockStream::createStream(uint32_t BlockSize,
|
||||
const MSFStreamLayout &Layout,
|
||||
BinaryStreamRef MsfData) {
|
||||
std::unique_ptr<MappedBlockStream> MappedBlockStream::createStream(
|
||||
uint32_t BlockSize, const MSFStreamLayout &Layout, BinaryStreamRef MsfData,
|
||||
BumpPtrAllocator &Allocator) {
|
||||
return llvm::make_unique<MappedBlockStreamImpl<MappedBlockStream>>(
|
||||
BlockSize, Layout, MsfData);
|
||||
BlockSize, Layout, MsfData, Allocator);
|
||||
}
|
||||
|
||||
std::unique_ptr<MappedBlockStream> MappedBlockStream::createIndexedStream(
|
||||
const MSFLayout &Layout, BinaryStreamRef MsfData, uint32_t StreamIndex) {
|
||||
const MSFLayout &Layout, BinaryStreamRef MsfData, uint32_t StreamIndex,
|
||||
BumpPtrAllocator &Allocator) {
|
||||
assert(StreamIndex < Layout.StreamMap.size() && "Invalid stream index");
|
||||
MSFStreamLayout SL;
|
||||
SL.Blocks = Layout.StreamMap[StreamIndex];
|
||||
SL.Length = Layout.StreamSizes[StreamIndex];
|
||||
return llvm::make_unique<MappedBlockStreamImpl<MappedBlockStream>>(
|
||||
Layout.SB->BlockSize, SL, MsfData);
|
||||
Layout.SB->BlockSize, SL, MsfData, Allocator);
|
||||
}
|
||||
|
||||
std::unique_ptr<MappedBlockStream>
|
||||
MappedBlockStream::createDirectoryStream(const MSFLayout &Layout,
|
||||
BinaryStreamRef MsfData) {
|
||||
BinaryStreamRef MsfData,
|
||||
BumpPtrAllocator &Allocator) {
|
||||
MSFStreamLayout SL;
|
||||
SL.Blocks = Layout.DirectoryBlocks;
|
||||
SL.Length = Layout.SB->NumDirectoryBytes;
|
||||
return createStream(Layout.SB->BlockSize, SL, MsfData);
|
||||
return createStream(Layout.SB->BlockSize, SL, MsfData, Allocator);
|
||||
}
|
||||
|
||||
std::unique_ptr<MappedBlockStream>
|
||||
MappedBlockStream::createFpmStream(const MSFLayout &Layout,
|
||||
BinaryStreamRef MsfData) {
|
||||
BinaryStreamRef MsfData,
|
||||
BumpPtrAllocator &Allocator) {
|
||||
MSFStreamLayout SL;
|
||||
initializeFpmStreamLayout(Layout, SL);
|
||||
return createStream(Layout.SB->BlockSize, SL, MsfData);
|
||||
return createStream(Layout.SB->BlockSize, SL, MsfData, Allocator);
|
||||
}
|
||||
|
||||
Error MappedBlockStream::readBytes(uint32_t Offset, uint32_t Size,
|
||||
@ -148,7 +152,7 @@ Error MappedBlockStream::readBytes(uint32_t Offset, uint32_t Size,
|
||||
// into it, and return an ArrayRef to that. Do not touch existing pool
|
||||
// allocations, as existing clients may be holding a pointer which must
|
||||
// not be invalidated.
|
||||
uint8_t *WriteBuffer = static_cast<uint8_t *>(Pool.Allocate(Size, 8));
|
||||
uint8_t *WriteBuffer = static_cast<uint8_t *>(Allocator.Allocate(Size, 8));
|
||||
if (auto EC = readBytes(Offset, MutableArrayRef<uint8_t>(WriteBuffer, Size)))
|
||||
return EC;
|
||||
|
||||
@ -269,10 +273,6 @@ Error MappedBlockStream::readBytes(uint32_t Offset,
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
uint32_t MappedBlockStream::getNumBytesCopied() const {
|
||||
return static_cast<uint32_t>(Pool.getBytesAllocated());
|
||||
}
|
||||
|
||||
void MappedBlockStream::invalidateCache() { CacheMap.shrink_and_clear(); }
|
||||
|
||||
void MappedBlockStream::fixCacheAfterWrite(uint32_t Offset,
|
||||
@ -313,43 +313,48 @@ void MappedBlockStream::fixCacheAfterWrite(uint32_t Offset,
|
||||
|
||||
WritableMappedBlockStream::WritableMappedBlockStream(
|
||||
uint32_t BlockSize, const MSFStreamLayout &Layout,
|
||||
WritableBinaryStreamRef MsfData)
|
||||
: ReadInterface(BlockSize, Layout, MsfData), WriteInterface(MsfData) {}
|
||||
WritableBinaryStreamRef MsfData, BumpPtrAllocator &Allocator)
|
||||
: ReadInterface(BlockSize, Layout, MsfData, Allocator),
|
||||
WriteInterface(MsfData) {}
|
||||
|
||||
std::unique_ptr<WritableMappedBlockStream>
|
||||
WritableMappedBlockStream::createStream(uint32_t BlockSize,
|
||||
const MSFStreamLayout &Layout,
|
||||
WritableBinaryStreamRef MsfData) {
|
||||
WritableBinaryStreamRef MsfData,
|
||||
BumpPtrAllocator &Allocator) {
|
||||
return llvm::make_unique<MappedBlockStreamImpl<WritableMappedBlockStream>>(
|
||||
BlockSize, Layout, MsfData);
|
||||
BlockSize, Layout, MsfData, Allocator);
|
||||
}
|
||||
|
||||
std::unique_ptr<WritableMappedBlockStream>
|
||||
WritableMappedBlockStream::createIndexedStream(const MSFLayout &Layout,
|
||||
WritableBinaryStreamRef MsfData,
|
||||
uint32_t StreamIndex) {
|
||||
uint32_t StreamIndex,
|
||||
BumpPtrAllocator &Allocator) {
|
||||
assert(StreamIndex < Layout.StreamMap.size() && "Invalid stream index");
|
||||
MSFStreamLayout SL;
|
||||
SL.Blocks = Layout.StreamMap[StreamIndex];
|
||||
SL.Length = Layout.StreamSizes[StreamIndex];
|
||||
return createStream(Layout.SB->BlockSize, SL, MsfData);
|
||||
return createStream(Layout.SB->BlockSize, SL, MsfData, Allocator);
|
||||
}
|
||||
|
||||
std::unique_ptr<WritableMappedBlockStream>
|
||||
WritableMappedBlockStream::createDirectoryStream(
|
||||
const MSFLayout &Layout, WritableBinaryStreamRef MsfData) {
|
||||
const MSFLayout &Layout, WritableBinaryStreamRef MsfData,
|
||||
BumpPtrAllocator &Allocator) {
|
||||
MSFStreamLayout SL;
|
||||
SL.Blocks = Layout.DirectoryBlocks;
|
||||
SL.Length = Layout.SB->NumDirectoryBytes;
|
||||
return createStream(Layout.SB->BlockSize, SL, MsfData);
|
||||
return createStream(Layout.SB->BlockSize, SL, MsfData, Allocator);
|
||||
}
|
||||
|
||||
std::unique_ptr<WritableMappedBlockStream>
|
||||
WritableMappedBlockStream::createFpmStream(const MSFLayout &Layout,
|
||||
WritableBinaryStreamRef MsfData) {
|
||||
WritableBinaryStreamRef MsfData,
|
||||
BumpPtrAllocator &Allocator) {
|
||||
MSFStreamLayout SL;
|
||||
initializeFpmStreamLayout(Layout, SL);
|
||||
return createStream(Layout.SB->BlockSize, SL, MsfData);
|
||||
return createStream(Layout.SB->BlockSize, SL, MsfData, Allocator);
|
||||
}
|
||||
|
||||
Error WritableMappedBlockStream::readBytes(uint32_t Offset, uint32_t Size,
|
||||
|
@ -66,7 +66,11 @@ void DbiModuleDescriptorBuilder::setObjFileName(StringRef Name) {
|
||||
|
||||
void DbiModuleDescriptorBuilder::addSymbol(CVSymbol Symbol) {
|
||||
Symbols.push_back(Symbol);
|
||||
SymbolByteSize += Symbol.data().size();
|
||||
// Symbols written to a PDB file are required to be 4 byte aligned. The same
|
||||
// is not true of object files.
|
||||
assert(Symbol.length() % alignOf(CodeViewContainer::Pdb) == 0 &&
|
||||
"Invalid Symbol alignment!");
|
||||
SymbolByteSize += Symbol.length();
|
||||
}
|
||||
|
||||
void DbiModuleDescriptorBuilder::addSourceFile(StringRef Path) {
|
||||
@ -140,7 +144,7 @@ Error DbiModuleDescriptorBuilder::commit(BinaryStreamWriter &ModiWriter,
|
||||
|
||||
if (Layout.ModDiStream != kInvalidStreamIndex) {
|
||||
auto NS = WritableMappedBlockStream::createIndexedStream(
|
||||
MsfLayout, MsfBuffer, Layout.ModDiStream);
|
||||
MsfLayout, MsfBuffer, Layout.ModDiStream, MSF.getAllocator());
|
||||
WritableBinaryStreamRef Ref(*NS);
|
||||
BinaryStreamWriter SymbolWriter(Ref);
|
||||
// Write the symbols.
|
||||
@ -153,7 +157,8 @@ Error DbiModuleDescriptorBuilder::commit(BinaryStreamWriter &ModiWriter,
|
||||
if (auto EC = SymbolWriter.writeStreamRef(RecordsRef))
|
||||
return EC;
|
||||
// TODO: Write C11 Line data
|
||||
|
||||
assert(SymbolWriter.getOffset() % alignOf(CodeViewContainer::Pdb) == 0 &&
|
||||
"Invalid debug section alignment!");
|
||||
for (const auto &Builder : C13Builders) {
|
||||
assert(Builder && "Empty C13 Fragment Builder!");
|
||||
if (auto EC = Builder->commit(SymbolWriter))
|
||||
@ -169,42 +174,9 @@ Error DbiModuleDescriptorBuilder::commit(BinaryStreamWriter &ModiWriter,
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
void DbiModuleDescriptorBuilder::addC13Fragment(
|
||||
std::unique_ptr<DebugLinesSubsection> Lines) {
|
||||
DebugLinesSubsection &Frag = *Lines;
|
||||
|
||||
// File Checksums have to come first, so push an empty entry on if this
|
||||
// is the first.
|
||||
if (C13Builders.empty())
|
||||
C13Builders.push_back(nullptr);
|
||||
|
||||
this->LineInfo.push_back(std::move(Lines));
|
||||
C13Builders.push_back(
|
||||
llvm::make_unique<DebugSubsectionRecordBuilder>(Frag.kind(), Frag));
|
||||
}
|
||||
|
||||
void DbiModuleDescriptorBuilder::addC13Fragment(
|
||||
std::unique_ptr<codeview::DebugInlineeLinesSubsection> Inlinees) {
|
||||
DebugInlineeLinesSubsection &Frag = *Inlinees;
|
||||
|
||||
// File Checksums have to come first, so push an empty entry on if this
|
||||
// is the first.
|
||||
if (C13Builders.empty())
|
||||
C13Builders.push_back(nullptr);
|
||||
|
||||
this->Inlinees.push_back(std::move(Inlinees));
|
||||
C13Builders.push_back(
|
||||
llvm::make_unique<DebugSubsectionRecordBuilder>(Frag.kind(), Frag));
|
||||
}
|
||||
|
||||
void DbiModuleDescriptorBuilder::setC13FileChecksums(
|
||||
std::unique_ptr<DebugChecksumsSubsection> Checksums) {
|
||||
assert(!ChecksumInfo && "Can't have more than one checksum info!");
|
||||
|
||||
if (C13Builders.empty())
|
||||
C13Builders.push_back(nullptr);
|
||||
|
||||
ChecksumInfo = std::move(Checksums);
|
||||
C13Builders[0] = llvm::make_unique<DebugSubsectionRecordBuilder>(
|
||||
ChecksumInfo->kind(), *ChecksumInfo);
|
||||
void DbiModuleDescriptorBuilder::addDebugSubsection(
|
||||
std::unique_ptr<DebugSubsection> Subsection) {
|
||||
assert(Subsection);
|
||||
C13Builders.push_back(llvm::make_unique<DebugSubsectionRecordBuilder>(
|
||||
std::move(Subsection), CodeViewContainer::Pdb));
|
||||
}
|
||||
|
@ -252,7 +252,7 @@ Error DbiStream::initializeSectionHeadersData() {
|
||||
return make_error<RawError>(raw_error_code::no_stream);
|
||||
|
||||
auto SHS = MappedBlockStream::createIndexedStream(
|
||||
Pdb.getMsfLayout(), Pdb.getMsfBuffer(), StreamNum);
|
||||
Pdb.getMsfLayout(), Pdb.getMsfBuffer(), StreamNum, Pdb.getAllocator());
|
||||
|
||||
size_t StreamLen = SHS->getLength();
|
||||
if (StreamLen % sizeof(object::coff_section))
|
||||
@ -284,7 +284,7 @@ Error DbiStream::initializeFpoRecords() {
|
||||
return make_error<RawError>(raw_error_code::no_stream);
|
||||
|
||||
auto FS = MappedBlockStream::createIndexedStream(
|
||||
Pdb.getMsfLayout(), Pdb.getMsfBuffer(), StreamNum);
|
||||
Pdb.getMsfLayout(), Pdb.getMsfBuffer(), StreamNum, Pdb.getAllocator());
|
||||
|
||||
size_t StreamLen = FS->getLength();
|
||||
if (StreamLen % sizeof(object::FpoData))
|
||||
|
@ -357,8 +357,8 @@ Error DbiStreamBuilder::commit(const msf::MSFLayout &Layout,
|
||||
if (auto EC = finalize())
|
||||
return EC;
|
||||
|
||||
auto DbiS = WritableMappedBlockStream::createIndexedStream(Layout, MsfBuffer,
|
||||
StreamDBI);
|
||||
auto DbiS = WritableMappedBlockStream::createIndexedStream(
|
||||
Layout, MsfBuffer, StreamDBI, Allocator);
|
||||
|
||||
BinaryStreamWriter Writer(*DbiS);
|
||||
if (auto EC = Writer.writeObject(*Header))
|
||||
@ -396,7 +396,7 @@ Error DbiStreamBuilder::commit(const msf::MSFLayout &Layout,
|
||||
if (Stream.StreamNumber == kInvalidStreamIndex)
|
||||
continue;
|
||||
auto WritableStream = WritableMappedBlockStream::createIndexedStream(
|
||||
Layout, MsfBuffer, Stream.StreamNumber);
|
||||
Layout, MsfBuffer, Stream.StreamNumber, Allocator);
|
||||
BinaryStreamWriter DbgStreamWriter(*WritableStream);
|
||||
if (auto EC = DbgStreamWriter.writeArray(Stream.Data))
|
||||
return EC;
|
||||
|
@ -50,8 +50,8 @@ Error InfoStreamBuilder::finalizeMsfLayout() {
|
||||
|
||||
Error InfoStreamBuilder::commit(const msf::MSFLayout &Layout,
|
||||
WritableBinaryStreamRef Buffer) const {
|
||||
auto InfoS =
|
||||
WritableMappedBlockStream::createIndexedStream(Layout, Buffer, StreamPDB);
|
||||
auto InfoS = WritableMappedBlockStream::createIndexedStream(
|
||||
Layout, Buffer, StreamPDB, Msf.getAllocator());
|
||||
BinaryStreamWriter Writer(*InfoS);
|
||||
|
||||
InfoStreamHeader H;
|
||||
|
@ -55,9 +55,9 @@ Error ModuleDebugStreamRef::reload() {
|
||||
if (auto EC = Reader.readStreamRef(C13LinesSubstream, C13Size))
|
||||
return EC;
|
||||
|
||||
BinaryStreamReader LineReader(C13LinesSubstream);
|
||||
if (auto EC =
|
||||
LineReader.readArray(LinesAndChecksums, LineReader.bytesRemaining()))
|
||||
BinaryStreamReader SubsectionsReader(C13LinesSubstream);
|
||||
if (auto EC = SubsectionsReader.readArray(Subsections,
|
||||
SubsectionsReader.bytesRemaining()))
|
||||
return EC;
|
||||
|
||||
uint32_t GlobalRefsSize;
|
||||
@ -77,13 +77,27 @@ ModuleDebugStreamRef::symbols(bool *HadError) const {
|
||||
return make_range(SymbolsSubstream.begin(HadError), SymbolsSubstream.end());
|
||||
}
|
||||
|
||||
llvm::iterator_range<ModuleDebugStreamRef::LinesAndChecksumsIterator>
|
||||
ModuleDebugStreamRef::linesAndChecksums() const {
|
||||
return make_range(LinesAndChecksums.begin(), LinesAndChecksums.end());
|
||||
llvm::iterator_range<ModuleDebugStreamRef::DebugSubsectionIterator>
|
||||
ModuleDebugStreamRef::subsections() const {
|
||||
return make_range(Subsections.begin(), Subsections.end());
|
||||
}
|
||||
|
||||
bool ModuleDebugStreamRef::hasLineInfo() const {
|
||||
bool ModuleDebugStreamRef::hasDebugSubsections() const {
|
||||
return C13LinesSubstream.getLength() > 0;
|
||||
}
|
||||
|
||||
Error ModuleDebugStreamRef::commit() { return Error::success(); }
|
||||
|
||||
Expected<codeview::DebugChecksumsSubsectionRef>
|
||||
ModuleDebugStreamRef::findChecksumsSubsection() const {
|
||||
for (const auto &SS : subsections()) {
|
||||
if (SS.kind() != DebugSubsectionKind::FileChecksums)
|
||||
continue;
|
||||
|
||||
codeview::DebugChecksumsSubsectionRef Result;
|
||||
if (auto EC = Result.initialize(SS.getRecordData()))
|
||||
return std::move(EC);
|
||||
return Result;
|
||||
}
|
||||
return make_error<RawError>(raw_error_code::no_entry);
|
||||
}
|
||||
|
@ -146,7 +146,8 @@ Error PDBFile::parseFileHeaders() {
|
||||
// at getBlockSize() intervals, so we have to be compatible.
|
||||
// See the function fpmPn() for more information:
|
||||
// https://github.com/Microsoft/microsoft-pdb/blob/master/PDB/msf/msf.cpp#L489
|
||||
auto FpmStream = MappedBlockStream::createFpmStream(ContainerLayout, *Buffer);
|
||||
auto FpmStream =
|
||||
MappedBlockStream::createFpmStream(ContainerLayout, *Buffer, Allocator);
|
||||
BinaryStreamReader FpmReader(*FpmStream);
|
||||
ArrayRef<uint8_t> FpmBytes;
|
||||
if (auto EC = FpmReader.readBytes(FpmBytes,
|
||||
@ -184,7 +185,8 @@ Error PDBFile::parseStreamData() {
|
||||
// is exactly what we are attempting to parse. By specifying a custom
|
||||
// subclass of IPDBStreamData which only accesses the fields that have already
|
||||
// been parsed, we can avoid this and reuse MappedBlockStream.
|
||||
auto DS = MappedBlockStream::createDirectoryStream(ContainerLayout, *Buffer);
|
||||
auto DS = MappedBlockStream::createDirectoryStream(ContainerLayout, *Buffer,
|
||||
Allocator);
|
||||
BinaryStreamReader Reader(*DS);
|
||||
if (auto EC = Reader.readInteger(NumStreams))
|
||||
return EC;
|
||||
@ -407,5 +409,6 @@ PDBFile::safelyCreateIndexedStream(const MSFLayout &Layout,
|
||||
uint32_t StreamIndex) const {
|
||||
if (StreamIndex >= getNumStreams())
|
||||
return make_error<RawError>(raw_error_code::no_stream);
|
||||
return MappedBlockStream::createIndexedStream(Layout, MsfData, StreamIndex);
|
||||
return MappedBlockStream::createIndexedStream(Layout, MsfData, StreamIndex,
|
||||
Allocator);
|
||||
}
|
||||
|
@ -140,8 +140,8 @@ Error PDBFileBuilder::commit(StringRef Filename) {
|
||||
if (auto EC = Writer.writeArray(Layout.DirectoryBlocks))
|
||||
return EC;
|
||||
|
||||
auto DirStream =
|
||||
WritableMappedBlockStream::createDirectoryStream(Layout, Buffer);
|
||||
auto DirStream = WritableMappedBlockStream::createDirectoryStream(
|
||||
Layout, Buffer, Allocator);
|
||||
BinaryStreamWriter DW(*DirStream);
|
||||
if (auto EC = DW.writeInteger<uint32_t>(Layout.StreamSizes.size()))
|
||||
return EC;
|
||||
@ -158,8 +158,8 @@ Error PDBFileBuilder::commit(StringRef Filename) {
|
||||
if (!ExpectedSN)
|
||||
return ExpectedSN.takeError();
|
||||
|
||||
auto NS = WritableMappedBlockStream::createIndexedStream(Layout, Buffer,
|
||||
*ExpectedSN);
|
||||
auto NS = WritableMappedBlockStream::createIndexedStream(
|
||||
Layout, Buffer, *ExpectedSN, Allocator);
|
||||
BinaryStreamWriter NSWriter(*NS);
|
||||
if (auto EC = Strings.commit(NSWriter))
|
||||
return EC;
|
||||
|
@ -56,6 +56,10 @@ Error PDBStringTable::readStrings(BinaryStreamReader &Reader) {
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
codeview::DebugStringTableSubsectionRef PDBStringTable::getStringTable() const {
|
||||
return Strings;
|
||||
}
|
||||
|
||||
Error PDBStringTable::readHashTable(BinaryStreamReader &Reader) {
|
||||
const support::ulittle32_t *HashCount;
|
||||
if (auto EC = Reader.readObject(HashCount))
|
||||
|
@ -32,8 +32,7 @@ using namespace llvm::support;
|
||||
using namespace llvm::msf;
|
||||
using namespace llvm::pdb;
|
||||
|
||||
TpiStream::TpiStream(const PDBFile &File,
|
||||
std::unique_ptr<MappedBlockStream> Stream)
|
||||
TpiStream::TpiStream(PDBFile &File, std::unique_ptr<MappedBlockStream> Stream)
|
||||
: Pdb(File), Stream(std::move(Stream)) {}
|
||||
|
||||
TpiStream::~TpiStream() = default;
|
||||
@ -77,7 +76,8 @@ Error TpiStream::reload() {
|
||||
"Invalid TPI hash stream index.");
|
||||
|
||||
auto HS = MappedBlockStream::createIndexedStream(
|
||||
Pdb.getMsfLayout(), Pdb.getMsfBuffer(), Header->HashStreamIndex);
|
||||
Pdb.getMsfLayout(), Pdb.getMsfBuffer(), Header->HashStreamIndex,
|
||||
Pdb.getAllocator());
|
||||
BinaryStreamReader HSR(*HS);
|
||||
|
||||
// There should be a hash value for every type record, or no hashes at all.
|
||||
|
@ -147,8 +147,8 @@ Error TpiStreamBuilder::commit(const msf::MSFLayout &Layout,
|
||||
if (auto EC = finalize())
|
||||
return EC;
|
||||
|
||||
auto InfoS =
|
||||
WritableMappedBlockStream::createIndexedStream(Layout, Buffer, Idx);
|
||||
auto InfoS = WritableMappedBlockStream::createIndexedStream(Layout, Buffer,
|
||||
Idx, Allocator);
|
||||
|
||||
BinaryStreamWriter Writer(*InfoS);
|
||||
if (auto EC = Writer.writeObject(*Header))
|
||||
@ -159,8 +159,8 @@ Error TpiStreamBuilder::commit(const msf::MSFLayout &Layout,
|
||||
return EC;
|
||||
|
||||
if (HashStreamIndex != kInvalidStreamIndex) {
|
||||
auto HVS = WritableMappedBlockStream::createIndexedStream(Layout, Buffer,
|
||||
HashStreamIndex);
|
||||
auto HVS = WritableMappedBlockStream::createIndexedStream(
|
||||
Layout, Buffer, HashStreamIndex, Allocator);
|
||||
BinaryStreamWriter HW(*HVS);
|
||||
if (HashValueStream) {
|
||||
if (auto EC = HW.writeStreamRef(*HashValueStream))
|
||||
|
@ -39,6 +39,21 @@ void DIBuilder::trackIfUnresolved(MDNode *N) {
|
||||
UnresolvedNodes.emplace_back(N);
|
||||
}
|
||||
|
||||
void DIBuilder::finalizeSubprogram(DISubprogram *SP) {
|
||||
MDTuple *Temp = SP->getVariables().get();
|
||||
if (!Temp || !Temp->isTemporary())
|
||||
return;
|
||||
|
||||
SmallVector<Metadata *, 4> Variables;
|
||||
|
||||
auto PV = PreservedVariables.find(SP);
|
||||
if (PV != PreservedVariables.end())
|
||||
Variables.append(PV->second.begin(), PV->second.end());
|
||||
|
||||
DINodeArray AV = getOrCreateArray(Variables);
|
||||
TempMDTuple(Temp)->replaceAllUsesWith(AV.get());
|
||||
}
|
||||
|
||||
void DIBuilder::finalize() {
|
||||
if (!CUNode) {
|
||||
assert(!AllowUnresolvedNodes &&
|
||||
@ -62,25 +77,11 @@ void DIBuilder::finalize() {
|
||||
CUNode->replaceRetainedTypes(MDTuple::get(VMContext, RetainValues));
|
||||
|
||||
DISubprogramArray SPs = MDTuple::get(VMContext, AllSubprograms);
|
||||
auto resolveVariables = [&](DISubprogram *SP) {
|
||||
MDTuple *Temp = SP->getVariables().get();
|
||||
if (!Temp)
|
||||
return;
|
||||
|
||||
SmallVector<Metadata *, 4> Variables;
|
||||
|
||||
auto PV = PreservedVariables.find(SP);
|
||||
if (PV != PreservedVariables.end())
|
||||
Variables.append(PV->second.begin(), PV->second.end());
|
||||
|
||||
DINodeArray AV = getOrCreateArray(Variables);
|
||||
TempMDTuple(Temp)->replaceAllUsesWith(AV.get());
|
||||
};
|
||||
for (auto *SP : SPs)
|
||||
resolveVariables(SP);
|
||||
finalizeSubprogram(SP);
|
||||
for (auto *N : RetainValues)
|
||||
if (auto *SP = dyn_cast<DISubprogram>(N))
|
||||
resolveVariables(SP);
|
||||
finalizeSubprogram(SP);
|
||||
|
||||
if (!AllGVs.empty())
|
||||
CUNode->replaceGlobalVariables(MDTuple::get(VMContext, AllGVs));
|
||||
|
@ -99,87 +99,6 @@ DebugLoc DebugLoc::appendInlinedAt(DebugLoc DL, DILocation *InlinedAt,
|
||||
return Last;
|
||||
}
|
||||
|
||||
/// Reparent \c Scope from \c OrigSP to \c NewSP.
|
||||
static DIScope *reparentScope(LLVMContext &Ctx, DIScope *Scope,
|
||||
DISubprogram *OrigSP, DISubprogram *NewSP,
|
||||
DenseMap<const MDNode *, MDNode *> &Cache) {
|
||||
SmallVector<DIScope *, 3> ScopeChain;
|
||||
DIScope *Last = NewSP;
|
||||
DIScope *CurScope = Scope;
|
||||
do {
|
||||
if (auto *SP = dyn_cast<DISubprogram>(CurScope)) {
|
||||
// Don't rewrite this scope chain if it doesn't lead to the replaced SP.
|
||||
if (SP != OrigSP)
|
||||
return Scope;
|
||||
Cache.insert({OrigSP, NewSP});
|
||||
break;
|
||||
}
|
||||
if (auto *Found = Cache[CurScope]) {
|
||||
Last = cast<DIScope>(Found);
|
||||
break;
|
||||
}
|
||||
ScopeChain.push_back(CurScope);
|
||||
} while ((CurScope = CurScope->getScope().resolve()));
|
||||
|
||||
// Starting from the top, rebuild the nodes to point to the new inlined-at
|
||||
// location (then rebuilding the rest of the chain behind it) and update the
|
||||
// map of already-constructed inlined-at nodes.
|
||||
for (const DIScope *MD : reverse(ScopeChain)) {
|
||||
if (auto *LB = dyn_cast<DILexicalBlock>(MD))
|
||||
Cache[MD] = Last = DILexicalBlock::getDistinct(
|
||||
Ctx, Last, LB->getFile(), LB->getLine(), LB->getColumn());
|
||||
else if (auto *LB = dyn_cast<DILexicalBlockFile>(MD))
|
||||
Cache[MD] = Last = DILexicalBlockFile::getDistinct(
|
||||
Ctx, Last, LB->getFile(), LB->getDiscriminator());
|
||||
else
|
||||
llvm_unreachable("illegal parent scope");
|
||||
}
|
||||
return Last;
|
||||
}
|
||||
|
||||
void DebugLoc::reparentDebugInfo(Instruction &I, DISubprogram *OrigSP,
|
||||
DISubprogram *NewSP,
|
||||
DenseMap<const MDNode *, MDNode *> &Cache) {
|
||||
auto DL = I.getDebugLoc();
|
||||
if (!OrigSP || !NewSP || OrigSP == NewSP || !DL)
|
||||
return;
|
||||
|
||||
// Reparent the debug location.
|
||||
auto &Ctx = I.getContext();
|
||||
DILocation *InlinedAt = DL->getInlinedAt();
|
||||
if (InlinedAt) {
|
||||
while (auto *IA = InlinedAt->getInlinedAt())
|
||||
InlinedAt = IA;
|
||||
auto NewScope =
|
||||
reparentScope(Ctx, InlinedAt->getScope(), OrigSP, NewSP, Cache);
|
||||
InlinedAt =
|
||||
DebugLoc::get(InlinedAt->getLine(), InlinedAt->getColumn(), NewScope);
|
||||
}
|
||||
I.setDebugLoc(
|
||||
DebugLoc::get(DL.getLine(), DL.getCol(),
|
||||
reparentScope(Ctx, DL->getScope(), OrigSP, NewSP, Cache),
|
||||
DebugLoc::appendInlinedAt(DL, InlinedAt, Ctx, Cache,
|
||||
ReplaceLastInlinedAt)));
|
||||
|
||||
// Fix up debug variables to point to NewSP.
|
||||
auto reparentVar = [&](DILocalVariable *Var) {
|
||||
return DILocalVariable::get(
|
||||
Ctx,
|
||||
cast<DILocalScope>(
|
||||
reparentScope(Ctx, Var->getScope(), OrigSP, NewSP, Cache)),
|
||||
Var->getName(), Var->getFile(), Var->getLine(), Var->getType(),
|
||||
Var->getArg(), Var->getFlags(), Var->getAlignInBits());
|
||||
};
|
||||
if (auto *DbgValue = dyn_cast<DbgValueInst>(&I)) {
|
||||
auto *Var = DbgValue->getVariable();
|
||||
I.setOperand(2, MetadataAsValue::get(Ctx, reparentVar(Var)));
|
||||
} else if (auto *DbgDeclare = dyn_cast<DbgDeclareInst>(&I)) {
|
||||
auto *Var = DbgDeclare->getVariable();
|
||||
I.setOperand(1, MetadataAsValue::get(Ctx, reparentVar(Var)));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
|
||||
LLVM_DUMP_METHOD void DebugLoc::dump() const {
|
||||
if (!Loc)
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include "llvm/Analysis/CallGraphSCCPass.h"
|
||||
#include "llvm/Analysis/LazyCallGraph.h"
|
||||
#include "llvm/Analysis/LoopInfo.h"
|
||||
#include "llvm/Analysis/RegionInfo.h"
|
||||
#include "llvm/IR/Module.h"
|
||||
#include "llvm/IR/OptBisect.h"
|
||||
#include "llvm/Pass.h"
|
||||
@ -53,13 +54,20 @@ static std::string getDescription(const BasicBlock &BB) {
|
||||
}
|
||||
|
||||
static std::string getDescription(const Loop &L) {
|
||||
// FIXME: I'd like to be able to provide a better description here, but
|
||||
// calling L->getHeader() would introduce a new dependency on the
|
||||
// LLVMCore library.
|
||||
// FIXME: Move into LoopInfo so we can get a better description
|
||||
// (and avoid a circular dependency between IR and Analysis).
|
||||
return "loop";
|
||||
}
|
||||
|
||||
static std::string getDescription(const Region &R) {
|
||||
// FIXME: Move into RegionInfo so we can get a better description
|
||||
// (and avoid a circular dependency between IR and Analysis).
|
||||
return "region";
|
||||
}
|
||||
|
||||
static std::string getDescription(const CallGraphSCC &SCC) {
|
||||
// FIXME: Move into CallGraphSCCPass to avoid circular dependency between
|
||||
// IR and Analysis.
|
||||
std::string Desc = "SCC (";
|
||||
bool First = true;
|
||||
for (CallGraphNode *CGN : SCC) {
|
||||
@ -83,6 +91,7 @@ template bool OptBisect::shouldRunPass(const Pass *, const Function &);
|
||||
template bool OptBisect::shouldRunPass(const Pass *, const BasicBlock &);
|
||||
template bool OptBisect::shouldRunPass(const Pass *, const Loop &);
|
||||
template bool OptBisect::shouldRunPass(const Pass *, const CallGraphSCC &);
|
||||
template bool OptBisect::shouldRunPass(const Pass *, const Region &);
|
||||
|
||||
template <class UnitT>
|
||||
bool OptBisect::shouldRunPass(const Pass *P, const UnitT &U) {
|
||||
|
@ -122,6 +122,7 @@ static void computeCacheKey(
|
||||
AddUnsigned(Conf.CGOptLevel);
|
||||
AddUnsigned(Conf.CGFileType);
|
||||
AddUnsigned(Conf.OptLevel);
|
||||
AddUnsigned(Conf.UseNewPM);
|
||||
AddString(Conf.OptPipeline);
|
||||
AddString(Conf.AAPipeline);
|
||||
AddString(Conf.OverrideTriple);
|
||||
@ -621,6 +622,19 @@ unsigned LTO::getMaxTasks() const {
|
||||
}
|
||||
|
||||
Error LTO::run(AddStreamFn AddStream, NativeObjectCache Cache) {
|
||||
// Compute "dead" symbols, we don't want to import/export these!
|
||||
DenseSet<GlobalValue::GUID> GUIDPreservedSymbols;
|
||||
for (auto &Res : GlobalResolutions) {
|
||||
if (Res.second.VisibleOutsideThinLTO &&
|
||||
// IRName will be defined if we have seen the prevailing copy of
|
||||
// this value. If not, no need to preserve any ThinLTO copies.
|
||||
!Res.second.IRName.empty())
|
||||
GUIDPreservedSymbols.insert(GlobalValue::getGUID(
|
||||
GlobalValue::dropLLVMManglingEscape(Res.second.IRName)));
|
||||
}
|
||||
|
||||
computeDeadSymbols(ThinLTO.CombinedIndex, GUIDPreservedSymbols);
|
||||
|
||||
// Save the status of having a regularLTO combined module, as
|
||||
// this is needed for generating the ThinLTO Task ID, and
|
||||
// the CombinedModule will be moved at the end of runRegularLTO.
|
||||
@ -930,6 +944,17 @@ ThinBackend lto::createWriteIndexesThinBackend(std::string OldPrefix,
|
||||
};
|
||||
}
|
||||
|
||||
static bool IsLiveByGUID(const ModuleSummaryIndex &Index,
|
||||
GlobalValue::GUID GUID) {
|
||||
auto VI = Index.getValueInfo(GUID);
|
||||
if (!VI)
|
||||
return false;
|
||||
for (auto &I : VI.getSummaryList())
|
||||
if (Index.isGlobalValueLive(I.get()))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
Error LTO::runThinLTO(AddStreamFn AddStream, NativeObjectCache Cache,
|
||||
bool HasRegularLTO) {
|
||||
if (ThinLTO.ModuleMap.empty())
|
||||
@ -962,22 +987,8 @@ Error LTO::runThinLTO(AddStreamFn AddStream, NativeObjectCache Cache,
|
||||
StringMap<std::map<GlobalValue::GUID, GlobalValue::LinkageTypes>> ResolvedODR;
|
||||
|
||||
if (Conf.OptLevel > 0) {
|
||||
// Compute "dead" symbols, we don't want to import/export these!
|
||||
DenseSet<GlobalValue::GUID> GUIDPreservedSymbols;
|
||||
for (auto &Res : GlobalResolutions) {
|
||||
if (Res.second.VisibleOutsideThinLTO &&
|
||||
// IRName will be defined if we have seen the prevailing copy of
|
||||
// this value. If not, no need to preserve any ThinLTO copies.
|
||||
!Res.second.IRName.empty())
|
||||
GUIDPreservedSymbols.insert(GlobalValue::getGUID(
|
||||
GlobalValue::dropLLVMManglingEscape(Res.second.IRName)));
|
||||
}
|
||||
|
||||
auto DeadSymbols =
|
||||
computeDeadSymbols(ThinLTO.CombinedIndex, GUIDPreservedSymbols);
|
||||
|
||||
ComputeCrossModuleImport(ThinLTO.CombinedIndex, ModuleToDefinedGVSummaries,
|
||||
ImportLists, ExportLists, &DeadSymbols);
|
||||
ImportLists, ExportLists);
|
||||
|
||||
std::set<GlobalValue::GUID> ExportedGUIDs;
|
||||
for (auto &Res : GlobalResolutions) {
|
||||
@ -992,7 +1003,7 @@ Error LTO::runThinLTO(AddStreamFn AddStream, NativeObjectCache Cache,
|
||||
auto GUID = GlobalValue::getGUID(
|
||||
GlobalValue::dropLLVMManglingEscape(Res.second.IRName));
|
||||
// Mark exported unless index-based analysis determined it to be dead.
|
||||
if (!DeadSymbols.count(GUID))
|
||||
if (IsLiveByGUID(ThinLTO.CombinedIndex, GUID))
|
||||
ExportedGUIDs.insert(GUID);
|
||||
}
|
||||
|
||||
|
@ -42,11 +42,6 @@
|
||||
using namespace llvm;
|
||||
using namespace lto;
|
||||
|
||||
static cl::opt<bool>
|
||||
LTOUseNewPM("lto-use-new-pm",
|
||||
cl::desc("Run LTO passes using the new pass manager"),
|
||||
cl::init(false), cl::Hidden);
|
||||
|
||||
LLVM_ATTRIBUTE_NORETURN static void reportOpenError(StringRef Path, Twine Msg) {
|
||||
errs() << "failed to open " << Path << ": " << Msg << '\n';
|
||||
errs().flush();
|
||||
@ -266,7 +261,7 @@ bool opt(Config &Conf, TargetMachine *TM, unsigned Task, Module &Mod,
|
||||
if (!Conf.OptPipeline.empty())
|
||||
runNewPMCustomPasses(Mod, TM, Conf.OptPipeline, Conf.AAPipeline,
|
||||
Conf.DisableVerify);
|
||||
else if (LTOUseNewPM)
|
||||
else if (Conf.UseNewPM)
|
||||
runNewPMPasses(Mod, TM, Conf.OptLevel, IsThinLTO);
|
||||
else
|
||||
runOldPMPasses(Conf, Mod, TM, IsThinLTO, ExportSummary, ImportSummary);
|
||||
|
@ -628,13 +628,13 @@ void ThinLTOCodeGenerator::promote(Module &TheModule,
|
||||
PreservedSymbols, Triple(TheModule.getTargetTriple()));
|
||||
|
||||
// Compute "dead" symbols, we don't want to import/export these!
|
||||
auto DeadSymbols = computeDeadSymbols(Index, GUIDPreservedSymbols);
|
||||
computeDeadSymbols(Index, GUIDPreservedSymbols);
|
||||
|
||||
// Generate import/export list
|
||||
StringMap<FunctionImporter::ImportMapTy> ImportLists(ModuleCount);
|
||||
StringMap<FunctionImporter::ExportSetTy> ExportLists(ModuleCount);
|
||||
ComputeCrossModuleImport(Index, ModuleToDefinedGVSummaries, ImportLists,
|
||||
ExportLists, &DeadSymbols);
|
||||
ExportLists);
|
||||
|
||||
// Resolve LinkOnce/Weak symbols.
|
||||
StringMap<std::map<GlobalValue::GUID, GlobalValue::LinkageTypes>> ResolvedODR;
|
||||
@ -673,13 +673,13 @@ void ThinLTOCodeGenerator::crossModuleImport(Module &TheModule,
|
||||
PreservedSymbols, Triple(TheModule.getTargetTriple()));
|
||||
|
||||
// Compute "dead" symbols, we don't want to import/export these!
|
||||
auto DeadSymbols = computeDeadSymbols(Index, GUIDPreservedSymbols);
|
||||
computeDeadSymbols(Index, GUIDPreservedSymbols);
|
||||
|
||||
// Generate import/export list
|
||||
StringMap<FunctionImporter::ImportMapTy> ImportLists(ModuleCount);
|
||||
StringMap<FunctionImporter::ExportSetTy> ExportLists(ModuleCount);
|
||||
ComputeCrossModuleImport(Index, ModuleToDefinedGVSummaries, ImportLists,
|
||||
ExportLists, &DeadSymbols);
|
||||
ExportLists);
|
||||
auto &ImportList = ImportLists[TheModule.getModuleIdentifier()];
|
||||
|
||||
crossImportIntoModule(TheModule, Index, ModuleMap, ImportList);
|
||||
@ -750,13 +750,13 @@ void ThinLTOCodeGenerator::internalize(Module &TheModule,
|
||||
Index.collectDefinedGVSummariesPerModule(ModuleToDefinedGVSummaries);
|
||||
|
||||
// Compute "dead" symbols, we don't want to import/export these!
|
||||
auto DeadSymbols = computeDeadSymbols(Index, GUIDPreservedSymbols);
|
||||
computeDeadSymbols(Index, GUIDPreservedSymbols);
|
||||
|
||||
// Generate import/export list
|
||||
StringMap<FunctionImporter::ImportMapTy> ImportLists(ModuleCount);
|
||||
StringMap<FunctionImporter::ExportSetTy> ExportLists(ModuleCount);
|
||||
ComputeCrossModuleImport(Index, ModuleToDefinedGVSummaries, ImportLists,
|
||||
ExportLists, &DeadSymbols);
|
||||
ExportLists);
|
||||
auto &ExportList = ExportLists[ModuleIdentifier];
|
||||
|
||||
// Be friendly and don't nuke totally the module when the client didn't
|
||||
@ -902,14 +902,14 @@ void ThinLTOCodeGenerator::run() {
|
||||
computeGUIDPreservedSymbols(PreservedSymbols, TMBuilder.TheTriple);
|
||||
|
||||
// Compute "dead" symbols, we don't want to import/export these!
|
||||
auto DeadSymbols = computeDeadSymbols(*Index, GUIDPreservedSymbols);
|
||||
computeDeadSymbols(*Index, GUIDPreservedSymbols);
|
||||
|
||||
// Collect the import/export lists for all modules from the call-graph in the
|
||||
// combined index.
|
||||
StringMap<FunctionImporter::ImportMapTy> ImportLists(ModuleCount);
|
||||
StringMap<FunctionImporter::ExportSetTy> ExportLists(ModuleCount);
|
||||
ComputeCrossModuleImport(*Index, ModuleToDefinedGVSummaries, ImportLists,
|
||||
ExportLists, &DeadSymbols);
|
||||
ExportLists);
|
||||
|
||||
// We use a std::map here to be able to have a defined ordering when
|
||||
// producing a hash for the cache entry.
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user