llvm.org GIT mirror llvm / bbd902f
[BasicAA] Guard intrinsics don't write to memory Summary: The idea is very close to what we do for assume intrinsics: we mark the guard intrinsics as writing to arbitrary memory to maintain control dependence, but under the covers we teach AA that they do not mod any particular memory location. Reviewers: chandlerc, hfinkel, gbiv, reames Subscribers: george.burgess.iv, mcrosier, llvm-commits Differential Revision: http://reviews.llvm.org/D19575 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@269007 91177308-0d34-0410-b5e6-96231b3b80d8 Sanjoy Das 3 years ago
2 changed file(s) with 62 addition(s) and 4 deletion(s). Raw diff Collapse all Expand all
648648 return AAResultBase::getArgModRefInfo(CS, ArgIdx);
649649 }
650650
651 static bool isAssumeIntrinsic(ImmutableCallSite CS) {
651 static bool isIntrinsicCall(ImmutableCallSite CS, Intrinsic::ID IID) {
652652 const IntrinsicInst *II = dyn_cast(CS.getInstruction());
653 return II && II->getIntrinsicID() == Intrinsic::assume;
653 return II && II->getIntrinsicID() == IID;
654654 }
655655
656656 #ifndef NDEBUG
768768 // While the assume intrinsic is marked as arbitrarily writing so that
769769 // proper control dependencies will be maintained, it never aliases any
770770 // particular memory location.
771 if (isAssumeIntrinsic(CS))
771 if (isIntrinsicCall(CS, Intrinsic::assume))
772772 return MRI_NoModRef;
773
774 // Like assumes, guard intrinsics are also marked as arbitrarily writing so
775 // that proper control dependencies are maintained but they never mods any
776 // particular memory location.
777 //
778 // *Unlike* assumes, guard intrinsics are modeled as reading memory since the
779 // heap state at the point the guard is issued needs to be consistent in case
780 // the guard invokes the "deopt" continuation.
781 if (isIntrinsicCall(CS, Intrinsic::experimental_guard))
782 return MRI_Ref;
773783
774784 // The AAResultBase base class has some smarts, lets use them.
775785 return AAResultBase::getModRefInfo(CS, Loc);
780790 // While the assume intrinsic is marked as arbitrarily writing so that
781791 // proper control dependencies will be maintained, it never aliases any
782792 // particular memory location.
783 if (isAssumeIntrinsic(CS1) || isAssumeIntrinsic(CS2))
793 if (isIntrinsicCall(CS1, Intrinsic::assume) ||
794 isIntrinsicCall(CS2, Intrinsic::assume))
784795 return MRI_NoModRef;
796
797 // Like assumes, guard intrinsics are also marked as arbitrarily writing so
798 // that proper control dependencies are maintained but they never mod any
799 // particular memory location.
800 //
801 // *Unlike* assumes, guard intrinsics are modeled as reading memory since the
802 // heap state at the point the guard is issued needs to be consistent in case
803 // the guard invokes the "deopt" continuation.
804
805 // NB! This function is *not* commutative, so we specical case two
806 // possibilities for guard intrinsics.
807
808 if (isIntrinsicCall(CS1, Intrinsic::experimental_guard))
809 return getModRefBehavior(CS2) & MRI_Mod ? MRI_Ref : MRI_NoModRef;
810
811 if (isIntrinsicCall(CS2, Intrinsic::experimental_guard))
812 return getModRefBehavior(CS1) & MRI_Mod ? MRI_Mod : MRI_NoModRef;
785813
786814 // The AAResultBase base class has some smarts, lets use them.
787815 return AAResultBase::getModRefInfo(CS1, CS2);
0 ; RUN: opt < %s -basicaa -aa-eval -print-all-alias-modref-info -disable-output 2>&1 | FileCheck %s
1 target datalayout = "e-p:32:32:32-i1:8:32-i8:8:32-i16:16:32-i32:32:32-i64:32:32-f32:32:32-f64:32:32-v64:32:64-v128:32:128-a0:0:32-n32"
2
3 declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture, i8* nocapture, i64, i32, i1) #0
4 declare void @llvm.experimental.guard(i1, ...)
5 declare void @unknown_but_readonly() readonly
6
7 define void @test1(i8* %P, i8* %Q) {
8 tail call void(i1,...) @llvm.experimental.guard(i1 true) [ "deopt"() ]
9 tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i32 1, i1 false)
10 ret void
11
12 ; CHECK-LABEL: Function: test1:
13
14 ; CHECK: Just Ref: Ptr: i8* %P <-> tail call void (i1, ...) @llvm.experimental.guard(i1 true) [ "deopt"() ]
15 ; CHECK: Just Ref: Ptr: i8* %Q <-> tail call void (i1, ...) @llvm.experimental.guard(i1 true) [ "deopt"() ]
16 ; CHECK: Both ModRef: Ptr: i8* %P <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i32 1, i1 false)
17 ; CHECK: Both ModRef: Ptr: i8* %Q <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i32 1, i1 false)
18 ; CHECK: Just Ref: tail call void (i1, ...) @llvm.experimental.guard(i1 true) [ "deopt"() ] <-> tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i32 1, i1 false)
19 ; CHECK: Just Mod: tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %P, i8* %Q, i64 12, i32 1, i1 false) <-> tail call void (i1, ...) @llvm.experimental.guard(i1 true) [ "deopt"() ]
20 }
21
22 define void @test2() {
23 tail call void(i1,...) @llvm.experimental.guard(i1 true) [ "deopt"() ]
24 tail call void @unknown_but_readonly()
25 ret void
26 ; CHECK-LABEL: Function: test2:
27 ; CHECK: NoModRef: tail call void (i1, ...) @llvm.experimental.guard(i1 true) [ "deopt"() ] <-> tail call void @unknown_but_readonly()
28 ; CHECK: NoModRef: tail call void @unknown_but_readonly() <-> tail call void (i1, ...) @llvm.experimental.guard(i1 true) [ "deopt"() ]
29 }