diff --git a/llvm/include/llvm/Analysis/GlobalsModRef.h b/llvm/include/llvm/Analysis/GlobalsModRef.h --- a/llvm/include/llvm/Analysis/GlobalsModRef.h +++ b/llvm/include/llvm/Analysis/GlobalsModRef.h @@ -39,6 +39,9 @@ /// The globals that do not have their addresses taken. SmallPtrSet NonAddressTakenGlobals; + /// Are there functions with local linkage that may modify globals. + bool UnknownFunctionsWithLocalLinkage = false; + /// IndirectGlobals - The memory pointed to by this global is known to be /// 'owned' by the global. SmallPtrSet IndirectGlobals; diff --git a/llvm/lib/Analysis/GlobalsModRef.cpp b/llvm/lib/Analysis/GlobalsModRef.cpp --- a/llvm/lib/Analysis/GlobalsModRef.cpp +++ b/llvm/lib/Analysis/GlobalsModRef.cpp @@ -286,7 +286,7 @@ void GlobalsAAResult::AnalyzeGlobals(Module &M) { SmallPtrSet TrackedFunctions; for (Function &F : M) - if (F.hasLocalLinkage()) + if (F.hasLocalLinkage()) { if (!AnalyzeUsesOfPointer(&F)) { // Remember that we are tracking this global. NonAddressTakenGlobals.insert(&F); @@ -294,7 +294,9 @@ Handles.emplace_front(*this, &F); Handles.front().I = Handles.begin(); ++NumNonAddrTakenFunctions; - } + } else + UnknownFunctionsWithLocalLinkage = true; + } SmallPtrSet Readers, Writers; for (GlobalVariable &GV : M.globals()) @@ -526,9 +528,12 @@ FI.setMayReadAnyGlobal(); } else { FI.addModRefInfo(ModRefInfo::ModRef); - // Can't say anything useful unless it's an intrinsic - they don't - // read or write global variables of the kind considered here. - KnowNothing = !F->isIntrinsic(); + if (!F->onlyAccessesArgMemory()) + FI.setMayReadAnyGlobal(); + if (!F->isIntrinsic()) { + KnowNothing = true; + break; + } } continue; } @@ -927,7 +932,9 @@ // global we are tracking, return information if we have it. if (const GlobalValue *GV = dyn_cast(GetUnderlyingObject(Loc.Ptr, DL))) - if (GV->hasLocalLinkage()) + // If GV is internal to this IR and there is no function with local linkage + // that has had their address taken, keep looking for a tighter ModRefInfo. + if (GV->hasLocalLinkage() && !UnknownFunctionsWithLocalLinkage) if (const Function *F = Call->getCalledFunction()) if (NonAddressTakenGlobals.count(GV)) if (const FunctionInfo *FI = getFunctionInfo(F)) diff --git a/llvm/test/Analysis/GlobalsModRef/intrinsic_addressnottaken1.ll b/llvm/test/Analysis/GlobalsModRef/intrinsic_addressnottaken1.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Analysis/GlobalsModRef/intrinsic_addressnottaken1.ll @@ -0,0 +1,44 @@ +; RUN: opt -globals-aa -gvn -S < %s | FileCheck %s + +target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +@deallocCalled = internal global i8 0, align 1 + +; CHECK-LABEL: @main() +define dso_local i32 @main() { +entry: + %tmp0 = call i8* @llvm.objc.autoreleasePoolPush() #1 + %tmp6 = load i8, i8* @deallocCalled, align 1 + %tobool = icmp ne i8 %tmp6, 0 + br i1 %tobool, label %if.else, label %if.end + +if.else: ; preds = %entry + call void @__assert_fail() #0 + unreachable + +; CHECK-LABEL: if.end: +; CHECK-NEXT: call void @llvm.objc.autoreleasePoolPop +; CHECK-NOT: load i8, i8* @deallocCalled +if.end: ; preds = %entry + call void @llvm.objc.autoreleasePoolPop(i8* %tmp0) + %tmp7 = load i8, i8* @deallocCalled, align 1 + %tobool3 = icmp ne i8 %tmp7, 0 + br i1 %tobool3, label %if.end6, label %if.else5 + +if.else5: ; preds = %if.end + call void @__assert_fail() #0 + unreachable + +if.end6: ; preds = %if.end + store i8 0, i8* @deallocCalled, align 1 + ret i32 0 +} + +declare i8* @llvm.objc.autoreleasePoolPush() #1 +declare void @llvm.objc.autoreleasePoolPop(i8*) #1 +declare dso_local void @__assert_fail() #0 + +attributes #0 = { noreturn nounwind } +attributes #1 = { nounwind } + diff --git a/llvm/test/Analysis/GlobalsModRef/intrinsic_addressnottaken2.ll b/llvm/test/Analysis/GlobalsModRef/intrinsic_addressnottaken2.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Analysis/GlobalsModRef/intrinsic_addressnottaken2.ll @@ -0,0 +1,50 @@ +; RUN: opt -globals-aa -gvn -S < %s | FileCheck %s + +target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +@deallocCalled = internal global i8 0, align 1 + +define internal i8* @_i_Associated__dealloc() { +entry: + store i8 1, i8* @deallocCalled, align 1 + ret i8* null +} + +; CHECK-LABEL: @main() +define dso_local i32 @main() { +entry: + %tmp0 = call i8* @llvm.objc.autoreleasePoolPush() #1 + %tmp6 = load i8, i8* @deallocCalled, align 1 + %tobool = icmp ne i8 %tmp6, 0 + br i1 %tobool, label %if.else, label %if.end + +if.else: ; preds = %entry + call void @__assert_fail() #0 + unreachable + +; CHECK-LABEL: if.end: +; CHECK-NEXT: call void @llvm.objc.autoreleasePoolPop +; CHECK-NOT: load i8, i8* @deallocCalled +if.end: ; preds = %entry + call void @llvm.objc.autoreleasePoolPop(i8* %tmp0) + %tmp7 = load i8, i8* @deallocCalled, align 1 + %tobool3 = icmp ne i8 %tmp7, 0 + br i1 %tobool3, label %if.end6, label %if.else5 + +if.else5: ; preds = %if.end + call void @__assert_fail() #0 + unreachable + +if.end6: ; preds = %if.end + store i8 0, i8* @deallocCalled, align 1 + ret i32 0 +} + +declare i8* @llvm.objc.autoreleasePoolPush() #1 +declare void @llvm.objc.autoreleasePoolPop(i8*) #1 +declare dso_local void @__assert_fail() #0 + +attributes #0 = { noreturn nounwind } +attributes #1 = { nounwind } + diff --git a/llvm/test/Analysis/GlobalsModRef/intrinsic_addresstaken.ll b/llvm/test/Analysis/GlobalsModRef/intrinsic_addresstaken.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Analysis/GlobalsModRef/intrinsic_addresstaken.ll @@ -0,0 +1,53 @@ +; RUN: opt -globals-aa -gvn -S < %s | FileCheck %s + +target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +@deallocCalled = internal global i8 0, align 1 +@.objc_method_list = internal global { i8* ()* } { i8* ()* @_i_Associated__dealloc }, align 8 +@._OBJC_CLASS_Associated = global { i8* } { i8* bitcast ({ i8* ()* }* @.objc_method_list to i8*) }, align 8 +@._OBJC_INIT_CLASS_Associated = global { i8* }* @._OBJC_CLASS_Associated +@llvm.used = appending global [1 x i8*] [i8* bitcast ({ i8* }** @._OBJC_INIT_CLASS_Associated to i8*)] + +define internal i8* @_i_Associated__dealloc() { +entry: + store i8 1, i8* @deallocCalled, align 1 + ret i8* null +} + +; CHECK-LABEL: @main() +define dso_local i32 @main() { +entry: + %tmp0 = call i8* @llvm.objc.autoreleasePoolPush() #1 + %tmp6 = load i8, i8* @deallocCalled, align 1 + %tobool = icmp ne i8 %tmp6, 0 + br i1 %tobool, label %if.else, label %if.end + +if.else: ; preds = %entry + call void @__assert_fail() #0 + unreachable + +; CHECK-LABEL: if.end: +; CHECK-NEXT: call void @llvm.objc.autoreleasePoolPop +; CHECK-NEXT: load i8, i8* @deallocCalled +if.end: ; preds = %entry + call void @llvm.objc.autoreleasePoolPop(i8* %tmp0) + %tmp7 = load i8, i8* @deallocCalled, align 1 + %tobool3 = icmp ne i8 %tmp7, 0 + br i1 %tobool3, label %if.end6, label %if.else5 + +if.else5: ; preds = %if.end + call void @__assert_fail() #0 + unreachable + +if.end6: ; preds = %if.end + store i8 0, i8* @deallocCalled, align 1 + ret i32 0 +} + +declare i8* @llvm.objc.autoreleasePoolPush() #1 +declare void @llvm.objc.autoreleasePoolPop(i8*) #1 +declare dso_local void @__assert_fail() #0 + +attributes #0 = { noreturn nounwind } +attributes #1 = { nounwind }