aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/CodeGen/StackColoring.cpp22
-rw-r--r--test/CodeGen/X86/StackColoring.ll24
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