[llvm] 5d964e2 - [StackSafety] Check variable lifetime
Vitaly Buka via llvm-commits
llvm-commits at lists.llvm.org
Mon Jun 22 03:45:42 PDT 2020
Author: Vitaly Buka
Date: 2020-06-22T03:45:29-07:00
New Revision: 5d964e262f0c446dd1e25179d342a953a3611d76
URL: https://github.com/llvm/llvm-project/commit/5d964e262f0c446dd1e25179d342a953a3611d76
DIFF: https://github.com/llvm/llvm-project/commit/5d964e262f0c446dd1e25179d342a953a3611d76.diff
LOG: [StackSafety] Check variable lifetime
We can't consider variable safe if out-of-lifetime access is possible.
So if StackLifetime can't prove that the instruction always uses
the variable when it's still alive, we consider it unsafe.
Added:
Modified:
llvm/lib/Analysis/StackSafetyAnalysis.cpp
llvm/test/Analysis/StackSafetyAnalysis/local.ll
Removed:
################################################################################
diff --git a/llvm/lib/Analysis/StackSafetyAnalysis.cpp b/llvm/lib/Analysis/StackSafetyAnalysis.cpp
index 88aa5ce065ab..8ec69fc83725 100644
--- a/llvm/lib/Analysis/StackSafetyAnalysis.cpp
+++ b/llvm/lib/Analysis/StackSafetyAnalysis.cpp
@@ -297,6 +297,7 @@ bool StackSafetyLocalAnalysis::analyzeAllUses(Value *Ptr,
SmallPtrSet<const Value *, 16> Visited;
SmallVector<const Value *, 8> WorkList;
WorkList.push_back(Ptr);
+ const AllocaInst *AI = dyn_cast<AllocaInst>(Ptr);
// A DFS search through all uses of the alloca in bitcasts/PHI/GEPs/etc.
while (!WorkList.empty()) {
@@ -310,6 +311,10 @@ bool StackSafetyLocalAnalysis::analyzeAllUses(Value *Ptr,
switch (I->getOpcode()) {
case Instruction::Load: {
+ if (AI && !SL.isAliveAfter(AI, I)) {
+ US.updateRange(UnknownRange);
+ return false;
+ }
US.updateRange(
getAccessRange(UI, Ptr, DL.getTypeStoreSize(I->getType())));
break;
@@ -324,6 +329,10 @@ bool StackSafetyLocalAnalysis::analyzeAllUses(Value *Ptr,
US.updateRange(UnknownRange);
return false;
}
+ if (AI && !SL.isAliveAfter(AI, I)) {
+ US.updateRange(UnknownRange);
+ return false;
+ }
US.updateRange(getAccessRange(
UI, Ptr, DL.getTypeStoreSize(I->getOperand(0)->getType())));
break;
@@ -341,6 +350,11 @@ bool StackSafetyLocalAnalysis::analyzeAllUses(Value *Ptr,
if (I->isLifetimeStartOrEnd())
break;
+ if (AI && !SL.isAliveAfter(AI, I)) {
+ US.updateRange(UnknownRange);
+ return false;
+ }
+
if (const MemIntrinsic *MI = dyn_cast<MemIntrinsic>(I)) {
US.updateRange(getMemIntrinsicAccessRange(MI, UI, Ptr));
break;
diff --git a/llvm/test/Analysis/StackSafetyAnalysis/local.ll b/llvm/test/Analysis/StackSafetyAnalysis/local.ll
index ad4745c7befa..890d4dced335 100644
--- a/llvm/test/Analysis/StackSafetyAnalysis/local.ll
+++ b/llvm/test/Analysis/StackSafetyAnalysis/local.ll
@@ -476,8 +476,8 @@ define void @Overflow() {
; CHECK-LABEL: @Overflow dso_preemptable{{$}}
; CHECK-NEXT: args uses:
; CHECK-NEXT: allocas uses:
-; LOCAL: x[1]: empty-set, @LoadMinInt64(arg0, [-9223372036854775808,-9223372036854775807)){{$}}
-; GLOBAL: x[1]: full-set, @LoadMinInt64(arg0, [-9223372036854775808,-9223372036854775807)){{$}}
+; LOCAL-NEXT: x[1]: empty-set, @LoadMinInt64(arg0, [-9223372036854775808,-9223372036854775807)){{$}}
+; GLOBAL-NEXT: x[1]: full-set, @LoadMinInt64(arg0, [-9223372036854775808,-9223372036854775807)){{$}}
; CHECK-NOT: ]:
entry:
%x = alloca i8, align 4
@@ -491,7 +491,7 @@ define void @DeadBlock(i64* %p) {
; CHECK-NEXT: args uses:
; CHECK-NEXT: p[]: empty-set{{$}}
; CHECK-NEXT: allocas uses:
-; CHECK: x[1]: empty-set{{$}}
+; CHECK-NEXT: x[1]: empty-set{{$}}
; CHECK-NOT: ]:
entry:
%x = alloca i8, align 4
@@ -504,4 +504,83 @@ dead:
end:
ret void
-}
\ No newline at end of file
+}
+
+define void @LifeNotStarted() {
+; CHECK-LABEL: @LifeNotStarted dso_preemptable{{$}}
+; CHECK-NEXT: args uses:
+; CHECK-NEXT: allocas uses:
+; CHECK: x[1]: full-set{{$}}
+; CHECK: y[1]: full-set{{$}}
+; CHECK: z[1]: full-set{{$}}
+; CHECK-NOT: ]:
+entry:
+ %x = alloca i8, align 4
+ %y = alloca i8, align 4
+ %z = alloca i8, align 4
+
+ store i8 5, i8* %x
+ %n = load i8, i8* %y
+ call void @llvm.memset.p0i8.i32(i8* nonnull %z, i8 0, i32 1, i1 false)
+
+ call void @llvm.lifetime.start.p0i8(i64 1, i8* %x)
+ call void @llvm.lifetime.start.p0i8(i64 1, i8* %y)
+ call void @llvm.lifetime.start.p0i8(i64 1, i8* %z)
+
+ ret void
+}
+
+define void @LifeOK() {
+; CHECK-LABEL: @LifeOK dso_preemptable{{$}}
+; CHECK-NEXT: args uses:
+; CHECK-NEXT: allocas uses:
+; CHECK: x[1]: [0,1){{$}}
+; CHECK: y[1]: [0,1){{$}}
+; CHECK: z[1]: [0,1){{$}}
+; CHECK-NOT: ]:
+entry:
+ %x = alloca i8, align 4
+ %y = alloca i8, align 4
+ %z = alloca i8, align 4
+
+ call void @llvm.lifetime.start.p0i8(i64 1, i8* %x)
+ call void @llvm.lifetime.start.p0i8(i64 1, i8* %y)
+ call void @llvm.lifetime.start.p0i8(i64 1, i8* %z)
+
+ store i8 5, i8* %x
+ %n = load i8, i8* %y
+ call void @llvm.memset.p0i8.i32(i8* nonnull %z, i8 0, i32 1, i1 false)
+
+ ret void
+}
+
+define void @LifeEnded() {
+; CHECK-LABEL: @LifeEnded dso_preemptable{{$}}
+; CHECK-NEXT: args uses:
+; CHECK-NEXT: allocas uses:
+; CHECK: x[1]: full-set{{$}}
+; CHECK: y[1]: full-set{{$}}
+; CHECK: z[1]: full-set{{$}}
+; CHECK-NOT: ]:
+entry:
+ %x = alloca i8, align 4
+ %y = alloca i8, align 4
+ %z = alloca i8, align 4
+
+ call void @llvm.lifetime.start.p0i8(i64 1, i8* %x)
+ call void @llvm.lifetime.start.p0i8(i64 1, i8* %y)
+ call void @llvm.lifetime.start.p0i8(i64 1, i8* %z)
+
+ call void @llvm.lifetime.end.p0i8(i64 1, i8* %x)
+ call void @llvm.lifetime.end.p0i8(i64 1, i8* %y)
+ call void @llvm.lifetime.end.p0i8(i64 1, i8* %z)
+
+ store i8 5, i8* %x
+ %n = load i8, i8* %y
+ call void @llvm.memset.p0i8.i32(i8* nonnull %z, i8 0, i32 1, i1 false)
+
+ ret void
+}
+
+declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture)
+declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture)
\ No newline at end of file
More information about the llvm-commits
mailing list