Index: llvm/include/llvm/Analysis/AliasAnalysis.h =================================================================== --- llvm/include/llvm/Analysis/AliasAnalysis.h +++ llvm/include/llvm/Analysis/AliasAnalysis.h @@ -250,8 +250,11 @@ FMRL_ArgumentPointees = 8, /// Memory that is inaccessible via LLVM IR. FMRL_InaccessibleMem = 16, + /// Access to global variables + FMRL_GlobalMem = 32, /// Access to any memory. - FMRL_Anywhere = 32 | FMRL_InaccessibleMem | FMRL_ArgumentPointees + FMRL_Anywhere = + 64 | FMRL_InaccessibleMem | FMRL_ArgumentPointees | FMRL_GlobalMem }; /// Summary of how a function affects memory in the program. @@ -363,6 +366,12 @@ // This property corresponds to the IntrWriteMem LLVM intrinsic flag. FMRB_OnlyWritesMemory = FMRL_Anywhere | static_cast(ModRefInfo::Mod), + /// This function only reads and writes global variables. + /// + /// This property corresponds to the LLVM IR 'globalmemonly' attribute. + FMRB_OnlyAccessesGlobalMem = + FMRL_GlobalMem | static_cast(ModRefInfo::ModRef), + /// This indicates that the function could not be classified into one of the /// behaviors above. FMRB_UnknownModRefBehavior = @@ -667,6 +676,12 @@ ~(FMRL_InaccessibleMem | FMRL_ArgumentPointees)); } + /// Checks if functions with the specified behavior are known to read and + /// write only from global variables. + static bool onlyAccessesGlobalMem(FunctionModRefBehavior MRB) { + return !((unsigned)MRB & FMRL_Anywhere & ~FMRL_GlobalMem); + } + /// getModRefInfo (for call sites) - Return information about whether /// a particular call site modifies or reads the specified memory location. ModRefInfo getModRefInfo(const CallBase *Call, const MemoryLocation &Loc); Index: llvm/include/llvm/IR/Function.h =================================================================== --- llvm/include/llvm/IR/Function.h +++ llvm/include/llvm/IR/Function.h @@ -542,6 +542,13 @@ addFnAttr(Attribute::InaccessibleMemOnly); } + /// Determine if the function may only access or modify global + /// variables + bool onlyAccessesGlobalMemory() const { + return hasFnAttribute(Attribute::GlobalMemOnly); + } + void setOnlyAccessesGlobalMemory() { addFnAttr(Attribute::GlobalMemOnly); } + /// Determine if the function may only access memory that is /// either inaccessible from the IR or pointed to by its arguments. bool onlyAccessesInaccessibleMemOrArgMem() const { Index: llvm/include/llvm/IR/InstrTypes.h =================================================================== --- llvm/include/llvm/IR/InstrTypes.h +++ llvm/include/llvm/IR/InstrTypes.h @@ -1848,6 +1848,16 @@ void setOnlyAccessesInaccessibleMemOrArgMem() { addFnAttr(Attribute::InaccessibleMemOrArgMemOnly); } + + /// Determine if the function may only access or modify global + /// variables + bool onlyAccessesGlobalMemory() const { + return hasFnAttr(Attribute::GlobalMemOnly); + } + void setOnlyAccessesGlobalMemory() { + addAttribute(AttributeList::FunctionIndex, Attribute::GlobalMemOnly); + } + /// Determine if the call cannot return. bool doesNotReturn() const { return hasFnAttr(Attribute::NoReturn); } void setDoesNotReturn() { addFnAttr(Attribute::NoReturn); } Index: llvm/lib/Analysis/AliasAnalysis.cpp =================================================================== --- llvm/lib/Analysis/AliasAnalysis.cpp +++ llvm/lib/Analysis/AliasAnalysis.cpp @@ -275,6 +275,16 @@ Result = IsMustAlias ? setMust(Result) : clearMust(Result); } + // If Loc is not a global memory location, it could not be modified or + // referenced by a call that only accesses global memory locations + if (onlyAccessesGlobalMem(MRB)) { + const Value *V1 = + getUnderlyingObject(Loc.Ptr->stripPointerCastsForAliasAnalysis()); + if (!isa(V1)) { + return ModRefInfo::NoModRef; + } + } + // If Loc is a constant memory location, the call definitely could not // modify the memory location. if (isModSet(Result) && pointsToConstantMemory(Loc, AAQI, /*OrLocal*/ false)) Index: llvm/lib/Analysis/BasicAliasAnalysis.cpp =================================================================== --- llvm/lib/Analysis/BasicAliasAnalysis.cpp +++ llvm/lib/Analysis/BasicAliasAnalysis.cpp @@ -695,6 +695,9 @@ else if (Call->onlyAccessesInaccessibleMemOrArgMem()) Min = FunctionModRefBehavior(Min & FMRB_OnlyAccessesInaccessibleOrArgMem); + if (Call->onlyAccessesGlobalMemory()) + Min = FunctionModRefBehavior(Min & FMRB_OnlyAccessesGlobalMem); + // If the call has operand bundles then aliasing attributes from the function // it calls do not directly apply to the call. This can be made more precise // in the future. @@ -728,6 +731,9 @@ else if (F->onlyAccessesInaccessibleMemOrArgMem()) Min = FunctionModRefBehavior(Min & FMRB_OnlyAccessesInaccessibleOrArgMem); + if (F->onlyAccessesGlobalMemory()) + Min = FunctionModRefBehavior(Min & FMRB_OnlyAccessesGlobalMem); + return Min; } Index: llvm/test/Analysis/BasicAA/globalmemonly.ll =================================================================== --- /dev/null +++ llvm/test/Analysis/BasicAA/globalmemonly.ll @@ -0,0 +1,32 @@ +; RUN: opt -basic-aa -print-all-alias-modref-info -aa-eval < %s 2>&1 | 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" + +@g = global i32 0, align 4 +@g2 = global i32 0, align 4 + +define void @globalmemonly_function(i32* %0) globalmemonly { +bb: + store i32 1, i32* @g2, align 4 + ret void +} + +define void @test_alloca_globalmemonly() { +; CHECK: Function: test_alloca_globalmemonly: 1 pointers, 1 call sites +; CHECK-NEXT: NoModRef: Ptr: i32* %0 <-> call void @globalmemonly_function(i32* %0) +bb: + %0= alloca i32, align 4 + store i32 1, i32* %0, align 4 + call void @globalmemonly_function(i32* %0) + ret void +} + +define void @test_global_globalmemonly() { +; CHECK: Function: test_global_globalmemonly: 1 pointers, 1 call sites +; CHECK-NEXT: Both ModRef: Ptr: i32* @g <-> call void @globalmemonly_function(i32* @g) + +bb: + call void @globalmemonly_function(i32* @g) + ret void +}