Index: include/llvm/Analysis/GlobalsModRef.h =================================================================== --- include/llvm/Analysis/GlobalsModRef.h +++ include/llvm/Analysis/GlobalsModRef.h @@ -105,6 +105,8 @@ bool AnalyzeIndirectGlobalMemory(GlobalValue *GV); bool isNonEscapingGlobalNoAlias(const GlobalValue *GV, const Value *V); + ModRefInfo getModRefInfoForIntrinsic(ImmutableCallSite CS, + const GlobalValue *GV); }; /// Analysis pass providing a never-invalidated alias analysis result. Index: lib/Analysis/GlobalsModRef.cpp =================================================================== --- lib/Analysis/GlobalsModRef.cpp +++ lib/Analysis/GlobalsModRef.cpp @@ -765,6 +765,32 @@ return AAResultBase::alias(LocA, LocB); } +ModRefInfo GlobalsAAResult::getModRefInfoForIntrinsic(ImmutableCallSite CS, + const GlobalValue *GV) { + auto IsGV = [&](unsigned OpIdx) { + return GetUnderlyingObject(CS.getArgument(OpIdx), DL) == GV; + }; + + switch (CS.getCalledFunction()->getIntrinsicID()) { + default: + // We don't know the intrinsic, but if it's readnone, it doesn't modify + // or reference anything... + if (CS.doesNotAccessMemory()) + return MRI_NoModRef; + // ... and if it's readonly it only references. + if (CS.onlyReadsMemory()) + return MRI_Ref; + // Fallback - we don't know anything about this intrinsic. + return MRI_ModRef; + case Intrinsic::memset: + return (IsGV(0) ? MRI_Mod : MRI_NoModRef); + case Intrinsic::memcpy: + case Intrinsic::memmove: + return static_cast((IsGV(0) ? MRI_Mod : MRI_NoModRef) | + (IsGV(1) ? MRI_Ref : MRI_NoModRef)); + } +} + ModRefInfo GlobalsAAResult::getModRefInfo(ImmutableCallSite CS, const MemoryLocation &Loc) { unsigned Known = MRI_ModRef; @@ -777,7 +803,8 @@ if (const Function *F = CS.getCalledFunction()) if (NonAddressTakenGlobals.count(GV)) if (const FunctionInfo *FI = getFunctionInfo(F)) - Known = FI->getModRefInfoForGlobal(*GV); + Known = FI->getModRefInfoForGlobal(*GV) | + getModRefInfoForIntrinsic(CS, GV); if (Known == MRI_NoModRef) return MRI_NoModRef; // No need to query other mod/ref analyses Index: lib/Analysis/ScalarEvolution.cpp =================================================================== --- lib/Analysis/ScalarEvolution.cpp +++ lib/Analysis/ScalarEvolution.cpp @@ -8474,7 +8474,7 @@ F.printAsOperand(OS, /*PrintType=*/false); OS << "\n"; for (inst_iterator I = inst_begin(F), E = inst_end(F); I != E; ++I) - if (isSCEVable(I->getType()) && !isa(*I)) { + if (isSCEVable(I->getType()) /*&& !isa(*I)*/) { OS << *I << '\n'; OS << " --> "; const SCEV *SV = SE.getSCEV(&*I); Index: test/Analysis/GlobalsModRef/memset-escape.ll =================================================================== --- /dev/null +++ test/Analysis/GlobalsModRef/memset-escape.ll @@ -0,0 +1,65 @@ +; RUN: opt < %s -O1 -S -enable-non-lto-gmr=true | FileCheck %s + +target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-apple-macosx10.10.0" + +@a = internal global [3 x i32] zeroinitializer, align 4 +@b = common global i32 0, align 4 + +; The important thing we're checking for here is the reload of (some element of) +; @a after the memset. + +; CHECK-LABEL: @main +; CHECK: call void @llvm.memset.p0i8.i64{{.*}} @a +; CHECK: store i32 3 +; CHECK: load i32, i32* getelementptr {{.*}} @a +; CHECK: icmp eq i32 +; CHECK: br i1 + +define i32 @main() { +entry: + %retval = alloca i32, align 4 + %c = alloca [1 x i32], align 4 + store i32 0, i32* %retval, align 4 + %0 = bitcast [1 x i32]* %c to i8* + call void @llvm.memset.p0i8.i64(i8* %0, i8 0, i64 4, i32 4, i1 false) + store i32 1, i32* getelementptr inbounds ([3 x i32], [3 x i32]* @a, i64 0, i64 2), align 4 + store i32 0, i32* @b, align 4 + br label %for.cond + +for.cond: ; preds = %for.inc, %entry + %1 = load i32, i32* @b, align 4 + %cmp = icmp slt i32 %1, 3 + br i1 %cmp, label %for.body, label %for.end + +for.body: ; preds = %for.cond + %2 = load i32, i32* @b, align 4 + %idxprom = sext i32 %2 to i64 + %arrayidx = getelementptr inbounds [3 x i32], [3 x i32]* @a, i64 0, i64 %idxprom + store i32 0, i32* %arrayidx, align 4 + br label %for.inc + +for.inc: ; preds = %for.body + %3 = load i32, i32* @b, align 4 + %inc = add nsw i32 %3, 1 + store i32 %inc, i32* @b, align 4 + br label %for.cond + +for.end: ; preds = %for.cond + %4 = load i32, i32* getelementptr inbounds ([3 x i32], [3 x i32]* @a, i64 0, i64 2), align 4 + %cmp1 = icmp ne i32 %4, 0 + br i1 %cmp1, label %if.then, label %if.end + +if.then: ; preds = %for.end + call void @abort() #3 + unreachable + +if.end: ; preds = %for.end + ret i32 0 +} + +; Function Attrs: nounwind argmemonly +declare void @llvm.memset.p0i8.i64(i8* nocapture, i8, i64, i32, i1) nounwind argmemonly + +; Function Attrs: noreturn nounwind +declare void @abort() noreturn nounwind