Index: include/llvm/Analysis/AliasSetTracker.h =================================================================== --- include/llvm/Analysis/AliasSetTracker.h +++ include/llvm/Analysis/AliasSetTracker.h @@ -37,8 +37,6 @@ class AliasSetTracker; class BasicBlock; class LoadInst; -class AnyMemSetInst; -class AnyMemTransferInst; class raw_ostream; class StoreInst; class VAArgInst; @@ -381,8 +379,6 @@ void add(LoadInst *LI); void add(StoreInst *SI); void add(VAArgInst *VAAI); - void add(AnyMemSetInst *MSI); - void add(AnyMemTransferInst *MTI); void add(Instruction *I); // Dispatch to one of the other add methods... void add(BasicBlock &BB); // Add all instructions in basic block void add(const AliasSetTracker &AST); // Add alias relations from another AST Index: include/llvm/Analysis/MemoryLocation.h =================================================================== --- include/llvm/Analysis/MemoryLocation.h +++ include/llvm/Analysis/MemoryLocation.h @@ -109,7 +109,11 @@ /// Return a location representing a particular argument of a call. static MemoryLocation getForArgument(ImmutableCallSite CS, unsigned ArgIdx, - const TargetLibraryInfo &TLI); + const TargetLibraryInfo *TLI); + static MemoryLocation getForArgument(ImmutableCallSite CS, unsigned ArgIdx, + const TargetLibraryInfo &TLI) { + return getForArgument(CS, ArgIdx, &TLI); + } explicit MemoryLocation(const Value *Ptr = nullptr, LocationSize Size = UnknownSize, Index: lib/Analysis/AliasAnalysis.cpp =================================================================== --- lib/Analysis/AliasAnalysis.cpp +++ lib/Analysis/AliasAnalysis.cpp @@ -121,6 +121,18 @@ ModRefInfo AAResults::getArgModRefInfo(ImmutableCallSite CS, unsigned ArgIdx) { ModRefInfo Result = ModRefInfo::ModRef; + // Use function information first, then fall back to analyzing each argument + // individually + auto MRB = getModRefBehavior(CS); + if (MRB == FMRB_DoesNotAccessMemory || + MRB == FMRB_OnlyAccessesInaccessibleMem) + return ModRefInfo::NoModRef; + + if (onlyReadsMemory(MRB)) + Result = clearMod(Result); + else if (doesNotReadMemory(MRB)) + Result = clearRef(Result); + for (const auto &AA : AAs) { Result = intersectModRef(Result, AA->getArgModRefInfo(CS, ArgIdx)); Index: lib/Analysis/AliasSetTracker.cpp =================================================================== --- lib/Analysis/AliasSetTracker.cpp +++ lib/Analysis/AliasSetTracker.cpp @@ -372,28 +372,6 @@ addPointer(MemoryLocation::get(VAAI), AliasSet::ModRefAccess); } -void AliasSetTracker::add(AnyMemSetInst *MSI) { - auto MemLoc = MemoryLocation::getForDest(MSI); - AliasSet &AS = addPointer(MemLoc, AliasSet::ModAccess); - auto *MS = dyn_cast(MSI); - if (MS && MS->isVolatile()) - AS.setVolatile(); -} - -void AliasSetTracker::add(AnyMemTransferInst *MTI) { - auto SrcLoc = MemoryLocation::getForSource(MTI); - AliasSet &ASSrc = addPointer(SrcLoc, AliasSet::RefAccess); - - auto DestLoc = MemoryLocation::getForDest(MTI); - AliasSet &ASDst = addPointer(DestLoc, AliasSet::ModAccess); - - auto* MT = dyn_cast(MTI); - if (MT && MT->isVolatile()) { - ASSrc.setVolatile(); - ASDst.setVolatile(); - } -} - void AliasSetTracker::addUnknown(Instruction *Inst) { if (isa(Inst)) return; // Ignore DbgInfo Intrinsics. @@ -431,10 +409,39 @@ return add(SI); if (VAArgInst *VAAI = dyn_cast(I)) return add(VAAI); - if (AnyMemSetInst *MSI = dyn_cast(I)) - return add(MSI); - if (AnyMemTransferInst *MTI = dyn_cast(I)) - return add(MTI); + + // Handle all calls with known mod/ref sets generically, but special case the + // two family of intrinsics which can involve volatile access. + bool VolatileAccess = false; + if (auto *MS = dyn_cast(I)) + if (MS->isVolatile()) + VolatileAccess = true; + if (auto* MT = dyn_cast(I)) + if (MT->isVolatile()) + VolatileAccess = true; + + CallSite CS(I); + if (CS && CS.onlyAccessesArgMemory()) { + for (auto AI = CS.arg_begin(), AE = CS.arg_end(); AI != AE; ++AI) { + const Value *Arg = *AI; + if (!Arg->getType()->isPointerTy()) + continue; + unsigned ArgIdx = std::distance(CS.arg_begin(), AI); + MemoryLocation ArgLoc = MemoryLocation::getForArgument(CS, ArgIdx, + nullptr); + ModRefInfo ArgMask = AA.getArgModRefInfo(CS, ArgIdx); + auto Access = AliasSet::ModRefAccess; + if (isRefSet(ArgMask) && !isModSet(ArgMask)) + Access = AliasSet::RefAccess; + else if (!isRefSet(ArgMask) && isModSet(ArgMask)) + Access = AliasSet::ModAccess; + else if (!isRefSet(ArgMask) && !isModSet(ArgMask)) + Access = AliasSet::NoAccess; + auto &AS = addPointer(ArgLoc, Access); + if (VolatileAccess) AS.setVolatile(); + } + return; + } return addUnknown(I); } Index: lib/Analysis/MemoryLocation.cpp =================================================================== --- lib/Analysis/MemoryLocation.cpp +++ lib/Analysis/MemoryLocation.cpp @@ -108,7 +108,7 @@ MemoryLocation MemoryLocation::getForArgument(ImmutableCallSite CS, unsigned ArgIdx, - const TargetLibraryInfo &TLI) { + const TargetLibraryInfo *TLI) { AAMDNodes AATags; CS->getAAMetadata(AATags); const Value *Arg = CS.getArgument(ArgIdx); @@ -159,8 +159,9 @@ // LoopIdiomRecognizer likes to turn loops into calls to memset_pattern16 // whenever possible. LibFunc F; - if (CS.getCalledFunction() && TLI.getLibFunc(*CS.getCalledFunction(), F) && - F == LibFunc_memset_pattern16 && TLI.has(F)) { + if (CS.getCalledFunction() && TLI && + TLI->getLibFunc(*CS.getCalledFunction(), F) && + F == LibFunc_memset_pattern16 && TLI->has(F)) { assert((ArgIdx == 0 || ArgIdx == 1) && "Invalid argument index for memset_pattern16"); if (ArgIdx == 1) Index: test/Transforms/LICM/argmemonly-call.ll =================================================================== --- test/Transforms/LICM/argmemonly-call.ll +++ test/Transforms/LICM/argmemonly-call.ll @@ -68,3 +68,40 @@ store i32 %res, i32* %loc br label %loop } + +; memcpy doesn't write to it's source argument, so loads to that location +; can still be hoisted +define void @test5(i32* noalias %loc, i32* noalias %loc2) { +; CHECK-LABEL: @test5 +; CHECK: %val = load i32, i32* %loc2 +; CHECK-LABEL: loop: +; CHECK: @llvm.memcpy + br label %loop + +loop: + %val = load i32, i32* %loc2 + store i32 %val, i32* %loc + %dest = bitcast i32* %loc to i8* + %src = bitcast i32* %loc2 to i8* + call void @llvm.memcpy.p0i8.p0i8.i64(i8* %dest, i8* %src, i64 8, i1 false) + br label %loop +} + +define void @test6(i32* noalias %loc, i32* noalias %loc2) { +; CHECK-LABEL: @test6 +; CHECK: %val = load i32, i32* %loc2 +; CHECK-LABEL: loop: +; CHECK: @custom_memcpy + br label %loop + +loop: + %val = load i32, i32* %loc2 + store i32 %val, i32* %loc + %dest = bitcast i32* %loc to i8* + %src = bitcast i32* %loc2 to i8* + call void @custom_memcpy(i8* %dest, i8* %src) + br label %loop +} + +declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture writeonly, i8* nocapture readonly, i64, i1) +declare void @custom_memcpy(i8* nocapture writeonly, i8* nocapture readonly) argmemonly nounwind