[llvm] 57335b6 - [stack-safety] Allow to determine safe accesses.
Florian Mayer via llvm-commits
llvm-commits at lists.llvm.org
Fri Sep 10 11:24:16 PDT 2021
Author: Florian Mayer
Date: 2021-09-10T19:23:54+01:00
New Revision: 57335b6e2eaddfbef5d68b022fb1a65199c1cd86
URL: https://github.com/llvm/llvm-project/commit/57335b6e2eaddfbef5d68b022fb1a65199c1cd86
DIFF: https://github.com/llvm/llvm-project/commit/57335b6e2eaddfbef5d68b022fb1a65199c1cd86.diff
LOG: [stack-safety] Allow to determine safe accesses.
Reviewed By: vitalybuka
Differential Revision: https://reviews.llvm.org/D109503
Added:
Modified:
llvm/include/llvm/Analysis/StackSafetyAnalysis.h
llvm/lib/Analysis/StackSafetyAnalysis.cpp
llvm/test/Analysis/StackSafetyAnalysis/ipa-alias.ll
llvm/test/Analysis/StackSafetyAnalysis/ipa.ll
llvm/test/Analysis/StackSafetyAnalysis/local.ll
llvm/test/Analysis/StackSafetyAnalysis/memintrin.ll
Removed:
################################################################################
diff --git a/llvm/include/llvm/Analysis/StackSafetyAnalysis.h b/llvm/include/llvm/Analysis/StackSafetyAnalysis.h
index 59c1e3e3bd560..a028107e213ce 100644
--- a/llvm/include/llvm/Analysis/StackSafetyAnalysis.h
+++ b/llvm/include/llvm/Analysis/StackSafetyAnalysis.h
@@ -75,7 +75,12 @@ class StackSafetyGlobalInfo {
StackSafetyGlobalInfo &operator=(StackSafetyGlobalInfo &&);
~StackSafetyGlobalInfo();
+ // Whether we can prove that all accesses to this Alloca are in-range and
+ // during its lifetime.
bool isSafe(const AllocaInst &AI) const;
+ // Whether we can prove that an instruction only accesses a live alloca in
+ // range.
+ bool accessIsSafe(const Instruction &I) const;
void print(raw_ostream &O) const;
void dump() const;
};
diff --git a/llvm/lib/Analysis/StackSafetyAnalysis.cpp b/llvm/lib/Analysis/StackSafetyAnalysis.cpp
index 628fc0647b29e..18e303e55a599 100644
--- a/llvm/lib/Analysis/StackSafetyAnalysis.cpp
+++ b/llvm/lib/Analysis/StackSafetyAnalysis.cpp
@@ -30,6 +30,7 @@
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <memory>
+#include <tuple>
using namespace llvm;
@@ -116,6 +117,7 @@ template <typename CalleeTy> struct UseInfo {
// Access range if the address (alloca or parameters).
// It is allowed to be empty-set when there are no known accesses.
ConstantRange Range;
+ std::map<const Instruction *, ConstantRange> Accesses;
// List of calls which pass address as an argument.
// Value is offset range of address from base address (alloca or calling
@@ -130,6 +132,9 @@ template <typename CalleeTy> struct UseInfo {
void updateRange(const ConstantRange &R) { Range = unionNoWrap(Range, R); }
void addRange(const Instruction *I, const ConstantRange &R) {
+ auto Ins = Accesses.emplace(I, R);
+ if (!Ins.second)
+ Ins.first->second = unionNoWrap(Ins.first->second, R);
updateRange(R);
}
};
@@ -225,6 +230,7 @@ struct StackSafetyInfo::InfoTy {
struct StackSafetyGlobalInfo::InfoTy {
GVToSSI Info;
SmallPtrSet<const AllocaInst *, 8> SafeAllocas;
+ SmallPtrSet<const Instruction *, 8> SafeAccesses;
};
namespace {
@@ -351,7 +357,7 @@ void StackSafetyLocalAnalysis::analyzeAllUses(Value *Ptr,
case Instruction::Load: {
if (AI && !SL.isAliveAfter(AI, I)) {
US.addRange(I, UnknownRange);
- return;
+ break;
}
US.addRange(I,
getAccessRange(UI, Ptr, DL.getTypeStoreSize(I->getType())));
@@ -365,11 +371,11 @@ void StackSafetyLocalAnalysis::analyzeAllUses(Value *Ptr,
if (V == I->getOperand(0)) {
// Stored the pointer - conservatively assume it may be unsafe.
US.addRange(I, UnknownRange);
- return;
+ break;
}
if (AI && !SL.isAliveAfter(AI, I)) {
US.addRange(I, UnknownRange);
- return;
+ break;
}
US.addRange(
I, getAccessRange(
@@ -382,7 +388,7 @@ void StackSafetyLocalAnalysis::analyzeAllUses(Value *Ptr,
// FIXME: Process parameters correctly. This is a leak only if we return
// alloca.
US.addRange(I, UnknownRange);
- return;
+ break;
case Instruction::Call:
case Instruction::Invoke: {
@@ -391,7 +397,7 @@ void StackSafetyLocalAnalysis::analyzeAllUses(Value *Ptr,
if (AI && !SL.isAliveAfter(AI, I)) {
US.addRange(I, UnknownRange);
- return;
+ break;
}
if (const MemIntrinsic *MI = dyn_cast<MemIntrinsic>(I)) {
@@ -402,7 +408,7 @@ void StackSafetyLocalAnalysis::analyzeAllUses(Value *Ptr,
const auto &CB = cast<CallBase>(*I);
if (!CB.isArgOperand(&UI)) {
US.addRange(I, UnknownRange);
- return;
+ break;
}
unsigned ArgNo = CB.getArgOperandNo(&UI);
@@ -420,7 +426,7 @@ void StackSafetyLocalAnalysis::analyzeAllUses(Value *Ptr,
dyn_cast<GlobalValue>(CB.getCalledOperand()->stripPointerCasts());
if (!Callee) {
US.addRange(I, UnknownRange);
- return;
+ break;
}
assert(isa<Function>(Callee) || isa<GlobalAlias>(Callee));
@@ -808,17 +814,27 @@ const StackSafetyGlobalInfo::InfoTy &StackSafetyGlobalInfo::getInfo() const {
}
}
Info.reset(new InfoTy{
- createGlobalStackSafetyInfo(std::move(Functions), Index), {}});
+ createGlobalStackSafetyInfo(std::move(Functions), Index), {}, {}});
+
+ std::map<const Instruction *, bool> AccessIsUnsafe;
for (auto &FnKV : Info->Info) {
for (auto &KV : FnKV.second.Allocas) {
++NumAllocaTotal;
const AllocaInst *AI = KV.first;
- if (getStaticAllocaSizeRange(*AI).contains(KV.second.Range)) {
+ auto AIRange = getStaticAllocaSizeRange(*AI);
+ if (AIRange.contains(KV.second.Range)) {
Info->SafeAllocas.insert(AI);
++NumAllocaStackSafe;
}
+ for (const auto &A : KV.second.Accesses)
+ AccessIsUnsafe[A.first] |= !AIRange.contains(A.second);
}
}
+
+ for (const auto &KV : AccessIsUnsafe)
+ if (!KV.second)
+ Info->SafeAccesses.insert(KV.first);
+
if (StackSafetyPrint)
print(errs());
}
@@ -888,6 +904,11 @@ bool StackSafetyGlobalInfo::isSafe(const AllocaInst &AI) const {
return Info.SafeAllocas.count(&AI);
}
+bool StackSafetyGlobalInfo::accessIsSafe(const Instruction &I) const {
+ const auto &Info = getInfo();
+ return Info.SafeAccesses.count(&I);
+}
+
void StackSafetyGlobalInfo::print(raw_ostream &O) const {
auto &SSI = getInfo().Info;
if (SSI.empty())
@@ -896,7 +917,13 @@ void StackSafetyGlobalInfo::print(raw_ostream &O) const {
for (auto &F : M.functions()) {
if (!F.isDeclaration()) {
SSI.find(&F)->second.print(O, F.getName(), &F);
- O << "\n";
+ O << " safe accesses:"
+ << "\n";
+ for (const auto &I : instructions(F)) {
+ if (accessIsSafe(I)) {
+ O << " " << I << "\n";
+ }
+ }
O << "\n";
}
}
diff --git a/llvm/test/Analysis/StackSafetyAnalysis/ipa-alias.ll b/llvm/test/Analysis/StackSafetyAnalysis/ipa-alias.ll
index 02f3b257bada2..2bce5b9716e2b 100644
--- a/llvm/test/Analysis/StackSafetyAnalysis/ipa-alias.ll
+++ b/llvm/test/Analysis/StackSafetyAnalysis/ipa-alias.ll
@@ -66,6 +66,7 @@ define void @PreemptableAliasCall() #0 {
; GLOBAL-NEXT: x1[1]: full-set, @PreemptableAliasWrite1(arg0, [0,1)){{$}}
; LOCAL-NEXT: x2[1]: empty-set, @AliasToPreemptableAliasWrite1(arg0, [0,1)){{$}}
; GLOBAL-NEXT: x2[1]: [0,1), @AliasToPreemptableAliasWrite1(arg0, [0,1)){{$}}
+; GLOBAL-NEXT: safe accesses:
; CHECK-EMPTY:
entry:
%x1 = alloca i8
@@ -85,6 +86,7 @@ define void @InterposableAliasCall() #0 {
; LOCAL-NEXT: x[1]: empty-set, @InterposableAliasWrite1(arg0, [0,1)){{$}}
; NOLTO-NEXT: x[1]: full-set, @InterposableAliasWrite1(arg0, [0,1)){{$}}
; LTO-NEXT: x[1]: [0,1), @InterposableAliasWrite1(arg0, [0,1)){{$}}
+; GLOBAL-NEXT: safe accesses:
; CHECK-EMPTY:
entry:
%x = alloca i8
@@ -100,6 +102,7 @@ define void @AliasCall() #0 {
; CHECK-NEXT: allocas uses:
; LOCAL-NEXT: x[1]: empty-set, @AliasWrite1(arg0, [0,1)){{$}}
; GLOBAL-NEXT: x[1]: [0,1), @AliasWrite1(arg0, [0,1)){{$}}
+; GLOBAL-NEXT: safe accesses:
; CHECK-EMPTY:
entry:
%x = alloca i8
@@ -116,6 +119,7 @@ define void @BitcastAliasCall() #0 {
; GLOBAL-NEXT: x1[4]: [0,1), @BitcastAliasWrite1(arg0, [0,1)){{$}}
; LOCAL-NEXT: x2[1]: empty-set, @AliasToBitcastAliasWrite1(arg0, [0,1)){{$}}
; GLOBAL-NEXT: x2[1]: [0,1), @AliasToBitcastAliasWrite1(arg0, [0,1)){{$}}
+; GLOBAL-NEXT: safe accesses:
; CHECK-EMPTY:
entry:
%x1 = alloca i32
@@ -131,4 +135,5 @@ entry:
; CHECK-NEXT: args uses:
; CHECK-NEXT: p[]: [0,1){{$}}
; CHECK-NEXT: allocas uses:
+; GLOBAL-NEXT: safe accesses:
; CHECK-EMPTY:
diff --git a/llvm/test/Analysis/StackSafetyAnalysis/ipa.ll b/llvm/test/Analysis/StackSafetyAnalysis/ipa.ll
index fb63d53ae22f2..69ec4dac88c99 100644
--- a/llvm/test/Analysis/StackSafetyAnalysis/ipa.ll
+++ b/llvm/test/Analysis/StackSafetyAnalysis/ipa.ll
@@ -126,6 +126,7 @@ define void @f1() #0 {
; CHECK-NEXT: allocas uses:
; LOCAL-NEXT: x[4]: empty-set, @Write8(arg0, [0,1)){{$}}
; GLOBAL-NEXT: x[4]: [0,8), @Write8(arg0, [0,1)){{$}}
+; GLOBAL-NEXT: safe accesses:
; CHECK-EMPTY:
entry:
%x = alloca i32, align 4
@@ -141,6 +142,7 @@ define void @f2() #0 {
; CHECK-NEXT: allocas uses:
; LOCAL-NEXT: x[4]: empty-set, @Write1(arg0, [0,1)){{$}}
; GLOBAL-NEXT: x[4]: [0,1), @Write1(arg0, [0,1)){{$}}
+; GLOBAL-NEXT: safe accesses:
; CHECK-EMPTY:
entry:
%x = alloca i32, align 4
@@ -156,6 +158,7 @@ define void @f3() #0 {
; CHECK-NEXT: allocas uses:
; LOCAL-NEXT: x[4]: empty-set, @Write4(arg0, [0,1)){{$}}
; GLOBAL-NEXT: x[4]: [0,4), @Write4(arg0, [0,1)){{$}}
+; GLOBAL-NEXT: safe accesses:
; CHECK-EMPTY:
entry:
%x = alloca i32, align 4
@@ -171,6 +174,7 @@ define void @f4() #0 {
; CHECK-NEXT: allocas uses:
; LOCAL-NEXT: x[4]: empty-set, @Write1(arg0, [1,2)){{$}}
; GLOBAL-NEXT: x[4]: [1,2), @Write1(arg0, [1,2)){{$}}
+; GLOBAL-NEXT: safe accesses:
; CHECK-EMPTY:
entry:
%x = alloca i32, align 4
@@ -187,6 +191,7 @@ define void @f5() #0 {
; CHECK-NEXT: allocas uses:
; LOCAL-NEXT: empty-set, @Write4(arg0, [1,2)){{$}}
; GLOBAL-NEXT: [1,5), @Write4(arg0, [1,2)){{$}}
+; GLOBAL-NEXT: safe accesses:
; CHECK-EMPTY:
entry:
%x = alloca i32, align 4
@@ -203,6 +208,7 @@ define void @f6() #0 {
; CHECK-NEXT: allocas uses:
; LOCAL-NEXT: x[4]: empty-set, @ExternalCall(arg0, [0,1)){{$}}
; GLOBAL-NEXT: x[4]: full-set, @ExternalCall(arg0, [0,1)){{$}}
+; GLOBAL-NEXT: safe accesses:
; CHECK-EMPTY:
entry:
%x = alloca i32, align 4
@@ -218,6 +224,7 @@ define void @PreemptableCall() #0 {
; CHECK-NEXT: allocas uses:
; LOCAL-NEXT: x[4]: empty-set, @PreemptableWrite1(arg0, [0,1)){{$}}
; GLOBAL-NEXT: x[4]: full-set, @PreemptableWrite1(arg0, [0,1)){{$}}
+; GLOBAL-NEXT: safe accesses:
; CHECK-EMPTY:
entry:
%x = alloca i32, align 4
@@ -234,6 +241,7 @@ define void @InterposableCall() #0 {
; LOCAL-NEXT: x[4]: empty-set, @InterposableWrite1(arg0, [0,1)){{$}}
; NOLTO-NEXT: x[4]: full-set, @InterposableWrite1(arg0, [0,1)){{$}}
; LTO-NEXT: x[4]: [0,1), @InterposableWrite1(arg0, [0,1)){{$}}
+; GLOBAL-NEXT: safe accesses:
; CHECK-EMPTY:
entry:
%x = alloca i32, align 4
@@ -249,6 +257,7 @@ define void @PrivateCall() #0 {
; CHECK-NEXT: allocas uses:
; LOCAL-NEXT: x[4]: empty-set, @PrivateWrite1(arg0, [0,1)){{$}}
; GLOBAL-NEXT: x[4]: [0,1), @PrivateWrite1(arg0, [0,1)){{$}}
+; GLOBAL-NEXT: safe accesses:
; CHECK-EMPTY:
entry:
%x = alloca i32, align 4
@@ -262,6 +271,7 @@ define private void @PrivateWrite1(i8* %p) #0 {
; CHECK-NEXT: args uses:
; CHECK-NEXT: p[]: [0,1){{$}}
; CHECK-NEXT: allocas uses:
+; GLOBAL-NEXT: safe accesses:
; CHECK-EMPTY:
entry:
store i8 0, i8* %p, align 1
@@ -276,6 +286,7 @@ define void @f7() #0 {
; CHECK-NEXT: allocas uses:
; LOCAL-NEXT: x[4]: empty-set, @ReturnDependent(arg0, [0,1)){{$}}
; GLOBAL-NEXT: x[4]: full-set, @ReturnDependent(arg0, [0,1)){{$}}
+; GLOBAL-NEXT: safe accesses:
; CHECK-EMPTY:
entry:
%x = alloca i32, align 4
@@ -290,6 +301,7 @@ define void @f8left() #0 {
; CHECK-NEXT: allocas uses:
; LOCAL-NEXT: x[8]: empty-set, @Rec2(arg0, [2,3)){{$}}
; GLOBAL-NEXT: x[8]: [0,4), @Rec2(arg0, [2,3)){{$}}
+; GLOBAL-NEXT: safe accesses:
; CHECK-EMPTY:
entry:
%x = alloca i64, align 4
@@ -306,6 +318,7 @@ define void @f8right() #0 {
; CHECK-NEXT: allocas uses:
; LOCAL-NEXT: x[8]: empty-set, @Rec2(arg0, [6,7)){{$}}
; GLOBAL-NEXT: x[8]: [4,8), @Rec2(arg0, [6,7)){{$}}
+; GLOBAL-NEXT: safe accesses:
; CHECK-EMPTY:
entry:
%x = alloca i64, align 4
@@ -322,6 +335,7 @@ define void @f8oobleft() #0 {
; CHECK-NEXT: allocas uses:
; LOCAL-NEXT: x[8]: empty-set, @Rec2(arg0, [1,2)){{$}}
; GLOBAL-NEXT: x[8]: [-1,3), @Rec2(arg0, [1,2)){{$}}
+; GLOBAL-NEXT: safe accesses:
; CHECK-EMPTY:
entry:
%x = alloca i64, align 4
@@ -338,6 +352,7 @@ define void @f8oobright() #0 {
; CHECK-NEXT: allocas uses:
; LOCAL-NEXT: x[8]: empty-set, @Rec2(arg0, [7,8)){{$}}
; GLOBAL-NEXT: x[8]: [5,9), @Rec2(arg0, [7,8)){{$}}
+; GLOBAL-NEXT: safe accesses:
; CHECK-EMPTY:
entry:
%x = alloca i64, align 4
@@ -354,6 +369,7 @@ define void @TwoArguments() #0 {
; CHECK-NEXT: allocas uses:
; LOCAL-NEXT: x[8]: empty-set, @Write4_2(arg0, [4,5)), @Write4_2(arg1, [0,1)){{$}}
; GLOBAL-NEXT: x[8]: [0,8), @Write4_2(arg0, [4,5)), @Write4_2(arg1, [0,1)){{$}}
+; GLOBAL-NEXT: safe accesses:
; CHECK-EMPTY:
entry:
%x = alloca i64, align 4
@@ -369,6 +385,7 @@ define void @TwoArgumentsOOBOne() #0 {
; CHECK-NEXT: allocas uses:
; LOCAL-NEXT: x[8]: empty-set, @Write4_2(arg0, [5,6)), @Write4_2(arg1, [0,1)){{$}}
; GLOBAL-NEXT: x[8]: [0,9), @Write4_2(arg0, [5,6)), @Write4_2(arg1, [0,1)){{$}}
+; GLOBAL-NEXT: safe accesses:
; CHECK-EMPTY:
entry:
%x = alloca i64, align 4
@@ -384,6 +401,7 @@ define void @TwoArgumentsOOBOther() #0 {
; CHECK-NEXT: allocas uses:
; LOCAL-NEXT: x[8]: empty-set, @Write4_2(arg0, [4,5)), @Write4_2(arg1, [-1,0)){{$}}
; GLOBAL-NEXT: x[8]: [-1,8), @Write4_2(arg0, [4,5)), @Write4_2(arg1, [-1,0)){{$}}
+; GLOBAL-NEXT: safe accesses:
; CHECK-EMPTY:
entry:
%x = alloca i64, align 4
@@ -400,6 +418,7 @@ define void @TwoArgumentsOOBBoth() #0 {
; CHECK-NEXT: allocas uses:
; LOCAL-NEXT: x[8]: empty-set, @Write4_2(arg0, [5,6)), @Write4_2(arg1, [-1,0)){{$}}
; GLOBAL-NEXT: x[8]: [-1,9), @Write4_2(arg0, [5,6)), @Write4_2(arg1, [-1,0)){{$}}
+; GLOBAL-NEXT: safe accesses:
; CHECK-EMPTY:
entry:
%x = alloca i64, align 4
@@ -417,6 +436,9 @@ define i32 @TestRecursiveNoOffset(i32* %p, i32 %size) #0 {
; GLOBAL-NEXT: p[]: full-set, @RecursiveNoOffset(arg0, [0,1)){{$}}
; CHECK-NEXT: allocas uses:
; CHECK-NEXT: sum[4]: [0,4), @RecursiveNoOffset(arg2, [0,1)){{$}}
+; GLOBAL-NEXT: safe accesses:
+; GLOBAL-NEXT: store i32 0, i32* %sum, align 4
+; GLOBAL-NEXT: %1 = load i32, i32* %sum, align 4
; CHECK-EMPTY:
entry:
%sum = alloca i32, align 4
@@ -433,6 +455,7 @@ define void @TestRecursiveWithOffset(i32 %size) #0 {
; CHECK-NEXT: allocas uses:
; LOCAL-NEXT: sum[64]: empty-set, @RecursiveWithOffset(arg1, [0,1)){{$}}
; GLOBAL-NEXT: sum[64]: full-set, @RecursiveWithOffset(arg1, [0,1)){{$}}
+; GLOBAL-NEXT: safe accesses:
; CHECK-EMPTY:
entry:
%sum = alloca i32, i64 16, align 4
@@ -447,6 +470,7 @@ define void @TestUpdateArg() #0 {
; CHECK-NEXT: allocas uses:
; LOCAL-NEXT: x[16]: empty-set, @WriteAndReturn8(arg0, [0,1)){{$}}
; GLOBAL-NEXT: x[16]: full-set, @WriteAndReturn8(arg0, [0,1)){{$}}
+; GLOBAL-NEXT: safe accesses:
; CHECK-EMPTY:
entry:
%x = alloca i8, i64 16, align 4
@@ -460,6 +484,7 @@ define void @TestCrossModuleOnce() #0 {
; CHECK-NEXT: allocas uses:
; LOCAL-NEXT: y[1]: empty-set, @Write1SameModule(arg0, [0,1)){{$}}
; GLOBAL-NEXT: y[1]: [0,1), @Write1SameModule(arg0, [0,1)){{$}}
+; GLOBAL-NEXT: safe accesses:
; CHECK-EMPTY:
entry:
%y = alloca i8, align 4
@@ -473,6 +498,7 @@ define void @TestCrossModuleTwice() #0 {
; CHECK-NEXT: allocas uses:
; LOCAL-NEXT: z[1]: empty-set, @Write1DiffModule(arg0, [0,1)){{$}}
; GLOBAL-NEXT: z[1]: [0,1), @Write1DiffModule(arg0, [0,1)){{$}}
+; GLOBAL-NEXT: safe accesses:
; CHECK-EMPTY:
entry:
%z = alloca i8, align 4
@@ -486,6 +512,7 @@ define void @TestCrossModuleConflict() #0 {
; CHECK-NEXT: allocas uses:
; LOCAL-NEXT: x[1]: empty-set, @Write1Private(arg0, [0,1)){{$}}
; GLOBAL-NEXT: x[1]: [-1,0), @Write1Private(arg0, [0,1)){{$}}
+; GLOBAL-NEXT: safe accesses:
; CHECK-EMPTY:
entry:
%x = alloca i8, align 4
@@ -501,6 +528,7 @@ define void @TestCrossModuleWeak() #0 {
; LOCAL-NEXT: x[1]: empty-set, @Write1Weak(arg0, [0,1)){{$}}
; NOLTO-NEXT: x[1]: [1,2), @Write1Weak(arg0, [0,1)){{$}}
; LTO-NEXT: x[1]: full-set, @Write1Weak(arg0, [0,1)){{$}}
+; GLOBAL-NEXT: safe accesses:
; CHECK-EMPTY:
entry:
%x = alloca i8, align 4
@@ -534,12 +562,14 @@ entry:
; CHECK-NEXT: args uses:
; CHECK-NEXT: p[]: [0,1){{$}}
; CHECK-NEXT: allocas uses:
+; GLOBAL-NEXT: safe accesses:
; CHECK-EMPTY:
; CHECK-LABEL: @Write4{{$}}
; CHECK-NEXT: args uses:
; CHECK-NEXT: p[]: [0,4){{$}}
; CHECK-NEXT: allocas uses:
+; GLOBAL-NEXT: safe accesses:
; CHECK-EMPTY:
; CHECK-LABEL: @Write4_2{{$}}
@@ -547,36 +577,42 @@ entry:
; CHECK-NEXT: p[]: [0,4){{$}}
; CHECK-NEXT: q[]: [0,4){{$}}
; CHECK-NEXT: allocas uses:
+; GLOBAL-NEXT: safe accesses:
; CHECK-EMPTY:
; CHECK-LABEL: @Write8{{$}}
; CHECK-NEXT: args uses:
; CHECK-NEXT: p[]: [0,8){{$}}
; CHECK-NEXT: allocas uses:
+; GLOBAL-NEXT: safe accesses:
; CHECK-EMPTY:
; CHECK-LABEL: @WriteAndReturn8{{$}}
; CHECK-NEXT: args uses:
; CHECK-NEXT: p[]: full-set{{$}}
; CHECK-NEXT: allocas uses:
+; GLOBAL-NEXT: safe accesses:
; CHECK-EMPTY:
; CHECK-LABEL: @PreemptableWrite1 dso_preemptable{{$}}
; CHECK-NEXT: args uses:
; CHECK-NEXT: p[]: [0,1){{$}}
; CHECK-NEXT: allocas uses:
+; GLOBAL-NEXT: safe accesses:
; CHECK-EMPTY:
; CHECK-LABEL: @InterposableWrite1 interposable{{$}}
; CHECK-NEXT: args uses:
; CHECK-NEXT: p[]: [0,1){{$}}
; CHECK-NEXT: allocas uses:
+; GLOBAL-NEXT: safe accesses:
; CHECK-EMPTY:
; CHECK-LABEL: @ReturnDependent{{$}}
; CHECK-NEXT: args uses:
; CHECK-NEXT: p[]: full-set{{$}}
; CHECK-NEXT: allocas uses:
+; GLOBAL-NEXT: safe accesses:
; CHECK-EMPTY:
; CHECK-LABEL: @Rec0{{$}}
@@ -584,6 +620,7 @@ entry:
; LOCAL-NEXT: p[]: empty-set, @Write4(arg0, [2,3)){{$}}
; GLOBAL-NEXT: p[]: [2,6)
; CHECK-NEXT: allocas uses:
+; GLOBAL-NEXT: safe accesses:
; CHECK-EMPTY:
; CHECK-LABEL: @Rec1{{$}}
@@ -591,6 +628,7 @@ entry:
; LOCAL-NEXT: p[]: empty-set, @Rec0(arg0, [1,2)){{$}}
; GLOBAL-NEXT: p[]: [3,7)
; CHECK-NEXT: allocas uses:
+; GLOBAL-NEXT: safe accesses:
; CHECK-EMPTY:
; CHECK-LABEL: @Rec2{{$}}
@@ -598,6 +636,7 @@ entry:
; LOCAL-NEXT: p[]: empty-set, @Rec1(arg0, [-5,-4)){{$}}
; GLOBAL-NEXT: p[]: [-2,2)
; CHECK-NEXT: allocas uses:
+; GLOBAL-NEXT: safe accesses:
; CHECK-EMPTY:
; CHECK-LABEL: @RecursiveNoOffset{{$}}
@@ -606,6 +645,7 @@ entry:
; GLOBAL-NEXT: p[]: full-set, @RecursiveNoOffset(arg0, [4,5)){{$}}
; CHECK-NEXT: acc[]: [0,4), @RecursiveNoOffset(arg2, [0,1)){{$}}
; CHECK-NEXT: allocas uses:
+; GLOBAL-NEXT: safe accesses:
; CHECK-EMPTY:
; CHECK-LABEL: @RecursiveWithOffset{{$}}
@@ -613,12 +653,14 @@ entry:
; LOCAL-NEXT: acc[]: [0,4), @RecursiveWithOffset(arg1, [4,5)){{$}}
; GLOBAL-NEXT: acc[]: full-set, @RecursiveWithOffset(arg1, [4,5)){{$}}
; CHECK-NEXT: allocas uses:
+; GLOBAL-NEXT: safe accesses:
; CHECK-EMPTY:
; CHECK-LABEL: @ReturnAlloca
; CHECK-NEXT: args uses:
; CHECK-NEXT: allocas uses:
; CHECK-NEXT: x[8]: full-set
+; GLOBAL-NEXT: safe accesses:
; CHECK-EMPTY:
; INDEX-LABEL: ^0 = module:
diff --git a/llvm/test/Analysis/StackSafetyAnalysis/local.ll b/llvm/test/Analysis/StackSafetyAnalysis/local.ll
index 5fb59963609ec..6c0fbef8a2661 100644
--- a/llvm/test/Analysis/StackSafetyAnalysis/local.ll
+++ b/llvm/test/Analysis/StackSafetyAnalysis/local.ll
@@ -11,12 +11,15 @@ declare void @llvm.memcpy.p0i8.p0i8.i32(i8* %dest, i8* %src, i32 %len, i1 %isvol
declare void @llvm.memmove.p0i8.p0i8.i32(i8* %dest, i8* %src, i32 %len, i1 %isvolatile)
declare void @llvm.memset.p0i8.i64(i8* %dest, i8 %val, i64 %len, i1 %isvolatile)
+declare void @unknown_call(i8* %dest)
+
; Address leaked.
define void @LeakAddress() {
; CHECK-LABEL: @LeakAddress dso_preemptable{{$}}
; CHECK-NEXT: args uses:
; CHECK-NEXT: allocas uses:
; CHECK-NEXT: x[4]: full-set{{$}}
+; GLOBAL-NEXT: safe accesses:
; CHECK-EMPTY:
entry:
%x = alloca i32, align 4
@@ -30,6 +33,8 @@ define void @StoreInBounds() {
; CHECK-NEXT: args uses:
; CHECK-NEXT: allocas uses:
; CHECK-NEXT: x[4]: [0,1){{$}}
+; GLOBAL-NEXT: safe accesses:
+; GLOBAL-NEXT: store i8 0, i8* %x1, align 1
; CHECK-EMPTY:
entry:
%x = alloca i32, align 4
@@ -43,6 +48,8 @@ define void @StoreInBounds2() {
; CHECK-NEXT: args uses:
; CHECK-NEXT: allocas uses:
; CHECK-NEXT: x[4]: [0,4){{$}}
+; GLOBAL-NEXT: safe accesses:
+; GLOBAL-NEXT: store i32 0, i32* %x, align 4
; CHECK-EMPTY:
entry:
%x = alloca i32, align 4
@@ -55,6 +62,8 @@ define void @StoreInBounds3() {
; CHECK-NEXT: args uses:
; CHECK-NEXT: allocas uses:
; CHECK-NEXT: x[4]: [2,3){{$}}
+; GLOBAL-NEXT: safe accesses:
+; GLOBAL-NEXT: store i8 0, i8* %x2, align 1
; CHECK-EMPTY:
entry:
%x = alloca i32, align 4
@@ -70,6 +79,7 @@ define void @StoreInBounds4() {
; CHECK-NEXT: args uses:
; CHECK-NEXT: allocas uses:
; CHECK-NEXT: x[4]: full-set{{$}}
+; GLOBAL-NEXT: safe accesses:
; CHECK-EMPTY:
entry:
%x = alloca i32, align 4
@@ -85,6 +95,7 @@ define dso_local void @WriteMinMax(i8* %p) {
; CHECK-NEXT: args uses:
; CHECK-NEXT: p[]: full-set
; CHECK-NEXT: allocas uses:
+; GLOBAL-NEXT: safe accesses:
; CHECK-EMPTY:
entry:
%p1 = getelementptr i8, i8* %p, i64 9223372036854775805
@@ -99,6 +110,7 @@ define dso_local void @WriteMax(i8* %p) {
; CHECK-NEXT: args uses:
; CHECK-NEXT: p[]: [-9223372036854775807,9223372036854775806)
; CHECK-NEXT: allocas uses:
+; GLOBAL-NEXT: safe accesses:
; CHECK-EMPTY:
entry:
call void @llvm.memset.p0i8.i64(i8* %p, i8 1, i64 9223372036854775806, i1 0)
@@ -112,6 +124,7 @@ define void @StoreOutOfBounds() {
; CHECK-NEXT: args uses:
; CHECK-NEXT: allocas uses:
; CHECK-NEXT: x[4]: [2,6){{$}}
+; GLOBAL-NEXT: safe accesses:
; CHECK-EMPTY:
entry:
%x = alloca i32, align 4
@@ -128,6 +141,8 @@ define void @LoadInBounds() {
; CHECK-NEXT: args uses:
; CHECK-NEXT: allocas uses:
; CHECK-NEXT: x[4]: [0,1){{$}}
+; GLOBAL-NEXT: safe accesses:
+; GLOBAL-NEXT: %v = load i8, i8* %x1, align 1
; CHECK-EMPTY:
entry:
%x = alloca i32, align 4
@@ -141,6 +156,7 @@ define void @LoadOutOfBounds() {
; CHECK-NEXT: args uses:
; CHECK-NEXT: allocas uses:
; CHECK-NEXT: x[4]: [2,6){{$}}
+; GLOBAL-NEXT: safe accesses:
; CHECK-EMPTY:
entry:
%x = alloca i32, align 4
@@ -157,6 +173,7 @@ define i8* @Ret() {
; CHECK-NEXT: args uses:
; CHECK-NEXT: allocas uses:
; CHECK-NEXT: x[4]: full-set{{$}}
+; GLOBAL-NEXT: safe accesses:
; CHECK-EMPTY:
entry:
%x = alloca i32, align 4
@@ -173,6 +190,7 @@ define void @DirectCall() {
; CHECK-NEXT: allocas uses:
; LOCAL-NEXT: x[8]: empty-set, @Foo(arg0, [2,3)){{$}}
; GLOBAL-NEXT: x[8]: full-set, @Foo(arg0, [2,3)){{$}}
+; GLOBAL-NEXT: safe accesses:
; CHECK-EMPTY:
entry:
%x = alloca i64, align 4
@@ -190,6 +208,7 @@ define void @IndirectCall(void (i8*)* %p) {
; CHECK-NEXT: p[]: full-set{{$}}
; CHECK-NEXT: allocas uses:
; CHECK-NEXT: x[4]: full-set{{$}}
+; GLOBAL-NEXT: safe accesses:
; CHECK-EMPTY:
entry:
%x = alloca i32, align 4
@@ -204,6 +223,8 @@ define void @NonConstantOffset(i1 zeroext %z) {
; CHECK-NEXT: allocas uses:
; FIXME: SCEV can't look through selects.
; CHECK-NEXT: x[4]: [0,4){{$}}
+; GLOBAL-NEXT: safe accesses:
+; GLOBAL-NEXT: store i8 0, i8* %x2, align 1
; CHECK-EMPTY:
entry:
%x = alloca i32, align 4
@@ -219,6 +240,7 @@ define void @NegativeOffset() {
; CHECK-NEXT: args uses:
; CHECK-NEXT: allocas uses:
; CHECK-NEXT: x[40]: [-1600000000000,-1599999999996){{$}}
+; GLOBAL-NEXT: safe accesses:
; CHECK-EMPTY:
entry:
%x = alloca i32, i32 10, align 4
@@ -232,6 +254,7 @@ define void @PossiblyNegativeOffset(i16 %z) {
; CHECK-NEXT: args uses:
; CHECK-NEXT: allocas uses:
; CHECK-NEXT: x[40]: [-131072,131072){{$}}
+; GLOBAL-NEXT: safe accesses:
; CHECK-EMPTY:
entry:
%x = alloca i32, i32 10, align 4
@@ -245,6 +268,7 @@ define void @NonConstantOffsetOOB(i1 zeroext %z) {
; CHECK-NEXT: args uses:
; CHECK-NEXT: allocas uses:
; CHECK-NEXT: x[4]: [0,6){{$}}
+; GLOBAL-NEXT: safe accesses:
; CHECK-EMPTY:
entry:
%x = alloca i32, align 4
@@ -260,6 +284,8 @@ define void @ArrayAlloca() {
; CHECK-NEXT: args uses:
; CHECK-NEXT: allocas uses:
; CHECK-NEXT: x[40]: [36,40){{$}}
+; GLOBAL-NEXT: safe accesses:
+; GLOBAL-NEXT: store i32 0, i32* %x3, align 1
; CHECK-EMPTY:
entry:
%x = alloca i32, i32 10, align 4
@@ -275,6 +301,7 @@ define void @ArrayAllocaOOB() {
; CHECK-NEXT: args uses:
; CHECK-NEXT: allocas uses:
; CHECK-NEXT: x[40]: [37,41){{$}}
+; GLOBAL-NEXT: safe accesses:
; CHECK-EMPTY:
entry:
%x = alloca i32, i32 10, align 4
@@ -290,6 +317,7 @@ define void @DynamicAllocaUnused(i64 %size) {
; CHECK-NEXT: args uses:
; CHECK-NEXT: allocas uses:
; CHECK-NEXT: x[0]: empty-set{{$}}
+; GLOBAL-NEXT: safe accesses:
; CHECK-EMPTY:
entry:
%x = alloca i32, i64 %size, align 16
@@ -302,6 +330,7 @@ define void @DynamicAlloca(i64 %size) {
; CHECK-NEXT: args uses:
; CHECK-NEXT: allocas uses:
; CHECK-NEXT: x[0]: [0,4){{$}}
+; GLOBAL-NEXT: safe accesses:
; CHECK-EMPTY:
entry:
%x = alloca i32, i64 %size, align 16
@@ -316,6 +345,7 @@ define void @DynamicAllocaFiniteSizeRange(i1 zeroext %z) {
; CHECK-NEXT: args uses:
; CHECK-NEXT: allocas uses:
; CHECK-NEXT: x[0]: [0,4){{$}}
+; GLOBAL-NEXT: safe accesses:
; CHECK-EMPTY:
entry:
%size = select i1 %z, i64 3, i64 5
@@ -329,6 +359,8 @@ define signext i8 @SimpleLoop() {
; CHECK-NEXT: args uses:
; CHECK-NEXT: allocas uses:
; CHECK-NEXT: x[10]: [0,10){{$}}
+; GLOBAL-NEXT: safe accesses:
+; GLOBAL-NEXT: %1 = load volatile i8, i8* %p.09, align 1
; CHECK-EMPTY:
entry:
%x = alloca [10 x i8], align 1
@@ -355,6 +387,7 @@ define signext i8 @SimpleLoopOOB() {
; CHECK-NEXT: args uses:
; CHECK-NEXT: allocas uses:
; CHECK-NEXT: x[10]: [0,11){{$}}
+; GLOBAL-NEXT: safe accesses:
; CHECK-EMPTY:
entry:
%x = alloca [10 x i8], align 1
@@ -381,6 +414,7 @@ define dso_local void @SizeCheck(i32 %sz) {
; CHECK-NEXT: args uses:
; CHECK-NEXT: allocas uses:
; CHECK-NEXT: x1[128]: [0,4294967295){{$}}
+; GLOBAL-NEXT: safe accesses:
; CHECK-EMPTY:
entry:
%x1 = alloca [128 x i8], align 16
@@ -405,6 +439,7 @@ define void @Scalable(<vscale x 4 x i32>* %p, <vscale x 4 x i32>* %unused, <vsca
; CHECK-NEXT: unused[]: empty-set
; CHECK-NEXT: allocas uses:
; CHECK-NEXT: x[0]: [0,1){{$}}
+; GLOBAL-NEXT: safe accesses:
; CHECK-EMPTY:
entry:
%x = alloca <vscale x 4 x i32>, align 4
@@ -422,6 +457,8 @@ define void @ZeroSize(%zerosize_type *%p) {
; CHECK-NEXT: p[]: empty-set
; CHECK-NEXT: allocas uses:
; CHECK-NEXT: x[0]: empty-set
+; GLOBAL-NEXT: safe accesses:
+; GLOBAL-NEXT: store %zerosize_type undef, %zerosize_type* %x, align 4
; CHECK-EMPTY:
entry:
%x = alloca %zerosize_type, align 4
@@ -436,6 +473,7 @@ define void @OperandBundle() {
; CHECK-NEXT: args uses:
; CHECK-NEXT: allocas uses:
; CHECK-NEXT: a[4]: full-set
+; GLOBAL-NEXT: safe accesses:
; CHECK-EMPTY:
entry:
%a = alloca i32, align 4
@@ -447,6 +485,7 @@ define void @ByVal(i16* byval(i16) %p) {
; CHECK-LABEL: @ByVal dso_preemptable{{$}}
; CHECK-NEXT: args uses:
; CHECK-NEXT: allocas uses:
+ ; GLOBAL-NEXT: safe accesses:
; CHECK-EMPTY:
entry:
ret void
@@ -458,6 +497,9 @@ define void @TestByVal() {
; CHECK-NEXT: allocas uses:
; CHECK-NEXT: x[2]: [0,2)
; CHECK-NEXT: y[8]: [0,2)
+; GLOBAL-NEXT: safe accesses:
+; GLOBAL-NEXT: call void @ByVal(i16* byval(i16) %x)
+; GLOBAL-NEXT: call void @ByVal(i16* byval(i16) %y1)
; CHECK-EMPTY:
entry:
%x = alloca i16, align 4
@@ -477,6 +519,7 @@ define void @TestByValArray() {
; CHECK-NEXT: args uses:
; CHECK-NEXT: allocas uses:
; CHECK-NEXT: z[800000]: [500000,1300000)
+; GLOBAL-NEXT: safe accesses:
; CHECK-EMPTY:
entry:
%z = alloca [100000 x i64], align 4
@@ -492,6 +535,7 @@ define dso_local i8 @LoadMinInt64(i8* %p) {
; CHECK-NEXT: args uses:
; CHECK-NEXT: p[]: [-9223372036854775808,-9223372036854775807){{$}}
; CHECK-NEXT: allocas uses:
+ ; GLOBAL-NEXT: safe accesses:
; CHECK-EMPTY:
%p2 = getelementptr i8, i8* %p, i64 -9223372036854775808
%v = load i8, i8* %p2, align 1
@@ -504,6 +548,7 @@ define void @Overflow() {
; CHECK-NEXT: allocas uses:
; LOCAL-NEXT: x[1]: empty-set, @LoadMinInt64(arg0, [-9223372036854775808,-9223372036854775807)){{$}}
; GLOBAL-NEXT: x[1]: full-set, @LoadMinInt64(arg0, [-9223372036854775808,-9223372036854775807)){{$}}
+; GLOBAL-NEXT: safe accesses:
; CHECK-EMPTY:
entry:
%x = alloca i8, align 4
@@ -518,6 +563,7 @@ define void @DeadBlock(i64* %p) {
; CHECK-NEXT: p[]: empty-set{{$}}
; CHECK-NEXT: allocas uses:
; CHECK-NEXT: x[1]: empty-set{{$}}
+; GLOBAL-NEXT: safe accesses:
; CHECK-EMPTY:
entry:
%x = alloca i8, align 4
@@ -539,6 +585,7 @@ define void @LifeNotStarted() {
; CHECK: x[1]: full-set{{$}}
; CHECK: y[1]: full-set{{$}}
; CHECK: z[1]: full-set{{$}}
+; GLOBAL-NEXT: safe accesses:
; CHECK-EMPTY:
entry:
%x = alloca i8, align 4
@@ -563,6 +610,10 @@ define void @LifeOK() {
; CHECK: x[1]: [0,1){{$}}
; CHECK: y[1]: [0,1){{$}}
; CHECK: z[1]: [0,1){{$}}
+; GLOBAL-NEXT: safe accesses:
+; GLOBAL-NEXT: store i8 5, i8* %x
+; GLOBAL-NEXT: %n = load i8, i8* %y
+; GLOBAL-NEXT: call void @llvm.memset.p0i8.i32(i8* nonnull %z, i8 0, i32 1, i1 false)
; CHECK-EMPTY:
entry:
%x = alloca i8, align 4
@@ -587,6 +638,7 @@ define void @LifeEnded() {
; CHECK: x[1]: full-set{{$}}
; CHECK: y[1]: full-set{{$}}
; CHECK: z[1]: full-set{{$}}
+; GLOBAL-NEXT: safe accesses:
; CHECK-EMPTY:
entry:
%x = alloca i8, align 4
@@ -608,5 +660,236 @@ entry:
ret void
}
+define void @TwoAllocasOK() {
+; CHECK-LABEL: @TwoAllocasOK
+; CHECK-NEXT: args uses:
+; CHECK-NEXT: allocas uses:
+; CHECK: a[4]: [0,1){{$}}
+; CHECK: y[1]: [0,1){{$}}
+; GLOBAL-NEXT: safe accesses:
+; GLOBAL-NEXT: call void @llvm.memcpy.p0i8.p0i8.i32(i8* %y, i8* %x, i32 1, i1 false)
+; CHECK-EMPTY:
+entry:
+ %a = alloca i32, align 4
+ %x = bitcast i32* %a to i8*
+ %y = alloca i8, align 4
+ call void @llvm.memcpy.p0i8.p0i8.i32(i8* %y, i8* %x, i32 1, i1 false)
+ ret void
+}
+
+define void @TwoAllocasOOBDest() {
+; CHECK-LABEL: @TwoAllocasOOBDest
+; CHECK-NEXT: args uses:
+; CHECK-NEXT: allocas uses:
+; CHECK: a[4]: [0,4){{$}}
+; CHECK: y[1]: [0,4){{$}}
+; GLOBAL-NEXT: safe accesses:
+; CHECK-EMPTY:
+entry:
+ %a = alloca i32, align 4
+ %x = bitcast i32* %a to i8*
+ %y = alloca i8, align 4
+ call void @llvm.memcpy.p0i8.p0i8.i32(i8* %y, i8* %x, i32 4, i1 false)
+ ret void
+}
+
+define void @TwoAllocasOOBSource() {
+; CHECK-LABEL: @TwoAllocasOOBSource
+; CHECK-NEXT: args uses:
+; CHECK-NEXT: allocas uses:
+; CHECK: a[4]: [0,4){{$}}
+; CHECK: y[1]: [0,4){{$}}
+; GLOBAL-NEXT: safe accesses:
+; CHECK-EMPTY:
+entry:
+ %a = alloca i32, align 4
+ %x = bitcast i32* %a to i8*
+ %y = alloca i8, align 4
+ call void @llvm.memcpy.p0i8.p0i8.i32(i8* %x, i8* %y, i32 4, i1 false)
+ ret void
+}
+
+define void @TwoAllocasOOBBoth() {
+; CHECK-LABEL: @TwoAllocasOOBBoth
+; CHECK-NEXT: args uses:
+; CHECK-NEXT: allocas uses:
+; CHECK: a[4]: [0,5){{$}}
+; CHECK: y[1]: [0,5){{$}}
+; GLOBAL-NEXT: safe accesses:
+; CHECK-EMPTY:
+entry:
+ %a = alloca i32, align 4
+ %x = bitcast i32* %a to i8*
+ %y = alloca i8, align 4
+ call void @llvm.memcpy.p0i8.p0i8.i32(i8* %y, i8* %x, i32 5, i1 false)
+ ret void
+}
+
+define void @MixedAccesses() {
+; CHECK-LABEL: @MixedAccesses
+; CHECK-NEXT: args uses:
+; CHECK-NEXT: allocas uses:
+; CHECK: a[4]: [0,5){{$}}
+; GLOBAL-NEXT: safe accesses:
+; GLOBAL-NEXT: call void @llvm.memset.p0i8.i32(i8* %x, i8 1, i32 4, i1 false)
+; CHECK-EMPTY:
+entry:
+ %a = alloca i32, align 4
+ %x = bitcast i32* %a to i8*
+ call void @llvm.memset.p0i8.i32(i8* %x, i8 1, i32 5, i1 false)
+ call void @llvm.memset.p0i8.i32(i8* %x, i8 1, i32 4, i1 false)
+ ret void
+}
+
+define void @MixedAccesses2() {
+; CHECK-LABEL: @MixedAccesses2
+; CHECK-NEXT: args uses:
+; CHECK-NEXT: allocas uses:
+; CHECK: a[4]: [0,8){{$}}
+; GLOBAL-NEXT: safe accesses:
+; GLOBAL-NEXT: load i32, i32* %a, align 4
+; CHECK-EMPTY:
+entry:
+ %a = alloca i32, align 4
+ %a1 = bitcast i32* %a to i64*
+ %n1 = load i64, i64* %a1, align 4
+ %n2 = load i32, i32* %a, align 4
+ ret void
+}
+
+define void @MixedAccesses3(void (i8*)* %func) {
+; CHECK-LABEL: @MixedAccesses3
+; CHECK-NEXT: args uses:
+; CHECK-NEXT: func[]: full-set
+; CHECK-NEXT: allocas uses:
+; CHECK: a[4]: full-set{{$}}
+; GLOBAL-NEXT: safe accesses:
+; GLOBAL-NEXT: load i32, i32* %a, align 4
+; CHECK-EMPTY:
+entry:
+ %a = alloca i32, align 4
+ %x = bitcast i32* %a to i8*
+ %n2 = load i32, i32* %a, align 4
+ call void %func(i8* %x)
+ ret void
+}
+
+define void @MixedAccesses4() {
+; CHECK-LABEL: @MixedAccesses4
+; CHECK-NEXT: args uses:
+; CHECK-NEXT: allocas uses:
+; CHECK: a[4]: full-set{{$}}
+; CHECK: a1[8]: [0,8){{$}}
+; GLOBAL-NEXT: safe accesses:
+; GLOBAL-NEXT: load i32, i32* %a, align 4
+; CHECK-EMPTY:
+entry:
+ %a = alloca i32, align 4
+ %a1 = alloca i32*, align 4
+ %n2 = load i32, i32* %a, align 4
+ store i32* %a, i32** %a1
+ ret void
+}
+
+define i32* @MixedAccesses5(i1 %x, i32* %y) {
+; CHECK-LABEL: @MixedAccesses5
+; CHECK-NEXT: args uses:
+; CHECK: y[]: full-set
+; CHECK-NEXT: allocas uses:
+; CHECK: a[4]: full-set{{$}}
+; GLOBAL-NEXT: safe accesses:
+; GLOBAL-NEXT: load i32, i32* %a, align 4
+; CHECK-EMPTY:
+entry:
+ %a = alloca i32, align 4
+ br i1 %x, label %tlabel, label %flabel
+flabel:
+ %n = load i32, i32* %a, align 4
+ ret i32* %y
+tlabel:
+ ret i32* %a
+}
+
+define void @DoubleLifetime() {
+; CHECK-LABEL: @DoubleLifetime
+; CHECK-NEXT: args uses:
+; CHECK-NEXT: allocas uses:
+; CHECK: a[4]: full-set{{$}}
+; GLOBAL-NEXT: safe accesses:
+; GLOBAL-NEXT: call void @llvm.memset.p0i8.i32(i8* %x, i8 1, i32 4, i1 false)
+; CHECK-EMPTY:
+entry:
+ %a = alloca i32, align 4
+ %x = bitcast i32* %a to i8*
+ call void @llvm.lifetime.start.p0i8(i64 4, i8* %x)
+ call void @llvm.lifetime.end.p0i8(i64 4, i8* %x)
+ call void @llvm.memset.p0i8.i32(i8* %x, i8 1, i32 4, i1 true)
+
+ call void @llvm.lifetime.start.p0i8(i64 4, i8* %x)
+ call void @llvm.memset.p0i8.i32(i8* %x, i8 1, i32 4, i1 false)
+ call void @llvm.lifetime.end.p0i8(i64 4, i8* %x)
+ ret void
+}
+
+define void @DoubleLifetime2() {
+; CHECK-LABEL: @DoubleLifetime2
+; CHECK-NEXT: args uses:
+; CHECK-NEXT: allocas uses:
+; CHECK: a[4]: full-set{{$}}
+; GLOBAL-NEXT: safe accesses:
+; GLOBAL-NEXT: call void @llvm.memset.p0i8.i32(i8* %x, i8 1, i32 4, i1 false)
+; CHECK-EMPTY:
+entry:
+ %a = alloca i32, align 4
+ %x = bitcast i32* %a to i8*
+ call void @llvm.lifetime.start.p0i8(i64 4, i8* %x)
+ call void @llvm.lifetime.end.p0i8(i64 4, i8* %x)
+ %n = load i32, i32* %a
+
+ call void @llvm.lifetime.start.p0i8(i64 4, i8* %x)
+ call void @llvm.memset.p0i8.i32(i8* %x, i8 1, i32 4, i1 false)
+ call void @llvm.lifetime.end.p0i8(i64 4, i8* %x)
+ ret void
+}
+
+define void @DoubleLifetime3() {
+; CHECK-LABEL: @DoubleLifetime3
+; CHECK-NEXT: args uses:
+; CHECK-NEXT: allocas uses:
+; CHECK: a[4]: full-set{{$}}
+; GLOBAL-NEXT: safe accesses:
+; GLOBAL-NEXT: call void @llvm.memset.p0i8.i32(i8* %x, i8 1, i32 4, i1 false)
+; CHECK-EMPTY:
+entry:
+ %a = alloca i32, align 4
+ %x = bitcast i32* %a to i8*
+ call void @llvm.lifetime.start.p0i8(i64 4, i8* %x)
+ call void @llvm.lifetime.end.p0i8(i64 4, i8* %x)
+ store i32 5, i32* %a
+
+ call void @llvm.lifetime.start.p0i8(i64 4, i8* %x)
+ call void @llvm.memset.p0i8.i32(i8* %x, i8 1, i32 4, i1 false)
+ call void @llvm.lifetime.end.p0i8(i64 4, i8* %x)
+ ret void
+}
+
+define void @DoubleLifetime4() {
+; CHECK-LABEL: @DoubleLifetime4
+; CHECK-NEXT: args uses:
+; CHECK-NEXT: allocas uses:
+; CHECK: a[4]: full-set{{$}}
+; GLOBAL-NEXT: safe accesses:
+; GLOBAL-NEXT: call void @llvm.memset.p0i8.i32(i8* %x, i8 1, i32 4, i1 false)
+; CHECK-EMPTY:
+entry:
+ %a = alloca i32, align 4
+ %x = bitcast i32* %a to i8*
+ call void @llvm.lifetime.start.p0i8(i64 4, i8* %x)
+ call void @llvm.memset.p0i8.i32(i8* %x, i8 1, i32 4, i1 false)
+ call void @llvm.lifetime.end.p0i8(i64 4, i8* %x)
+ call void @unknown_call(i8* %x)
+ ret void
+}
+
declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture)
declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture)
diff --git a/llvm/test/Analysis/StackSafetyAnalysis/memintrin.ll b/llvm/test/Analysis/StackSafetyAnalysis/memintrin.ll
index 3d458cbfeff8c..a19e3ed46efb0 100644
--- a/llvm/test/Analysis/StackSafetyAnalysis/memintrin.ll
+++ b/llvm/test/Analysis/StackSafetyAnalysis/memintrin.ll
@@ -1,5 +1,5 @@
; RUN: opt -S -passes="print<stack-safety-local>" -disable-output < %s 2>&1 | FileCheck %s
-; RUN: opt -S -passes="print-stack-safety" -disable-output < %s 2>&1 | FileCheck %s
+; RUN: opt -S -passes="print-stack-safety" -disable-output < %s 2>&1 | FileCheck %s --check-prefixes=CHECK,GLOBAL
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"
@@ -14,6 +14,8 @@ define void @MemsetInBounds() {
; CHECK-NEXT: args uses:
; CHECK-NEXT: allocas uses:
; CHECK-NEXT: x[4]: [0,4){{$}}
+; GLOBAL-NEXT: safe accesses:
+; GLOBAL-NEXT: call void @llvm.memset.p0i8.i32(i8* %x1, i8 42, i32 4, i1 false)
; CHECK-EMPTY:
entry:
%x = alloca i32, align 4
@@ -28,6 +30,8 @@ define void @VolatileMemsetInBounds() {
; CHECK-NEXT: args uses:
; CHECK-NEXT: allocas uses:
; CHECK-NEXT: x[4]: [0,4){{$}}
+; GLOBAL-NEXT: safe accesses:
+; GLOBAL-NEXT: call void @llvm.memset.p0i8.i32(i8* %x1, i8 42, i32 4, i1 true)
; CHECK-EMPTY:
entry:
%x = alloca i32, align 4
@@ -41,6 +45,7 @@ define void @MemsetOutOfBounds() {
; CHECK-NEXT: args uses:
; CHECK-NEXT: allocas uses:
; CHECK-NEXT: x[4]: [0,5){{$}}
+; GLOBAL-NEXT: safe accesses:
; CHECK-EMPTY:
entry:
%x = alloca i32, align 4
@@ -54,6 +59,7 @@ define void @MemsetNonConst(i32 %size) {
; CHECK-NEXT: args uses:
; CHECK-NEXT: allocas uses:
; CHECK-NEXT: x[4]: [0,4294967295){{$}}
+; GLOBAL-NEXT: safe accesses:
; CHECK-EMPTY:
entry:
%x = alloca i32, align 4
@@ -69,6 +75,7 @@ define void @MemsetNonConstInBounds(i1 zeroext %z) {
; CHECK-NEXT: args uses:
; CHECK-NEXT: allocas uses:
; CHECK-NEXT: x[4]: [0,7){{$}}
+; GLOBAL-NEXT: safe accesses:
; CHECK-EMPTY:
entry:
%x = alloca i32, align 4
@@ -84,6 +91,7 @@ define void @MemsetNonConstSize() {
; CHECK-NEXT: allocas uses:
; CHECK-NEXT: x[4]: [0,4294967295){{$}}
; CHECK-NEXT: y[4]: empty-set{{$}}
+; GLOBAL-NEXT: safe accesses:
; CHECK-EMPTY:
entry:
%x = alloca i32, align 4
@@ -102,6 +110,8 @@ define void @MemcpyInBounds() {
; CHECK-NEXT: allocas uses:
; CHECK-NEXT: x[4]: [0,4){{$}}
; CHECK-NEXT: y[4]: [0,4){{$}}
+; GLOBAL-NEXT: safe accesses:
+; GLOBAL-NEXT: call void @llvm.memcpy.p0i8.p0i8.i32(i8* %x1, i8* %y1, i32 4, i1 false)
; CHECK-EMPTY:
entry:
%x = alloca i32, align 4
@@ -118,6 +128,7 @@ define void @MemcpySrcOutOfBounds() {
; CHECK-NEXT: allocas uses:
; CHECK-NEXT: x[8]: [0,5){{$}}
; CHECK-NEXT: y[4]: [0,5){{$}}
+; GLOBAL-NEXT: safe accesses
; CHECK-EMPTY:
entry:
%x = alloca i64, align 4
@@ -134,6 +145,7 @@ define void @MemcpyDstOutOfBounds() {
; CHECK-NEXT: allocas uses:
; CHECK-NEXT: x[4]: [0,5){{$}}
; CHECK-NEXT: y[8]: [0,5){{$}}
+; GLOBAL-NEXT: safe accesses
; CHECK-EMPTY:
entry:
%x = alloca i32, align 4
@@ -150,6 +162,7 @@ define void @MemcpyBothOutOfBounds() {
; CHECK-NEXT: allocas uses:
; CHECK-NEXT: x[4]: [0,9){{$}}
; CHECK-NEXT: y[8]: [0,9){{$}}
+; GLOBAL-NEXT: safe accesses
; CHECK-EMPTY:
entry:
%x = alloca i32, align 4
@@ -165,6 +178,8 @@ define void @MemcpySelfInBounds() {
; CHECK-NEXT: args uses:
; CHECK-NEXT: allocas uses:
; CHECK-NEXT: x[8]: [0,8){{$}}
+; GLOBAL-NEXT: safe accesses
+; GLOBAL-NEXT: call void @llvm.memcpy.p0i8.p0i8.i32(i8* %x1, i8* %x2, i32 3, i1 false)
; CHECK-EMPTY:
entry:
%x = alloca i64, align 4
@@ -179,6 +194,7 @@ define void @MemcpySelfSrcOutOfBounds() {
; CHECK-NEXT: args uses:
; CHECK-NEXT: allocas uses:
; CHECK-NEXT: x[8]: [0,9){{$}}
+; GLOBAL-NEXT: safe accesses:
; CHECK-EMPTY:
entry:
%x = alloca i64, align 4
@@ -193,6 +209,7 @@ define void @MemcpySelfDstOutOfBounds() {
; CHECK-NEXT: args uses:
; CHECK-NEXT: allocas uses:
; CHECK-NEXT: x[8]: [0,9){{$}}
+; GLOBAL-NEXT: safe accesses:
; CHECK-EMPTY:
entry:
%x = alloca i64, align 4
@@ -207,6 +224,7 @@ define void @MemmoveSelfBothOutOfBounds() {
; CHECK-NEXT: args uses:
; CHECK-NEXT: allocas uses:
; CHECK-NEXT: x[8]: [0,14){{$}}
+; GLOBAL-NEXT: safe accesses:
; CHECK-EMPTY:
entry:
%x = alloca i64, align 4
More information about the llvm-commits
mailing list