diff options
-rw-r--r-- | lib/CodeGen/StackColoring.cpp | 22 | ||||
-rw-r--r-- | test/CodeGen/X86/StackColoring.ll | 24 |
2 files changed, 41 insertions, 5 deletions
diff --git a/lib/CodeGen/StackColoring.cpp b/lib/CodeGen/StackColoring.cpp index a14d730025..1a7801abd8 100644 --- a/lib/CodeGen/StackColoring.cpp +++ b/lib/CodeGen/StackColoring.cpp @@ -73,7 +73,6 @@ STATISTIC(StackSlotMerged, "Number of stack slot merged."); STATISTIC(EscapedAllocas, "Number of allocas that escaped the lifetime region"); - //===----------------------------------------------------------------------===// // StackColoring Pass //===----------------------------------------------------------------------===// @@ -259,8 +258,8 @@ unsigned StackColoring::collectMarkers(unsigned NumSlot) { const Value *Allocation = MFI->getObjectAllocation(Slot); if (Allocation) { - DEBUG(dbgs()<<"Found lifetime marker for allocation: "<< - Allocation->getName()<<"\n"); + DEBUG(dbgs()<<"Found a lifetime marker for slot #"<<Slot<< + " with allocation: "<< Allocation->getName()<<"\n"); } if (IsStart) { @@ -538,8 +537,12 @@ void StackColoring::remapInstructions(DenseMap<int, int> &SlotRemap) { // inside the expected live range. If the instruction is not inside // the calculated range then it means that the alloca usage moved // outside of the lifetime markers. + // NOTE: Alloca address calculations which happen outside the lifetime + // zone are are okay, despite the fact that we don't have a good way + // for validating all of the usages of the calculation. #ifndef NDEBUG - if (!I->isDebugValue()) { + bool TouchesMemory = I->mayLoad() || I->mayStore(); + if (!I->isDebugValue() && TouchesMemory) { SlotIndex Index = Indexes->getInstructionIndex(I); LiveInterval *Interval = Intervals[FromSlot]; assert(Interval->find(Index) != Interval->end() && @@ -569,6 +572,15 @@ void StackColoring::removeInvalidSlotRanges() { I->getOpcode() == TargetOpcode::LIFETIME_END || I->isDebugValue()) continue; + // Some intervals are suspicious! In some cases we find address + // calculations outside of the lifetime zone, but not actual memory + // read or write. Memory accesses outside of the lifetime zone are a clear + // violation, but address calculations are okay. This can happen when + // GEPs are hoisted outside of the lifetime zone. + // So, in here we only check instrucitons which can read or write memory. + if (!I->mayLoad() && !I->mayStore()) + continue; + // Check all of the machine operands. for (unsigned i = 0 ; i < I->getNumOperands(); ++i) { MachineOperand &MO = I->getOperand(i); @@ -652,7 +664,7 @@ bool StackColoring::runOnMachineFunction(MachineFunction &Func) { DEBUG(dbgs()<<"Total Stack size: "<<TotalSize<<" bytes\n\n"); // Don't continue because there are not enough lifetime markers, or the - // stack or too small, or we are told not to optimize the slots. + // stack is too small, or we are told not to optimize the slots. if (NumMarkers < 2 || TotalSize < 16 || DisableColoring) { DEBUG(dbgs()<<"Will not try to merge slots.\n"); return removeAllMarkers(); diff --git a/test/CodeGen/X86/StackColoring.ll b/test/CodeGen/X86/StackColoring.ll index a83a4ebbe2..f8ae74f292 100644 --- a/test/CodeGen/X86/StackColoring.ll +++ b/test/CodeGen/X86/StackColoring.ll @@ -376,6 +376,30 @@ block2: } +; Check that we don't assert and crash even when there are usages +; of allocas which do not read or write outside the declared lifetime regions. +;YESCOLOR: shady_range +;NOCOLOR: shady_range + +%struct.Klass = type { i32, i32 } + +define i32 @shady_range(i32 %argc, i8** nocapture %argv) uwtable { + %a.i = alloca [4 x %struct.Klass], align 16 + %b.i = alloca [4 x %struct.Klass], align 16 + %a8 = bitcast [4 x %struct.Klass]* %a.i to i8* + %b8 = bitcast [4 x %struct.Klass]* %b.i to i8* + ; I am used outside the lifetime zone below: + %z2 = getelementptr inbounds [4 x %struct.Klass]* %a.i, i64 0, i64 0, i32 0 + call void @llvm.lifetime.start(i64 -1, i8* %a8) + call void @llvm.lifetime.start(i64 -1, i8* %b8) + %z3 = load i32* %z2, align 16 + %r = call i32 @foo(i32 %z3, i8* %a8) + %r2 = call i32 @foo(i32 %z3, i8* %b8) + call void @llvm.lifetime.end(i64 -1, i8* %a8) + call void @llvm.lifetime.end(i64 -1, i8* %b8) + ret i32 9 +} + declare void @bar([100 x i32]* , [100 x i32]*) nounwind declare void @llvm.lifetime.start(i64, i8* nocapture) nounwind |