mirror of
https://github.com/RPCS3/llvm.git
synced 2025-02-03 09:14:30 +00:00
GlobalsAA: Take advantage of ArgMemOnly, InaccessibleMemOnly and InaccessibleMemOrArgMemOnly attributes
Summary: 1. Modify AnalyzeCallGraph() to retain function info for external functions if the function has [InaccessibleMemOr]ArgMemOnly flags. 2. When analyzing the use of a global is function parameter at a call site, mark the callee also as modifying the global appropriately. 3. Add additional test cases. Depends on D15499 Reviewers: hfinkel, jmolloy Subscribers: llvm-commits Differential Revision: http://reviews.llvm.org/D15605 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@255994 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
35e39f0c8a
commit
5a9e526f29
@ -376,6 +376,15 @@ bool GlobalsAAResult::AnalyzeUsesOfPointer(Value *V,
|
||||
} else {
|
||||
return true; // Argument of an unknown call.
|
||||
}
|
||||
// If the Callee is not ReadNone, it may read the global,
|
||||
// and if it is not ReadOnly, it may also write to it.
|
||||
Function *CalleeF = CS.getCalledFunction();
|
||||
if (!CalleeF->doesNotAccessMemory()) {
|
||||
if (Readers)
|
||||
Readers->insert(CalleeF);
|
||||
if (Writers && !CalleeF->onlyReadsMemory())
|
||||
Writers->insert(CalleeF);
|
||||
}
|
||||
}
|
||||
} else if (ICmpInst *ICI = dyn_cast<ICmpInst>(I)) {
|
||||
if (!isa<ConstantPointerNull>(ICI->getOperand(1)))
|
||||
@ -507,7 +516,7 @@ void GlobalsAAResult::AnalyzeCallGraph(CallGraph &CG, Module &M) {
|
||||
|
||||
if (F->isDeclaration()) {
|
||||
// Try to get mod/ref behaviour from function attributes.
|
||||
if (F->doesNotAccessMemory()) {
|
||||
if (F->doesNotAccessMemory() || F->onlyAccessesInaccessibleMemory()) {
|
||||
// Can't do better than that!
|
||||
} else if (F->onlyReadsMemory()) {
|
||||
FI.addModRefInfo(MRI_Ref);
|
||||
@ -515,6 +524,12 @@ void GlobalsAAResult::AnalyzeCallGraph(CallGraph &CG, Module &M) {
|
||||
// This function might call back into the module and read a global -
|
||||
// consider every global as possibly being read by this function.
|
||||
FI.setMayReadAnyGlobal();
|
||||
} else if (F->onlyAccessesArgMemory() ||
|
||||
F->onlyAccessesInaccessibleMemOrArgMem()) {
|
||||
// This function may only access (read/write) memory pointed to by its
|
||||
// arguments. If this pointer is to a global, this escaping use of the
|
||||
// pointer is captured in AnalyzeUsesOfPointer().
|
||||
FI.addModRefInfo(MRI_ModRef);
|
||||
} else {
|
||||
FI.addModRefInfo(MRI_ModRef);
|
||||
// Can't say anything useful unless it's an intrinsic - they don't
|
||||
|
47
test/Analysis/GlobalsModRef/argmemonly-escape.ll
Normal file
47
test/Analysis/GlobalsModRef/argmemonly-escape.ll
Normal file
@ -0,0 +1,47 @@
|
||||
; 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
|
||||
|
||||
; The important thing we're checking for here is the reload of (some element of)
|
||||
; @a after the memset.
|
||||
|
||||
; CHECK-LABEL: @main
|
||||
; CHECK: load i32, i32* getelementptr {{.*}} @a
|
||||
; CHECK-NEXT: call void @memsetp0i8i64{{.*}} @a
|
||||
; CHECK-NEXT: load i32, i32* getelementptr {{.*}} @a
|
||||
; CHECK-NEXT: call void @memsetp0i8i64A{{.*}} @a
|
||||
; CHECK-NEXT: load i32, i32* getelementptr {{.*}} @a
|
||||
; CHECK: icmp eq
|
||||
; CHECK: br i1
|
||||
|
||||
define i32 @main() {
|
||||
entry:
|
||||
%0 = bitcast [3 x i32]* @a to i8*
|
||||
%1 = load i32, i32* getelementptr inbounds ([3 x i32], [3 x i32]* @a, i64 0, i64 2), align 4
|
||||
call void @memsetp0i8i64(i8* %0, i8 0, i64 4, i32 4, i1 false)
|
||||
%2 = load i32, i32* getelementptr inbounds ([3 x i32], [3 x i32]* @a, i64 0, i64 2), align 4
|
||||
call void @memsetp0i8i64A(i8* %0, i8 0, i64 4, i32 4, i1 false)
|
||||
%3 = load i32, i32* getelementptr inbounds ([3 x i32], [3 x i32]* @a, i64 0, i64 2), align 4
|
||||
%4 = add i32 %2, %3
|
||||
%cmp1 = icmp eq i32 %1, %4
|
||||
br i1 %cmp1, label %if.then, label %if.end
|
||||
|
||||
if.then: ; preds = %entr
|
||||
call void @abort() #3
|
||||
unreachable
|
||||
|
||||
if.end: ; preds = %entry
|
||||
ret i32 0
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind argmemonly
|
||||
declare void @memsetp0i8i64(i8* nocapture, i8, i64, i32, i1) nounwind argmemonly
|
||||
|
||||
; Function Attrs: nounwind inaccessiblemem_or_argmemonly
|
||||
declare void @memsetp0i8i64A(i8* nocapture, i8, i64, i32, i1) nounwind inaccessiblemem_or_argmemonly
|
||||
|
||||
; Function Attrs: noreturn nounwind
|
||||
declare void @abort() noreturn nounwind
|
@ -16,3 +16,23 @@ define i32 @test(i32* %P) {
|
||||
define void @doesnotmodX() {
|
||||
ret void
|
||||
}
|
||||
|
||||
declare void @InaccessibleMemOnlyFunc( ) #0
|
||||
declare void @InaccessibleMemOrArgMemOnlyFunc( ) #1
|
||||
|
||||
define i32 @test2(i32* %P) {
|
||||
; CHECK: @test2
|
||||
; CHECK-NEXT: store i32 12, i32* @X
|
||||
; CHECK-NEXT: call void @InaccessibleMemOnlyFunc()
|
||||
; CHECK-NEXT: call void @InaccessibleMemOrArgMemOnlyFunc()
|
||||
; CHECK-NOT: load i32
|
||||
; CHECK-NEXT: ret i32 12
|
||||
store i32 12, i32* @X
|
||||
call void @InaccessibleMemOnlyFunc( )
|
||||
call void @InaccessibleMemOrArgMemOnlyFunc( )
|
||||
%V = load i32, i32* @X ; <i32> [#uses=1]
|
||||
ret i32 %V
|
||||
}
|
||||
|
||||
attributes #0 = { inaccessiblememonly }
|
||||
attributes #1 = { inaccessiblemem_or_argmemonly }
|
||||
|
Loading…
x
Reference in New Issue
Block a user