Index: llvm/trunk/include/llvm/Analysis/AliasAnalysis.h =================================================================== --- llvm/trunk/include/llvm/Analysis/AliasAnalysis.h +++ llvm/trunk/include/llvm/Analysis/AliasAnalysis.h @@ -112,8 +112,10 @@ FMRL_Nowhere = 0, /// Access to memory via argument pointers. FMRL_ArgumentPointees = 4, + /// Memory that is inaccessible via LLVM IR. + FMRL_InaccessibleMem = 8, /// Access to any memory. - FMRL_Anywhere = 8 | FMRL_ArgumentPointees + FMRL_Anywhere = 16 | FMRL_InaccessibleMem | FMRL_ArgumentPointees }; /// Summary of how a function affects memory in the program. @@ -143,6 +145,22 @@ /// This property corresponds to the IntrArgMemOnly LLVM intrinsic flag. FMRB_OnlyAccessesArgumentPointees = FMRL_ArgumentPointees | MRI_ModRef, + /// The only memory references in this function (if it has any) are + /// references of memory that is otherwise inaccessible via LLVM IR. + /// + /// This property corresponds to the LLVM IR inaccessiblememonly attribute. + FMRB_OnlyAccessesInaccessibleMem = FMRL_InaccessibleMem | MRI_ModRef, + + /// The function may perform non-volatile loads and stores of objects + /// pointed to by its pointer-typed arguments, with arbitrary offsets, and + /// it may also perform loads and stores of memory that is otherwise + /// inaccessible via LLVM IR. + /// + /// This property corresponds to the LLVM IR + /// inaccessiblemem_or_argmemonly attribute. + FMRB_OnlyAccessesInaccessibleOrArgMem = FMRL_InaccessibleMem | + FMRL_ArgumentPointees | MRI_ModRef, + /// This function does not perform any non-local stores or volatile loads, /// but may read from any memory location. /// @@ -339,6 +357,26 @@ return (MRB & MRI_ModRef) && (MRB & FMRL_ArgumentPointees); } + /// Checks if functions with the specified behavior are known to read and + /// write at most from memory that is inaccessible from LLVM IR. + static bool onlyAccessesInaccessibleMem(FunctionModRefBehavior MRB) { + return !(MRB & FMRL_Anywhere & ~FMRL_InaccessibleMem); + } + + /// Checks if functions with the specified behavior are known to potentially + /// read or write from memory that is inaccessible from LLVM IR. + static bool doesAccessInaccessibleMem(FunctionModRefBehavior MRB) { + return (MRB & MRI_ModRef) && (MRB & FMRL_InaccessibleMem); + } + + /// Checks if functions with the specified behavior are known to read and + /// write at most from memory that is inaccessible from LLVM IR or objects + /// pointed to by their pointer-typed arguments (with arbitrary offsets). + static bool onlyAccessesInaccessibleOrArgMem(FunctionModRefBehavior MRB) { + return !(MRB & FMRL_Anywhere & + ~(FMRL_InaccessibleMem | FMRL_ArgumentPointees)); + } + /// getModRefInfo (for call sites) - Return information about whether /// a particular call site modifies or reads the specified memory location. ModRefInfo getModRefInfo(ImmutableCallSite CS, const MemoryLocation &Loc); Index: llvm/trunk/lib/Analysis/AliasAnalysis.cpp =================================================================== --- llvm/trunk/lib/Analysis/AliasAnalysis.cpp +++ llvm/trunk/lib/Analysis/AliasAnalysis.cpp @@ -141,7 +141,8 @@ // Try to refine the mod-ref info further using other API entry points to the // aggregate set of AA results. auto MRB = getModRefBehavior(CS); - if (MRB == FMRB_DoesNotAccessMemory) + if (MRB == FMRB_DoesNotAccessMemory || + MRB == FMRB_OnlyAccessesInaccessibleMem) return MRI_NoModRef; if (onlyReadsMemory(MRB)) @@ -149,7 +150,7 @@ else if (doesNotReadMemory(MRB)) Result = ModRefInfo(Result & MRI_Mod); - if (onlyAccessesArgPointees(MRB)) { + if (onlyAccessesArgPointees(MRB) || onlyAccessesInaccessibleOrArgMem(MRB)) { bool DoesAlias = false; ModRefInfo AllArgsMask = MRI_NoModRef; if (doesAccessArgPointees(MRB)) { Index: llvm/trunk/lib/Analysis/BasicAliasAnalysis.cpp =================================================================== --- llvm/trunk/lib/Analysis/BasicAliasAnalysis.cpp +++ llvm/trunk/lib/Analysis/BasicAliasAnalysis.cpp @@ -609,6 +609,10 @@ if (F->onlyAccessesArgMemory()) Min = FunctionModRefBehavior(Min & FMRB_OnlyAccessesArgumentPointees); + else if (F->onlyAccessesInaccessibleMemory()) + Min = FunctionModRefBehavior(Min & FMRB_OnlyAccessesInaccessibleMem); + else if (F->onlyAccessesInaccessibleMemOrArgMem()) + Min = FunctionModRefBehavior(Min & FMRB_OnlyAccessesInaccessibleOrArgMem); return Min; } Index: llvm/trunk/test/Analysis/BasicAA/cs-cs.ll =================================================================== --- llvm/trunk/test/Analysis/BasicAA/cs-cs.ll +++ llvm/trunk/test/Analysis/BasicAA/cs-cs.ll @@ -23,18 +23,18 @@ ; CHECK-LABEL: Function: test1: ; CHECK: NoAlias: i8* %p, i8* %q -; CHECK: Just Ref: Ptr: i8* %p <-> %a = call <8 x i16> @llvm.arm.neon.vld1.v8i16.p0i8(i8* %p, i32 16) #5 -; CHECK: NoModRef: Ptr: i8* %q <-> %a = call <8 x i16> @llvm.arm.neon.vld1.v8i16.p0i8(i8* %p, i32 16) #5 +; CHECK: Just Ref: Ptr: i8* %p <-> %a = call <8 x i16> @llvm.arm.neon.vld1.v8i16.p0i8(i8* %p, i32 16) +; CHECK: NoModRef: Ptr: i8* %q <-> %a = call <8 x i16> @llvm.arm.neon.vld1.v8i16.p0i8(i8* %p, i32 16) ; CHECK: NoModRef: Ptr: i8* %p <-> call void @llvm.arm.neon.vst1.p0i8.v8i16(i8* %q, <8 x i16> %y, i32 16) ; CHECK: Both ModRef: Ptr: i8* %q <-> call void @llvm.arm.neon.vst1.p0i8.v8i16(i8* %q, <8 x i16> %y, i32 16) -; CHECK: Just Ref: Ptr: i8* %p <-> %b = call <8 x i16> @llvm.arm.neon.vld1.v8i16.p0i8(i8* %p, i32 16) #5 -; CHECK: NoModRef: Ptr: i8* %q <-> %b = call <8 x i16> @llvm.arm.neon.vld1.v8i16.p0i8(i8* %p, i32 16) #5 -; CHECK: NoModRef: %a = call <8 x i16> @llvm.arm.neon.vld1.v8i16.p0i8(i8* %p, i32 16) #5 <-> call void @llvm.arm.neon.vst1.p0i8.v8i16(i8* %q, <8 x i16> %y, i32 16) -; CHECK: NoModRef: %a = call <8 x i16> @llvm.arm.neon.vld1.v8i16.p0i8(i8* %p, i32 16) #5 <-> %b = call <8 x i16> @llvm.arm.neon.vld1.v8i16.p0i8(i8* %p, i32 16) #5 -; CHECK: NoModRef: call void @llvm.arm.neon.vst1.p0i8.v8i16(i8* %q, <8 x i16> %y, i32 16) <-> %a = call <8 x i16> @llvm.arm.neon.vld1.v8i16.p0i8(i8* %p, i32 16) #5 -; CHECK: NoModRef: call void @llvm.arm.neon.vst1.p0i8.v8i16(i8* %q, <8 x i16> %y, i32 16) <-> %b = call <8 x i16> @llvm.arm.neon.vld1.v8i16.p0i8(i8* %p, i32 16) #5 -; CHECK: NoModRef: %b = call <8 x i16> @llvm.arm.neon.vld1.v8i16.p0i8(i8* %p, i32 16) #5 <-> %a = call <8 x i16> @llvm.arm.neon.vld1.v8i16.p0i8(i8* %p, i32 16) #5 -; CHECK: NoModRef: %b = call <8 x i16> @llvm.arm.neon.vld1.v8i16.p0i8(i8* %p, i32 16) #5 <-> call void @llvm.arm.neon.vst1.p0i8.v8i16(i8* %q, <8 x i16> %y, i32 16) +; CHECK: Just Ref: Ptr: i8* %p <-> %b = call <8 x i16> @llvm.arm.neon.vld1.v8i16.p0i8(i8* %p, i32 16) +; CHECK: NoModRef: Ptr: i8* %q <-> %b = call <8 x i16> @llvm.arm.neon.vld1.v8i16.p0i8(i8* %p, i32 16) +; CHECK: NoModRef: %a = call <8 x i16> @llvm.arm.neon.vld1.v8i16.p0i8(i8* %p, i32 16) #{{[0-9]+}} <-> call void @llvm.arm.neon.vst1.p0i8.v8i16(i8* %q, <8 x i16> %y, i32 16) +; CHECK: NoModRef: %a = call <8 x i16> @llvm.arm.neon.vld1.v8i16.p0i8(i8* %p, i32 16) #{{[0-9]+}} <-> %b = call <8 x i16> @llvm.arm.neon.vld1.v8i16.p0i8(i8* %p, i32 16) +; CHECK: NoModRef: call void @llvm.arm.neon.vst1.p0i8.v8i16(i8* %q, <8 x i16> %y, i32 16) <-> %a = call <8 x i16> @llvm.arm.neon.vld1.v8i16.p0i8(i8* %p, i32 16) +; CHECK: NoModRef: call void @llvm.arm.neon.vst1.p0i8.v8i16(i8* %q, <8 x i16> %y, i32 16) <-> %b = call <8 x i16> @llvm.arm.neon.vld1.v8i16.p0i8(i8* %p, i32 16) +; CHECK: NoModRef: %b = call <8 x i16> @llvm.arm.neon.vld1.v8i16.p0i8(i8* %p, i32 16) #{{[0-9]+}} <-> %a = call <8 x i16> @llvm.arm.neon.vld1.v8i16.p0i8(i8* %p, i32 16) +; CHECK: NoModRef: %b = call <8 x i16> @llvm.arm.neon.vld1.v8i16.p0i8(i8* %p, i32 16) #{{[0-9]+}} <-> call void @llvm.arm.neon.vst1.p0i8.v8i16(i8* %q, <8 x i16> %y, i32 16) } define void @test2(i8* %P, i8* %Q) nounwind ssp { @@ -247,10 +247,45 @@ ; CHECK: Just Ref: call void @a_readonly_func(i8* %P) <-> call void @a_writeonly_func(i8* %P) } -attributes #0 = { argmemonly nounwind readonly } -attributes #1 = { argmemonly nounwind } -attributes #2 = { noinline nounwind readonly } -attributes #3 = { noinline nounwind writeonly } -attributes #4 = { nounwind ssp } -attributes #5 = { nounwind } +declare void @an_inaccessiblememonly_func() nounwind inaccessiblememonly +declare void @an_inaccessibleorargmemonly_func(i8 *) nounwind inaccessiblemem_or_argmemonly +declare void @an_argmemonly_func(i8 *) nounwind argmemonly +define void @test8(i8* %p) { +entry: + %q = getelementptr i8, i8* %p, i64 16 + call void @a_readonly_func(i8* %p) + call void @an_inaccessiblememonly_func() + call void @a_writeonly_func(i8* %q) + call void @an_inaccessiblememonly_func() + call void @an_inaccessibleorargmemonly_func(i8* %q) + call void @an_argmemonly_func(i8* %q) + ret void + +; CHECK-LABEL: Function: test8 +; CHECK: NoModRef: Ptr: i8* %p <-> call void @an_inaccessiblememonly_func() +; CHECK: NoModRef: Ptr: i8* %q <-> call void @an_inaccessiblememonly_func() +; CHECK: NoModRef: Ptr: i8* %p <-> call void @an_inaccessibleorargmemonly_func(i8* %q) +; CHECK: Both ModRef: Ptr: i8* %q <-> call void @an_inaccessibleorargmemonly_func(i8* %q) +; CHECK: NoModRef: Ptr: i8* %p <-> call void @an_argmemonly_func(i8* %q) +; CHECK: Both ModRef: Ptr: i8* %q <-> call void @an_argmemonly_func(i8* %q) +; CHECK: Just Ref: call void @a_readonly_func(i8* %p) <-> call void @an_inaccessiblememonly_func() +; CHECK: Just Ref: call void @a_readonly_func(i8* %p) <-> call void @an_inaccessibleorargmemonly_func(i8* %q) +; CHECK: Just Ref: call void @a_readonly_func(i8* %p) <-> call void @an_argmemonly_func(i8* %q) +; CHECK: Both ModRef: call void @an_inaccessiblememonly_func() <-> call void @a_readonly_func(i8* %p) +; CHECK: Both ModRef: call void @an_inaccessiblememonly_func() <-> call void @a_writeonly_func(i8* %q) +; CHECK: Both ModRef: call void @an_inaccessiblememonly_func() <-> call void @an_inaccessiblememonly_func() +; CHECK: Both ModRef: call void @an_inaccessiblememonly_func() <-> call void @an_inaccessibleorargmemonly_func(i8* %q) +; CHECK: NoModRef: call void @an_inaccessiblememonly_func() <-> call void @an_argmemonly_func(i8* %q) +; CHECK: Just Mod: call void @a_writeonly_func(i8* %q) <-> call void @an_inaccessiblememonly_func() +; CHECK: Just Mod: call void @a_writeonly_func(i8* %q) <-> call void @an_inaccessibleorargmemonly_func(i8* %q) +; CHECK: Just Mod: call void @a_writeonly_func(i8* %q) <-> call void @an_argmemonly_func(i8* %q) +; CHECK: Both ModRef: call void @an_inaccessibleorargmemonly_func(i8* %q) <-> call void @a_readonly_func(i8* %p) +; CHECK: Both ModRef: call void @an_inaccessibleorargmemonly_func(i8* %q) <-> call void @a_writeonly_func(i8* %q) +; CHECK: Both ModRef: call void @an_inaccessibleorargmemonly_func(i8* %q) <-> call void @an_inaccessiblememonly_func() +; CHECK: Both ModRef: call void @an_inaccessibleorargmemonly_func(i8* %q) <-> call void @an_argmemonly_func(i8* %q) +; CHECK: Both ModRef: call void @an_argmemonly_func(i8* %q) <-> call void @a_readonly_func(i8* %p) +; CHECK: Both ModRef: call void @an_argmemonly_func(i8* %q) <-> call void @a_writeonly_func(i8* %q) +; CHECK: NoModRef: call void @an_argmemonly_func(i8* %q) <-> call void @an_inaccessiblememonly_func() +; CHECK: Both ModRef: call void @an_argmemonly_func(i8* %q) <-> call void @an_inaccessibleorargmemonly_func(i8* %q) +}