44 #include "llvm/Config/llvm-config.h" 66 #define DEBUG_TYPE "stack-coloring" 81 cl::desc(
"Do not optimize lifetime zones that " 91 cl::desc(
"Treat stack lifetimes as starting on first use, not on START marker."));
94 STATISTIC(NumMarkerSeen,
"Number of lifetime markers found.");
95 STATISTIC(StackSpaceSaved,
"Number of bytes saved due to merging slots.");
96 STATISTIC(StackSlotMerged,
"Number of stack slot merged.");
97 STATISTIC(EscapedAllocas,
"Number of allocas that escaped the lifetime region");
388 struct BlockLifetimeInfo {
404 LivenessMap BlockLiveness;
438 unsigned NumIterations;
456 void dumpIntervals()
const;
458 void dumpBV(
const char *tag,
const BitVector &BV)
const;
462 bool removeAllMarkers();
467 unsigned collectMarkers(
unsigned NumSlot);
473 void calculateLocalLiveness();
477 bool applyFirstUse(
int Slot) {
480 if (ConservativeSlots.
test(Slot))
495 void calculateLiveIntervals(
unsigned NumSlots);
507 void removeInvalidSlotRanges();
521 "Merge disjoint stack slots",
false,
false)
526 void StackColoring::getAnalysisUsage(
AnalysisUsage &AU)
const {
531 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 534 dbgs() << tag <<
" : { ";
535 for (
unsigned I = 0,
E = BV.
size();
I !=
E; ++
I)
541 LivenessMap::const_iterator BI = BlockLiveness.find(MBB);
542 assert(BI != BlockLiveness.end() &&
"Block not found");
543 const BlockLifetimeInfo &BlockInfo = BI->second;
545 dumpBV(
"BEGIN", BlockInfo.Begin);
546 dumpBV(
"END", BlockInfo.End);
547 dumpBV(
"LIVE_IN", BlockInfo.LiveIn);
548 dumpBV(
"LIVE_OUT", BlockInfo.LiveOut);
560 for (
unsigned I = 0,
E = Intervals.
size();
I !=
E; ++
I) {
561 dbgs() <<
"Interval[" <<
I <<
"]:\n";
562 Intervals[
I]->dump();
571 "Expected LIFETIME_START or LIFETIME_END op");
591 if (!InterestingSlots.
test(Slot))
598 if (!applyFirstUse(Slot)) {
608 int Slot = MO.getIndex();
611 if (InterestingSlots.
test(Slot) && applyFirstUse(Slot)) {
625 unsigned StackColoring::collectMarkers(
unsigned NumSlot) {
626 unsigned MarkersFound = 0;
627 BlockBitVecMap SeenStartMap;
628 InterestingSlots.
clear();
629 InterestingSlots.
resize(NumSlot);
630 ConservativeSlots.
clear();
631 ConservativeSlots.
resize(NumSlot);
644 BetweenStartEnd.
resize(NumSlot);
646 PE = MBB->
pred_end(); PI != PE; ++PI) {
647 BlockBitVecMap::const_iterator
I = SeenStartMap.find(*PI);
648 if (I != SeenStartMap.end()) {
649 BetweenStartEnd |= I->second;
660 InterestingSlots.
set(Slot);
662 BetweenStartEnd.
set(Slot);
663 NumStartLifetimes[Slot] += 1;
665 BetweenStartEnd.
reset(Slot);
666 NumEndLifetimes[Slot] += 1;
676 <<
" with allocation: " << Allocation->
getName() <<
"\n");
684 int Slot = MO.getIndex();
687 if (! BetweenStartEnd.
test(Slot)) {
688 ConservativeSlots.
set(Slot);
693 BitVector &SeenStart = SeenStartMap[MBB];
694 SeenStart |= BetweenStartEnd;
702 for (
unsigned slot = 0; slot < NumSlot; ++slot)
703 if (NumStartLifetimes[slot] > 1 || NumEndLifetimes[slot] > 1)
704 ConservativeSlots.
set(slot);
705 LLVM_DEBUG(dumpBV(
"Conservative slots", ConservativeSlots));
713 BasicBlocks[MBB] = BasicBlockNumbering.
size();
717 BlockLifetimeInfo &BlockInfo = BlockLiveness[MBB];
719 BlockInfo.Begin.resize(NumSlot);
720 BlockInfo.End.resize(NumSlot);
724 bool isStart =
false;
726 if (isLifetimeStartOrEnd(MI, slots, isStart)) {
728 assert(slots.
size() == 1 &&
"unexpected: MI ends multiple slots");
730 if (BlockInfo.Begin.test(Slot)) {
731 BlockInfo.Begin.reset(Slot);
733 BlockInfo.End.set(Slot);
735 for (
auto Slot : slots) {
743 <<
" with allocation: " << Allocation->getName());
746 if (BlockInfo.End.test(Slot)) {
747 BlockInfo.End.reset(Slot);
749 BlockInfo.Begin.set(Slot);
757 NumMarkerSeen += MarkersFound;
761 void StackColoring::calculateLocalLiveness() {
762 unsigned NumIters = 0;
770 LivenessMap::iterator BI = BlockLiveness.find(BB);
771 assert(BI != BlockLiveness.end() &&
"Block not found");
772 BlockLifetimeInfo &BlockInfo = BI->second;
777 PE = BB->pred_end(); PI != PE; ++PI) {
778 LivenessMap::const_iterator
I = BlockLiveness.find(*PI);
782 if (I != BlockLiveness.end())
783 LocalLiveIn |= I->second.LiveOut;
794 LocalLiveOut.
reset(BlockInfo.End);
795 LocalLiveOut |= BlockInfo.Begin;
798 if (LocalLiveIn.
test(BlockInfo.LiveIn)) {
800 BlockInfo.LiveIn |= LocalLiveIn;
804 if (LocalLiveOut.
test(BlockInfo.LiveOut)) {
806 BlockInfo.LiveOut |= LocalLiveOut;
811 NumIterations = NumIters;
814 void StackColoring::calculateLiveIntervals(
unsigned NumSlots) {
823 DefinitelyInUse.
clear();
824 DefinitelyInUse.
resize(NumSlots);
827 BlockLifetimeInfo &MBBLiveness = BlockLiveness[&MBB];
828 for (
int pos = MBBLiveness.LiveIn.find_first(); pos != -1;
829 pos = MBBLiveness.LiveIn.find_next(pos)) {
836 bool IsStart =
false;
837 if (!isLifetimeStartOrEnd(MI, slots, IsStart))
840 for (
auto Slot : slots) {
845 if (!DefinitelyInUse[Slot]) {
847 DefinitelyInUse[Slot] =
true;
849 if (!Starts[Slot].isValid())
850 Starts[Slot] = ThisIndex;
852 if (Starts[Slot].isValid()) {
853 VNInfo *VNI = Intervals[Slot]->getValNumInfo(0);
854 Intervals[Slot]->addSegment(
855 LiveInterval::Segment(Starts[Slot], ThisIndex, VNI));
857 DefinitelyInUse[Slot] =
false;
864 for (
unsigned i = 0; i < NumSlots; ++i) {
865 if (!Starts[i].isValid())
869 VNInfo *VNI = Intervals[i]->getValNumInfo(0);
870 Intervals[i]->addSegment(LiveInterval::Segment(Starts[i], EndIdx, VNI));
875 bool StackColoring::removeAllMarkers() {
888 unsigned FixedInstr = 0;
889 unsigned FixedMemOp = 0;
890 unsigned FixedDbg = 0;
896 if (SlotRemap.
count(
VI.Slot)) {
898 << cast<DILocalVariable>(
VI.Var)->getName() <<
"].\n");
899 VI.Slot = SlotRemap[
VI.Slot];
910 for (
const std::pair<int, int> &
SI : SlotRemap) {
913 assert(To && From &&
"Invalid allocation object");
930 MergedAllocas.
insert(From);
950 for (
auto &
Use : FromAI->
uses()) {
952 if (BCI->isUsedByMetadata())
974 const AllocaInst *AI = dyn_cast_or_null<AllocaInst>(MMO->getValue());
978 if (!Allocas.
count(AI))
981 MMO->setValue(Allocas[AI]);
989 int FromSlot = MO.getIndex();
996 if (!SlotRemap.count(FromSlot))
1007 bool TouchesMemory =
I.mayLoad() ||
I.mayStore();
1014 "Found instruction usage outside of live range.");
1019 int ToSlot = SlotRemap[FromSlot];
1020 MO.setIndex(ToSlot);
1026 bool ReplaceMemOps =
false;
1030 bool MayHaveConflictingAAMD =
false;
1031 if (MMO->getAAInfo()) {
1032 if (
const Value *MMOV = MMO->getValue()) {
1037 MayHaveConflictingAAMD =
true;
1039 for (
Value *V : Objs) {
1043 const AllocaInst *AI = dyn_cast_or_null<AllocaInst>(V);
1044 if (AI && MergedAllocas.
count(AI)) {
1045 MayHaveConflictingAAMD =
true;
1051 if (MayHaveConflictingAAMD) {
1053 ReplaceMemOps =
true;
1062 I.setMemRefs(*MF, NewMMOs);
1073 LLVM_DEBUG(
dbgs() <<
"Fixed " << FixedMemOp <<
" machine memory operands.\n");
1074 LLVM_DEBUG(
dbgs() <<
"Fixed " << FixedDbg <<
" debug locations.\n");
1075 LLVM_DEBUG(
dbgs() <<
"Fixed " << FixedInstr <<
" machine instructions.\n");
1078 void StackColoring::removeInvalidSlotRanges() {
1091 if (!
I.mayLoad() && !
I.mayStore())
1099 int Slot = MO.getIndex();
1104 if (Intervals[Slot]->
empty())
1111 if (Interval->
find(Index) == Interval->
end()) {
1121 unsigned NumSlots) {
1123 for (
unsigned i=0; i < NumSlots; ++i) {
1125 if (SlotRemap.
count(i)) {
1126 int Target = SlotRemap[i];
1128 while (SlotRemap.
count(Target)) {
1129 Target = SlotRemap[Target];
1130 SlotRemap[i] = Target;
1138 <<
"********** Function: " << Func.
getName() <<
'\n');
1140 MFI = &MF->getFrameInfo();
1141 Indexes = &getAnalysis<SlotIndexes>();
1142 BlockLiveness.clear();
1143 BasicBlocks.
clear();
1144 BasicBlockNumbering.
clear();
1148 VNInfoAllocator.
Reset();
1157 SortedSlots.
reserve(NumSlots);
1159 LiveStarts.
resize(NumSlots);
1161 unsigned NumMarkers = collectMarkers(NumSlots);
1163 unsigned TotalSize = 0;
1164 LLVM_DEBUG(
dbgs() <<
"Found " << NumMarkers <<
" markers and " << NumSlots
1174 LLVM_DEBUG(
dbgs() <<
"Total Stack size: " << TotalSize <<
" bytes\n\n");
1181 return removeAllMarkers();
1184 for (
unsigned i=0; i < NumSlots; ++i) {
1185 std::unique_ptr<LiveInterval> LI(
new LiveInterval(i, 0));
1186 LI->getNextValue(Indexes->
getZeroIndex(), VNInfoAllocator);
1192 calculateLocalLiveness();
1193 LLVM_DEBUG(
dbgs() <<
"Dataflow iterations: " << NumIterations <<
"\n");
1197 calculateLiveIntervals(NumSlots);
1203 removeInvalidSlotRanges();
1207 unsigned RemovedSlots = 0;
1208 unsigned ReducedSize = 0;
1211 for (
unsigned I = 0;
I < NumSlots; ++
I) {
1212 if (Intervals[SortedSlots[
I]]->
empty())
1213 SortedSlots[
I] = -1;
1224 std::stable_sort(SortedSlots.
begin(), SortedSlots.
end(),
1225 [
this](
int LHS,
int RHS) {
1227 if (LHS == -1)
return false;
1228 if (RHS == -1)
return true;
1233 for (
auto &s : LiveStarts)
1236 bool Changed =
true;
1239 for (
unsigned I = 0;
I < NumSlots; ++
I) {
1240 if (SortedSlots[
I] == -1)
1243 for (
unsigned J=
I+1; J < NumSlots; ++J) {
1244 if (SortedSlots[J] == -1)
1247 int FirstSlot = SortedSlots[
I];
1248 int SecondSlot = SortedSlots[J];
1251 auto &FirstS = LiveStarts[FirstSlot];
1252 auto &SecondS = LiveStarts[SecondSlot];
1262 int OldSize = FirstS.size();
1263 FirstS.append(SecondS.begin(), SecondS.end());
1264 auto Mid = FirstS.begin() + OldSize;
1265 std::inplace_merge(FirstS.begin(), Mid, FirstS.end());
1267 SlotRemap[SecondSlot] = FirstSlot;
1268 SortedSlots[J] = -1;
1270 << SecondSlot <<
" together.\n");
1276 "Merging a small object into a larger one");
1288 StackSpaceSaved += ReducedSize;
1289 StackSlotMerged += RemovedSlots;
1290 LLVM_DEBUG(
dbgs() <<
"Merge " << RemovedSlots <<
" slots. Saved " 1291 << ReducedSize <<
" bytes\n");
1295 expungeSlotMap(SlotRemap, NumSlots);
1296 remapInstructions(SlotRemap);
1298 return removeAllMarkers();
void resize(unsigned N, bool t=false)
resize - Grow or shrink the bitvector.
iterator_range< use_iterator > uses()
SmallVector< WinEHHandlerType, 1 > HandlerArray
static PassRegistry * getPassRegistry()
getPassRegistry - Access the global registry object, which is automatically initialized at applicatio...
GCNRegPressure max(const GCNRegPressure &P1, const GCNRegPressure &P2)
static int getStartOrEndSlot(const MachineInstr &MI)
This class represents lattice values for constants.
Did not trigger a stack protector.
Interval Class - An Interval is a set of nodes defined such that every node in the interval has all o...
void push_back(const T &Elt)
Merge disjoint stack slots
LiveInterval - This class represents the liveness of a register, or stack slot.
bool test(unsigned Idx) const
bool isLiveAtIndexes(ArrayRef< SlotIndex > Slots) const
static void dump(StringRef Title, SpillInfo const &Spills)
STATISTIC(NumFunctions, "Total number of functions")
std::vector< MachineBasicBlock * >::const_iterator const_pred_iterator
This defines the Use class.
void reserve(size_type N)
VNInfo - Value Number Information.
iterator_range< mop_iterator > operands()
VariableDbgInfoMapTy & getVariableDbgInfo()
union llvm::WinEHHandlerType::@189 CatchObj
The CatchObj starts out life as an LLVM alloca and is eventually turned frame index.
#define INITIALIZE_PASS_DEPENDENCY(depName)
A description of a memory reference used in the backend.
void clear()
clear - Removes all bits from the bitvector. Does not change capacity.
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
void Reset()
Deallocate all but the current slab and reset the current pointer to the beginning of it...
Printable printMBBReference(const MachineBasicBlock &MBB)
Prints a machine basic block reference.
PointerType * getType() const
Overload to return most specific pointer type.
char & StackColoringID
StackSlotColoring - This pass performs stack coloring and merging.
A Use represents the edge between a Value definition and its users.
The address of this allocation is exposed and triggered protection.
void eraseFromParent()
Unlink 'this' from the containing basic block and delete it.
SlotIndex getInstructionIndex(const MachineInstr &MI) const
Returns the base index for the given instruction.
The MachineFrameInfo class represents an abstract stack frame until prolog/epilog code is inserted...
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
void MergeSegmentsInAsValue(const LiveRange &RHS, VNInfo *LHSValNo)
Merge all of the live segments of a specific val# in RHS into this live range as the specified value ...
This class represents a no-op cast from one type to another.
INITIALIZE_PASS_BEGIN(StackColoring, DEBUG_TYPE, "Merge disjoint stack slots", false, false) INITIALIZE_PASS_END(StackColoring
int getObjectIndexEnd() const
Return one past the maximum frame object index.
SSPLayoutKind getObjectSSPLayout(int ObjectIdx) const
int getNumber() const
MachineBasicBlocks are uniquely numbered at the function level, unless they're not in a MachineFuncti...
void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
int64_t getObjectSize(int ObjectIdx) const
Return the size of the specified object.
StringRef getName() const
getName - Return the name of the corresponding LLVM function.
void setObjectSSPLayout(int ObjectIdx, SSPLayoutKind Kind)
Array or nested array >= SSP-buffer-size.
This corresponds to the llvm.lifetime.
unsigned getObjectAlignment(int ObjectIdx) const
Return the alignment of the specified stack object.
initializer< Ty > init(const Ty &Val)
void dump(const SparseBitVector< ElementSize > &LHS, raw_ostream &out)
StringRef getName() const
Return the name of the corresponding LLVM basic block, or an empty string.
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - Subclasses that override getAnalysisUsage must call this.
void RemoveStackObject(int ObjectIdx)
Remove or mark dead a statically sized stack object.
Allocate memory in an ever growing pool, as if by bump-pointer.
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
LLVM_ATTRIBUTE_ALWAYS_INLINE iterator begin()
This file contains the declarations for the subclasses of Constant, which represent the different fla...
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
bool getUnderlyingObjectsForCodeGen(const Value *V, SmallVectorImpl< Value *> &Objects, const DataLayout &DL)
This is a wrapper around GetUnderlyingObjects and adds support for basic ptrtoint+arithmetic+inttoptr...
SlotIndex getMBBStartIdx(unsigned Num) const
Returns the first index in the given basic block number.
Represent the analysis usage information of a pass.
SlotIndex getZeroIndex()
Returns the zero index for this analysis.
size_type count(ConstPtrType Ptr) const
count - Return 1 if the specified pointer is in the set, 0 otherwise.
SlotIndex getMBBEndIdx(unsigned Num) const
Returns the last index in the given basic block number.
static UndefValue * get(Type *T)
Static factory methods - Return an 'undef' object of the specified type.
pred_iterator pred_begin()
bool isDebugInstr() const
INITIALIZE_PASS_END(RegBankSelect, DEBUG_TYPE, "Assign register bank of generic virtual registers", false, false) RegBankSelect
void sort(IteratorTy Start, IteratorTy End)
iterator find(SlotIndex Pos)
find - Return an iterator pointing to the first segment that ends after Pos, or end().
constexpr bool empty(const T &RangeOrContainer)
Test whether RangeOrContainer is empty. Similar to C++17 std::empty.
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements...
BlockVerifier::State From
MachineOperand class - Representation of each machine instruction operand.
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small...
void initializeStackColoringPass(PassRegistry &)
A collection of metadata nodes that might be associated with a memory access used by the alias-analys...
SSPLayoutKind
Stack Smashing Protection (SSP) rules require that vulnerable stack allocations are located close the...
const Function & getFunction() const
Return the LLVM function that this machine code represents.
bool isUsedByMetadata() const
Return true if there is metadata referencing this value.
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Target - Wrapper for Target specific information.
VNInfo * getValNumInfo(unsigned ValNo)
getValNumInfo - Returns pointer to the specified val#.
Representation of each machine instruction.
const AllocaInst * getObjectAllocation(int ObjectIdx) const
Return the underlying Alloca of the specified stack object if it exists.
LLVM_ATTRIBUTE_ALWAYS_INLINE iterator end()
LLVM_NODISCARD bool empty() const
StringRef getName() const
Return a constant reference to the value's name.
void insertAfter(Instruction *InsertPos)
Insert an unlinked instruction into a basic block immediately after the specified instruction...
static cl::opt< bool > LifetimeStartOnFirstUse("stackcoloring-lifetime-start-on-first-use", cl::init(true), cl::Hidden, cl::desc("Treat stack lifetimes as starting on first use, not on START marker."))
Enable enhanced dataflow scheme for lifetime analysis (treat first use of stack slot as start of slot...
size_type size() const
size - Returns the number of bits in this bitvector.
size_type count(const_arg_type_t< KeyT > Val) const
Return 1 if the specified key is in the map, 0 otherwise.
iterator_range< df_iterator< T > > depth_first(const T &G)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
static cl::opt< bool > DisableColoring("no-stack-coloring", cl::init(false), cl::Hidden, cl::desc("Disable stack coloring"))
static cl::opt< bool > ProtectFromEscapedAllocas("protect-from-escaped-allocas", cl::init(false), cl::Hidden, cl::desc("Do not optimize lifetime zones that " "are broken"))
The user may write code that uses allocas outside of the declared lifetime zone.
LLVM Value Representation.
void print(raw_ostream &os) const
Print this index to the given raw_ostream.
const MachineOperand & getOperand(unsigned i) const
SlotIndex - An opaque wrapper around machine indexes.
void setObjectAlignment(int ObjectIdx, unsigned Align)
setObjectAlignment - Change the alignment of the specified stack object.
an instruction to allocate memory on the stack