diff --git a/llvm/include/llvm/Analysis/StackSafetyAnalysis.h b/llvm/include/llvm/Analysis/StackSafetyAnalysis.h --- a/llvm/include/llvm/Analysis/StackSafetyAnalysis.h +++ b/llvm/include/llvm/Analysis/StackSafetyAnalysis.h @@ -75,7 +75,12 @@ 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 --- a/llvm/lib/Analysis/StackSafetyAnalysis.cpp +++ b/llvm/lib/Analysis/StackSafetyAnalysis.cpp @@ -30,6 +30,7 @@ #include "llvm/Support/raw_ostream.h" #include #include +#include using namespace llvm; @@ -116,6 +117,7 @@ // 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 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 @@ 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 StackSafetyGlobalInfo::InfoTy { GVToSSI Info; SmallPtrSet SafeAllocas; + SmallPtrSet SafeAccesses; }; namespace { @@ -352,7 +358,7 @@ 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()))); @@ -366,11 +372,11 @@ 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( @@ -383,7 +389,7 @@ // 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: { @@ -392,7 +398,7 @@ if (AI && !SL.isAliveAfter(AI, I)) { US.addRange(I, UnknownRange); - return; + break; } if (const MemIntrinsic *MI = dyn_cast(I)) { @@ -403,7 +409,7 @@ const auto &CB = cast(*I); if (!CB.isArgOperand(&UI)) { US.addRange(I, UnknownRange); - return; + break; } unsigned ArgNo = CB.getArgOperandNo(&UI); @@ -421,7 +427,7 @@ dyn_cast(CB.getCalledOperand()->stripPointerCasts()); if (!Callee) { US.addRange(I, UnknownRange); - return; + break; } assert(isa(Callee) || isa(Callee)); @@ -809,17 +815,27 @@ } } Info.reset(new InfoTy{ - createGlobalStackSafetyInfo(std::move(Functions), Index), {}}); + createGlobalStackSafetyInfo(std::move(Functions), Index), {}, {}}); + + std::map Accesses; 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) + Accesses[A.first] |= !AIRange.contains(A.second); } } + + for (const auto &KV : Accesses) + if (!KV.second) + Info->SafeAccesses.insert(KV.first); + if (StackSafetyPrint) print(errs()); } @@ -889,6 +905,11 @@ 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()) @@ -897,7 +918,13 @@ 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 --- a/llvm/test/Analysis/StackSafetyAnalysis/ipa-alias.ll +++ b/llvm/test/Analysis/StackSafetyAnalysis/ipa-alias.ll @@ -66,6 +66,7 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 --- a/llvm/test/Analysis/StackSafetyAnalysis/ipa.ll +++ b/llvm/test/Analysis/StackSafetyAnalysis/ipa.ll @@ -126,6 +126,7 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 --- a/llvm/test/Analysis/StackSafetyAnalysis/local.ll +++ b/llvm/test/Analysis/StackSafetyAnalysis/local.ll @@ -11,12 +11,17 @@ 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) +declare i1 @unknown_cond() +declare i32* @unknown_ptr() + ; 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 +35,8 @@ ; 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 +50,8 @@ ; 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 +64,8 @@ ; 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 +81,7 @@ ; 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 +97,7 @@ ; 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 +112,7 @@ ; 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 +126,7 @@ ; 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 +143,8 @@ ; 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 +158,7 @@ ; 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 +175,7 @@ ; 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 +192,7 @@ ; 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 +210,7 @@ ; 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 +225,8 @@ ; 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 +242,7 @@ ; 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 +256,7 @@ ; 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 +270,7 @@ ; 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 +286,8 @@ ; 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 +303,7 @@ ; 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 +319,7 @@ ; 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 +332,7 @@ ; 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 +347,7 @@ ; 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 +361,8 @@ ; 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 +389,7 @@ ; 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 +416,7 @@ ; 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 +441,7 @@ ; CHECK-NEXT: unused[]: empty-set ; CHECK-NEXT: allocas uses: ; CHECK-NEXT: x[0]: [0,1){{$}} +; GLOBAL-NEXT: safe accesses: ; CHECK-EMPTY: entry: %x = alloca , align 4 @@ -422,6 +459,8 @@ ; 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 +475,7 @@ ; 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 +487,7 @@ ; CHECK-LABEL: @ByVal dso_preemptable{{$}} ; CHECK-NEXT: args uses: ; CHECK-NEXT: allocas uses: + ; GLOBAL-NEXT: safe accesses: ; CHECK-EMPTY: entry: ret void @@ -458,6 +499,9 @@ ; 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 +521,7 @@ ; 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 +537,7 @@ ; 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 +550,7 @@ ; 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 +565,7 @@ ; 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 +587,7 @@ ; 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 +612,10 @@ ; 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 +640,7 @@ ; 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 +662,237 @@ 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() { +; CHECK-LABEL: @MixedAccesses5 +; CHECK-NEXT: args uses: +; 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 = call i1 @unknown_cond() + br i1 %x, label %tlabel, label %flabel +flabel: + %n = load i32, i32* %a, align 4 + %y = call i32* @unknown_ptr() + 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 --- a/llvm/test/Analysis/StackSafetyAnalysis/memintrin.ll +++ b/llvm/test/Analysis/StackSafetyAnalysis/memintrin.ll @@ -1,5 +1,5 @@ ; RUN: opt -S -passes="print" -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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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 @@ ; 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