Index: llvm/include/llvm/Analysis/AliasSetTracker.h =================================================================== --- llvm/include/llvm/Analysis/AliasSetTracker.h +++ llvm/include/llvm/Analysis/AliasSetTracker.h @@ -138,6 +138,10 @@ } delete this; } + void updateNoAliasSideChannelIfMatching(Value *Old, Value *New) { + if (AAInfo.NoAliasSideChannel == Old) + AAInfo.NoAliasSideChannel = New; + } }; // Doubly linked list of nodes. @@ -354,6 +358,25 @@ // Map from pointers to their node PointerMapType PointerMap; + // FIXME: NOTE: when we get a callback, the resulting update might be _SLOW_ + class ASTSideChannelCallbackVH final : public CallbackVH { + AliasSetTracker *AST; + + void deleted() override; + void allUsesReplacedWith(Value *) override; + + public: + ASTSideChannelCallbackVH(Value *V, AliasSetTracker *AST = nullptr); + ASTSideChannelCallbackVH &operator=(Value *V); + }; + + /// Traits to tell DenseMap that tell us how to compare and hash the value + /// handle. + struct ASTSideChannelCallbackVHDenseMapInfo : public DenseMapInfo {}; + using SideChannelSetType = + DenseSet; + SideChannelSetType SideChannelPointers; + public: /// Create an empty collection of AliasSets, and use the specified alias /// analysis object to disambiguate load and store addresses. @@ -412,6 +435,19 @@ /// tracker already knows about a value, it will ignore the request. void copyValue(Value *From, Value *To); + /// This method is used to remove a side_channel pointer value from the + /// AliasSetTracker entirely. It should be used when an instruction is deleted + /// from the program to update the AST. If you don't use this, you would have + /// dangling pointers to deleted instructions. + void deleteSideChannelValue(Value *PtrVal); + + /// This method should be used whenever a preexisting side_channel value in + /// the program is copied or cloned, introducing a new value. Note that it is + /// ok for clients that use this method to introduce the same value multiple + /// times: if the tracker already knows about a value, it will ignore the + /// request. + void copySideChannelValue(Value *From, Value *To); + using iterator = ilist::iterator; using const_iterator = ilist::const_iterator; Index: llvm/include/llvm/Analysis/BasicAliasAnalysis.h =================================================================== --- llvm/include/llvm/Analysis/BasicAliasAnalysis.h +++ llvm/include/llvm/Analysis/BasicAliasAnalysis.h @@ -61,6 +61,7 @@ DominatorTree *DT; LoopInfo *LI; PhiValues *PV; + unsigned RecurseLevel = 0; public: BasicAAResult(const DataLayout &DL, const Function &F, Index: llvm/include/llvm/Analysis/ScopedNoAliasAA.h =================================================================== --- llvm/include/llvm/Analysis/ScopedNoAliasAA.h +++ llvm/include/llvm/Analysis/ScopedNoAliasAA.h @@ -21,8 +21,8 @@ #include namespace llvm { - class DominatorTree; + class Function; class MDNode; class MemoryLocation; @@ -64,12 +64,10 @@ SmallPtrSetImpl &Visited, SmallVectorImpl &CompatibleSet, int Depth = 0); - bool noAliasByIntrinsic(const MDNode *ANoAlias, - const Value *APtr, - const MDNode *BNoAlias, - const Value *BPtr, - const CallBase *CallA = nullptr, - const CallBase *CallB = nullptr); + bool noAliasByIntrinsic(const MDNode *ANoAlias, const Value *APtr, + const MDNode *BNoAlias, const Value *BPtr, + const CallBase *CallA, const CallBase *CallB, + AAQueryInfo &AAQI); DominatorTree *DT; }; @@ -95,7 +93,10 @@ ScopedNoAliasAAWrapperPass(); - ScopedNoAliasAAResult &getResult() { setDT(); return *Result; } + ScopedNoAliasAAResult &getResult() { + setDT(); + return *Result; + } const ScopedNoAliasAAResult &getResult() const { return *Result; } bool doInitialization(Module &M) override; Index: llvm/include/llvm/IR/Instruction.h =================================================================== --- llvm/include/llvm/IR/Instruction.h +++ llvm/include/llvm/IR/Instruction.h @@ -309,8 +309,15 @@ /// @} /// Sets the metadata on this instruction from the AAMDNodes structure. + /// NOTE: The noalias_sidechannel must be copied over explicitely using + /// 'setAAMetadataNoAliasSideChannel'. This must only be done if the dominator + /// relationship between the noalias_sidechannel and this instruction holds. void setAAMetadata(const AAMDNodes &N); + /// Sets (only) the noalias_sidechannel. Normally used in combination with + /// setAAMetadata. + void setAAMetadataNoAliasSideChannel(const AAMDNodes &N); + /// Retrieve the raw weight values of a conditional branch or select. /// Returns true on success with profile weights filled in. /// Returns false if no metadata or invalid metadata was found. Index: llvm/include/llvm/IR/Metadata.h =================================================================== --- llvm/include/llvm/IR/Metadata.h +++ llvm/include/llvm/IR/Metadata.h @@ -642,16 +642,19 @@ /// memory access used by the alias-analysis infrastructure. struct AAMDNodes { explicit AAMDNodes(MDNode *T = nullptr, MDNode *S = nullptr, - MDNode *N = nullptr) - : TBAA(T), Scope(S), NoAlias(N) {} + MDNode *N = nullptr, Value *NSC = nullptr) + : TBAA(T), Scope(S), NoAlias(N), NoAliasSideChannel(NSC) {} bool operator==(const AAMDNodes &A) const { - return TBAA == A.TBAA && Scope == A.Scope && NoAlias == A.NoAlias; + return TBAA == A.TBAA && Scope == A.Scope && NoAlias == A.NoAlias && + NoAliasSideChannel == A.NoAliasSideChannel; } bool operator!=(const AAMDNodes &A) const { return !(*this == A); } - explicit operator bool() const { return TBAA || Scope || NoAlias; } + explicit operator bool() const { + return TBAA || Scope || NoAlias || NoAliasSideChannel; + } /// The tag for type-based alias analysis. MDNode *TBAA; @@ -662,6 +665,9 @@ /// The tag specifying the noalias scope. MDNode *NoAlias; + /// The NoAlias SideChannel pointer path + Value *NoAliasSideChannel; + /// Given two sets of AAMDNodes that apply to the same pointer, /// give the best AAMDNodes that are compatible with both (i.e. a set of /// nodes whose allowable aliasing conclusions are a subset of those @@ -672,6 +678,9 @@ Result.TBAA = Other.TBAA == TBAA ? TBAA : nullptr; Result.Scope = Other.Scope == Scope ? Scope : nullptr; Result.NoAlias = Other.NoAlias == NoAlias ? NoAlias : nullptr; + Result.NoAliasSideChannel = Other.NoAliasSideChannel == NoAliasSideChannel + ? NoAliasSideChannel + : nullptr; return Result; } }; @@ -692,7 +701,8 @@ static unsigned getHashValue(const AAMDNodes &Val) { return DenseMapInfo::getHashValue(Val.TBAA) ^ DenseMapInfo::getHashValue(Val.Scope) ^ - DenseMapInfo::getHashValue(Val.NoAlias); + DenseMapInfo::getHashValue(Val.NoAlias) ^ + DenseMapInfo::getHashValue(Val.NoAliasSideChannel); } static bool isEqual(const AAMDNodes &LHS, const AAMDNodes &RHS) { @@ -1425,6 +1435,32 @@ // Create wrappers for C Binding types (see CBindingWrapping.h). DEFINE_ISA_CONVERSION_FUNCTIONS(NamedMDNode, LLVMNamedMDNodeRef) +/// This is a simple wrapper around an MDNode which provides a higher-level +/// interface by hiding the details of how alias analysis information is encoded +/// in its operands. +class AliasScopeNode { + const MDNode *Node = nullptr; + +public: + AliasScopeNode() = default; + explicit AliasScopeNode(const MDNode *N) : Node(N) {} + + /// Get the MDNode for this AliasScopeNode. + const MDNode *getNode() const { return Node; } + + /// Get the MDNode for this AliasScopeNode's domain. + const MDNode *getDomain() const { + if (Node->getNumOperands() < 2) + return nullptr; + return dyn_cast_or_null(Node->getOperand(1)); + } + StringRef getName() const { + if (Node->getNumOperands() > 2) + if (MDString *N = dyn_cast_or_null(Node->getOperand(2))) + return N->getString(); + return StringRef(); + } +}; } // end namespace llvm #endif // LLVM_IR_METADATA_H Index: llvm/lib/Analysis/AliasSetTracker.cpp =================================================================== --- llvm/lib/Analysis/AliasSetTracker.cpp +++ llvm/lib/Analysis/AliasSetTracker.cpp @@ -292,6 +292,7 @@ I->second->eraseFromList(); PointerMap.clear(); + SideChannelPointers.clear(); // The alias sets should all be clear now. AliasSets.clear(); @@ -357,6 +358,10 @@ AliasSet::PointerRec &Entry = getEntryFor(Pointer); + if (AAInfo.NoAliasSideChannel) + SideChannelPointers.insert( + ASTSideChannelCallbackVH(AAInfo.NoAliasSideChannel, this)); + if (AliasAnyAS) { // At this point, the AST is saturated, so we only have one active alias // set. That means we already know which alias set we want to return, and @@ -732,6 +737,65 @@ return *this = ASTCallbackVH(V, AST); } +//===----------------------------------------------------------------------===// +// ASTSideChannelCallbackVH Class Implementation +//===----------------------------------------------------------------------===// + +void AliasSetTracker::ASTSideChannelCallbackVH::deleted() { + assert(AST && "ASTCallbackVH called with a null AliasSetTracker!"); + AST->deleteSideChannelValue(getValPtr()); + // this now dangles! +} + +void AliasSetTracker::ASTSideChannelCallbackVH::allUsesReplacedWith(Value *V) { + AST->copySideChannelValue(getValPtr(), V); +} + +AliasSetTracker::ASTSideChannelCallbackVH::ASTSideChannelCallbackVH( + Value *V, AliasSetTracker *ast) + : CallbackVH(V), AST(ast) {} + +AliasSetTracker::ASTSideChannelCallbackVH & +AliasSetTracker::ASTSideChannelCallbackVH::operator=(Value *V) { + return *this = ASTSideChannelCallbackVH(V, AST); +} + +void AliasSetTracker::deleteSideChannelValue(Value *PtrVal) { + // FIXME: slow algorithms ahead + SideChannelSetType::iterator I = SideChannelPointers.find_as(PtrVal); + if (I == SideChannelPointers.end()) + return; // nope + + // iterate over all PointerRecords to update the AAMDNodes that contain this + // pointer + for (auto &AS : *this) { + for (auto &PR : AS) { + PR.updateNoAliasSideChannelIfMatching(PtrVal, nullptr); + } + } + + SideChannelPointers.erase(I); +} + +void AliasSetTracker::copySideChannelValue(Value *From, Value *To) { + // FIXME: slow algorithms ahead + SideChannelSetType::iterator I = SideChannelPointers.find_as(From); + if (I == SideChannelPointers.end()) + return; // nope + + // iterate over all PointerRecords to update the AAMDNodes that contain this + // pointer + for (auto &AS : *this) { + for (auto &PR : AS) { + PR.updateNoAliasSideChannelIfMatching(From, To); + } + } + + // Update the set + SideChannelPointers.erase(I); + SideChannelPointers.insert(ASTSideChannelCallbackVH(To, this)); +} + //===----------------------------------------------------------------------===// // AliasSetPrinter Pass //===----------------------------------------------------------------------===// Index: llvm/lib/Analysis/BasicAliasAnalysis.cpp =================================================================== --- llvm/lib/Analysis/BasicAliasAnalysis.cpp +++ llvm/lib/Analysis/BasicAliasAnalysis.cpp @@ -853,10 +853,15 @@ if (CacheIt != AAQI.AliasCache.end()) return CacheIt->second; + ++RecurseLevel; AliasResult Alias = aliasCheck(LocA.Ptr, LocA.Size, LocA.AATags, LocB.Ptr, LocB.Size, LocB.AATags, AAQI); - VisitedPhiBBs.clear(); + // protect cache against recursive calls from ScopedNoAliasAA: only clean up + // at the top level + if (--RecurseLevel == 0) { + VisitedPhiBBs.clear(); + } return Alias; } Index: llvm/lib/Analysis/ScopedNoAliasAA.cpp =================================================================== --- llvm/lib/Analysis/ScopedNoAliasAA.cpp +++ llvm/lib/Analysis/ScopedNoAliasAA.cpp @@ -32,12 +32,13 @@ //===----------------------------------------------------------------------===// #include "llvm/Analysis/ScopedNoAliasAA.h" -#include "llvm/Analysis/CaptureTracking.h" -#include "llvm/Analysis/ValueTracking.h" #include "llvm/ADT/SmallPtrSet.h" +#include "llvm/Analysis/CaptureTracking.h" #include "llvm/Analysis/MemoryLocation.h" +#include "llvm/Analysis/ValueTracking.h" #include "llvm/IR/Dominators.h" #include "llvm/IR/Instruction.h" +#include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Metadata.h" #include "llvm/Pass.h" @@ -60,31 +61,6 @@ MaxNoAliasDepth("scoped-noalias-max-depth", cl::init(12), cl::Hidden, cl::desc("Maximum depth for noalias intrinsic search")); -namespace { - -/// This is a simple wrapper around an MDNode which provides a higher-level -/// interface by hiding the details of how alias analysis information is encoded -/// in its operands. -class AliasScopeNode { - const MDNode *Node = nullptr; - -public: - AliasScopeNode() = default; - explicit AliasScopeNode(const MDNode *N) : Node(N) {} - - /// Get the MDNode for this AliasScopeNode. - const MDNode *getNode() const { return Node; } - - /// Get the MDNode for this AliasScopeNode's domain. - const MDNode *getDomain() const { - if (Node->getNumOperands() < 2) - return nullptr; - return dyn_cast_or_null(Node->getOperand(1)); - } -}; - -} // end anonymous namespace - AliasResult ScopedNoAliasAAResult::alias(const MemoryLocation &LocA, const MemoryLocation &LocB, AAQueryInfo &AAQI) { @@ -102,11 +78,17 @@ if (!mayAliasInScopes(BScopes, ANoAlias)) return NoAlias; - if (noAliasByIntrinsic(ANoAlias, LocA.Ptr, BNoAlias, LocB.Ptr)) - return NoAlias; + if (LocA.AATags.NoAliasSideChannel && LocB.AATags.NoAliasSideChannel) { + if (noAliasByIntrinsic(ANoAlias, LocA.AATags.NoAliasSideChannel, BNoAlias, + LocB.AATags.NoAliasSideChannel, nullptr, nullptr, + AAQI)) + return NoAlias; - if (noAliasByIntrinsic(BNoAlias, LocB.Ptr, ANoAlias, LocA.Ptr)) - return NoAlias; + if (noAliasByIntrinsic(BNoAlias, LocB.AATags.NoAliasSideChannel, ANoAlias, + LocA.AATags.NoAliasSideChannel, nullptr, nullptr, + AAQI)) + return NoAlias; + } // If they may alias, chain to the next AliasAnalysis. return AAResultBase::alias(LocA, LocB, AAQI); @@ -128,12 +110,15 @@ if (!mayAliasInScopes(CSScopes, Loc.AATags.NoAlias)) return ModRefInfo::NoModRef; - if (noAliasByIntrinsic(Loc.AATags.NoAlias, Loc.Ptr, CSNoAlias, - nullptr, nullptr, Call)) - return ModRefInfo::NoModRef; + if (Loc.AATags.NoAliasSideChannel) { + if (noAliasByIntrinsic(Loc.AATags.NoAlias, Loc.AATags.NoAliasSideChannel, + CSNoAlias, nullptr, nullptr, Call, AAQI)) + return ModRefInfo::NoModRef; - if (noAliasByIntrinsic(CSNoAlias, nullptr, Loc.AATags.NoAlias, Loc.Ptr, Call)) - return ModRefInfo::NoModRef; + if (noAliasByIntrinsic(CSNoAlias, nullptr, Loc.AATags.NoAlias, + Loc.AATags.NoAliasSideChannel, Call, nullptr, AAQI)) + return ModRefInfo::NoModRef; + } return AAResultBase::getModRefInfo(Call, Loc, AAQI); } @@ -152,17 +137,18 @@ Call1->getMetadata(LLVMContext::MD_noalias); const MDNode *CS2NoAlias = Call2->getMetadata(LLVMContext::MD_noalias); - - if (!mayAliasInScopes(CS1Scopes, CS2NoAlias)) + if (!mayAliasInScopes(CS1Scopes, Call2->getMetadata(LLVMContext::MD_noalias))) return ModRefInfo::NoModRef; - if (!mayAliasInScopes(CS2Scopes, CS1NoAlias)) + if (!mayAliasInScopes(CS2Scopes, Call1->getMetadata(LLVMContext::MD_noalias))) return ModRefInfo::NoModRef; - if (noAliasByIntrinsic(CS1NoAlias, nullptr, CS2NoAlias, nullptr, Call1, Call2)) + if (noAliasByIntrinsic(CS1NoAlias, nullptr, CS2NoAlias, nullptr, Call1, Call2, + AAQI)) return ModRefInfo::NoModRef; - if (noAliasByIntrinsic(CS2NoAlias, nullptr, CS1NoAlias, nullptr, Call2, Call1)) + if (noAliasByIntrinsic(CS2NoAlias, nullptr, CS1NoAlias, nullptr, Call2, Call1, + AAQI)) return ModRefInfo::NoModRef; return AAResultBase::getModRefInfo(Call1, Call2, AAQI); @@ -283,18 +269,20 @@ // Our pointer is derived from P, with NoAliasCalls along the way. // Compatibility with any of them is fine. - auto NAI = - find_if(NoAliasCalls, - [&](Instruction *A) { - return !mayAliasInScopes( - dyn_cast( - cast(A->getOperand(1))-> - getMetadata()), ANoAlias) && - !mayAliasInScopes( - dyn_cast( - cast(A->getOperand(1))-> - getMetadata()), BNoAlias); - }); + auto NAI = find_if(NoAliasCalls, [&](Instruction *A) { + return !mayAliasInScopes( + dyn_cast( + cast( + A->getOperand(Intrinsic::SideNoAliasScopeArg)) + ->getMetadata()), + ANoAlias) && + !mayAliasInScopes( + dyn_cast( + cast( + A->getOperand(Intrinsic::SideNoAliasScopeArg)) + ->getMetadata()), + BNoAlias); + }); if (NAI != NoAliasCalls.end()) { CompatibleSet.push_back(*NAI); return true; @@ -337,12 +325,14 @@ return true; } -bool ScopedNoAliasAAResult::noAliasByIntrinsic(const MDNode *ANoAlias, - const Value *APtr, - const MDNode *BNoAlias, - const Value *BPtr, - const CallBase *CallA, - const CallBase *CallB) { +bool ScopedNoAliasAAResult::noAliasByIntrinsic( + const MDNode *ANoAlias, const Value *APtr, const MDNode *BNoAlias, + const Value *BPtr, const CallBase *CallA, const CallBase *CallB, + AAQueryInfo &AAQI) { + LLVM_DEBUG(llvm::dbgs() << ">ScopedNoAliasAAResult::noAliasByIntrinsic:{" + << (const void *)ANoAlias << "," << (const void *)APtr + << "},{" << (const void *)BNoAlias << "," + << (const void *)BPtr << "}\n"); if (!ANoAlias || !BNoAlias) return false; @@ -364,8 +354,8 @@ if (!Arg->getType()->isPointerTy()) continue; - if (!noAliasByIntrinsic(ANoAlias, Arg, BNoAlias, BPtr, - nullptr, CallB)) { + if (!noAliasByIntrinsic(ANoAlias, Arg, BNoAlias, BPtr, nullptr, CallB, + AAQI)) { LLVM_DEBUG(dbgs() << "SNA: CSA: noalias fail for arg: " << *Arg << "\n"); return false; } @@ -384,7 +374,8 @@ LLVM_DEBUG(dbgs() << "SNA: A: " << *APtr << "\n"); LLVM_DEBUG(dbgs() << "SNB: "; if (CallB) dbgs() << "CSB: " << *CallB; - else dbgs() << "B: " << *BPtr; dbgs() << "\n"); + else if (BPtr) dbgs() << "B: " << *BPtr; + else dbgs() << "B: nullptr"; dbgs() << "\n"); SmallPtrSet Visited; SmallVector CompatibleSet; @@ -424,6 +415,144 @@ LLVM_DEBUG(dbgs() << "\n"); #endif + // We need to check now if any compatible llvm.side.noalias call is + // potentially using the same 'P' object as one of the 'BNoAliasCalls'. + // If this is true for at least one entry, we must bail out and assume + // 'may_alias' + + { + MDNode *NoAliasUnknownScopeMD = + AInst->getParent()->getParent()->getMetadata("noalias"); + + for (Instruction *CA : CompatibleSet) { + LLVM_DEBUG(llvm::dbgs() << "- CA:" << *CA << "\n"); + assert(isa(CA) && + (cast(CA)->getIntrinsicID() == + llvm::Intrinsic::side_noalias)); + for (Instruction *CB : BNoAliasCalls) { + LLVM_DEBUG(llvm::dbgs() << "- CB:" << *CB << "\n"); + assert(isa(CB) && + (cast(CB)->getIntrinsicID() == + llvm::Intrinsic::side_noalias)); + + // With the llvm.side.noalias version, we have different parts that can + // represent a P: + // - the actual 'identifyP' address (or an offset vs an optimized away + // alloca) + // - the objectId (objectId's currently represent an offset to the + // original alloca of the object) + // - the scope (different scopes = different objects; with the exception + // of the 'unknown scope' an unknown scope can potentially be the same + // as a real variable scope. + // If any of these are different, the P will not alias => *P will also + // not alias + + // Let's start with the fast checks first; + + // Same call ? + if (CA == CB) { + LLVM_DEBUG(llvm::dbgs() << "SNA == SNB\n"); + return false; + } + + // - different objectId ? + { + // check ObjId first: if the obj id's (aka, offset in the object) are + // different, they represent different objects + auto ObjIdA = + cast( + CA->getOperand(Intrinsic::SideNoAliasIdentifyPObjIdArg)) + ->getZExtValue(); + auto ObjIdB = + cast( + CB->getOperand(Intrinsic::SideNoAliasIdentifyPObjIdArg)) + ->getZExtValue(); + if (ObjIdA != ObjIdB) { + LLVM_DEBUG(llvm::dbgs() << "SNA.ObjId != SNB.ObjId\n"); + continue; + } + } + + // Different Scope ? (except for unknown scope) + { + bool isDifferentPByScope = true; + auto *CASnaScope = CA->getOperand(Intrinsic::SideNoAliasScopeArg); + auto *CBSnaScope = CB->getOperand(Intrinsic::SideNoAliasScopeArg); + if (CASnaScope == CBSnaScope) { + // compatibility check below will resolve + isDifferentPByScope = false; + } else { + if (NoAliasUnknownScopeMD) { + if ((cast(CASnaScope)->getMetadata() == + NoAliasUnknownScopeMD) || + (cast(CBSnaScope)->getMetadata() == + NoAliasUnknownScopeMD)) { + isDifferentPByScope = false; + } + } + } + if (isDifferentPByScope) { + LLVM_DEBUG(llvm::dbgs() + << "SNA.Scope != SNB.Scope (and not 'unknown scope')\n"); + continue; + } + } + + // Different 'P' ? + { + Value *P_A = CA->getOperand(Intrinsic::SideNoAliasIdentifyPArg); + Value *P_B = CB->getOperand(Intrinsic::SideNoAliasIdentifyPArg); + + if (P_A == P_B) { + LLVM_DEBUG(dbgs() << " SNA.Scope == SNB.Scope, SNA.P == SNB.P\n"); + return false; + } + + Constant *CP_A = dyn_cast(P_A); + if (CP_A) { + Constant *CP_B = dyn_cast(P_B); + if (CP_B) { + CP_B = ConstantExpr::getBitCast(CP_B, CP_A->getType()); + Constant *Cmp = + ConstantExpr::getCompare(CmpInst::ICMP_NE, CP_A, CP_B, true); + if (Cmp && Cmp->isNullValue()) { + LLVM_DEBUG(dbgs() << " SNA.Scope == SNB.Scope, !(SNA.P != " + "SNB.P) as constant\n"); + return false; + } + } + } + // Check if P_A.addr and P_B.addr alias. If they don't, they describe + // different pointers. + LLVM_DEBUG(llvm::dbgs() + << " SNA.P=" << *P_A << ", SNB.P=" << *P_B << "\n"); + AAMDNodes P_A_Metadata; + AAMDNodes P_B_Metadata; + CA->getAAMetadata(P_A_Metadata); + CB->getAAMetadata(P_B_Metadata); + + // The noalias_sidechannel is not handled in the + // Instruction::getAAMetadata for intrinsics + P_A_Metadata.NoAliasSideChannel = + CA->getOperand(Intrinsic::SideNoAliasIdentifyPSideChannelArg); + P_B_Metadata.NoAliasSideChannel = + CB->getOperand(Intrinsic::SideNoAliasIdentifyPSideChannelArg); + + // Check with 1 unit + MemoryLocation ML_P_A(P_A, 1ull, P_A_Metadata); + MemoryLocation ML_P_B(P_B, 1ull, P_B_Metadata); + if (getBestAAResults().alias(ML_P_A, ML_P_B, AAQI) != + AliasResult::NoAlias) { + LLVM_DEBUG(llvm::dbgs() << " P ... may alias\n"); + return false; + } + LLVM_DEBUG(llvm::dbgs() << " P is NoAlias\n"); + continue; + } + } + } + } + // The noalias scope from the compatible intrinsics are really identified by // their scope argument, and we need to make sure that LocB.Ptr is not only // not derived from the calls currently in CompatibleSet, but also from any @@ -439,20 +568,21 @@ CompatibleSet.end()); SmallVector CompatibleSetMVs; for (auto &C : CompatibleSet) - CompatibleSetMVs.push_back(cast(C->getOperand(1))); + CompatibleSetMVs.push_back( + cast(C->getOperand(Intrinsic::SideNoAliasScopeArg))); for (auto &MV : CompatibleSetMVs) for (Use &U : MV->uses()) - if (auto *UI = dyn_cast(U.getUser())) + if (auto *UI = dyn_cast(U.getUser())) { + // Skip noalias declarations + if (auto *CB = dyn_cast(UI)) + if (CB->getIntrinsicID() == Intrinsic::noalias_decl) + continue; if (CompatibleSetMembers.insert(UI).second) { CompatibleSet.push_back(UI); LLVM_DEBUG(dbgs() << "SNA: Adding to compatible set based on MD use: " << *UI << "\n"); } - - if (std::find_first_of(CompatibleSet.begin(), CompatibleSet.end(), - BNoAliasCalls.begin(), BNoAliasCalls.end()) != - CompatibleSet.end()) - return false; + } LLVM_DEBUG(dbgs() << "SNA: B does not derive from the compatible set!\n"); @@ -481,8 +611,9 @@ // derived from the return value of the noalias intrinsic, and we cannot // conclude anything about the aliasing. for (auto &C : CompatibleSet) - if (PointerMayBeCapturedBefore(C, /* ReturnCaptures */false, - /* StoreCaptures */false, I, DT)) { + if (PointerMayBeCapturedBefore(C, /* ReturnCaptures */ false, + /* StoreCaptures */ false, I, DT, + /* IncludeI */ false, nullptr, 80)) { LLVM_DEBUG(dbgs() << "SNA: Pointer " << *C << " might be captured!\n"); return false; } @@ -548,4 +679,5 @@ void ScopedNoAliasAAWrapperPass::getAnalysisUsage(AnalysisUsage &AU) const { AU.setPreservesAll(); + AU.addUsedIfAvailable(); } Index: llvm/lib/Analysis/TypeBasedAliasAnalysis.cpp =================================================================== --- llvm/lib/Analysis/TypeBasedAliasAnalysis.cpp +++ llvm/lib/Analysis/TypeBasedAliasAnalysis.cpp @@ -112,6 +112,7 @@ #include "llvm/IR/Constants.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/Instruction.h" +#include "llvm/IR/Instructions.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Metadata.h" #include "llvm/Pass.h" @@ -519,6 +520,14 @@ return Ret; } +static Value *MergeSideChannel(Value *lhs, Value *rhs) { + // Similar to what we do for N.NoAlias: only identical side_channels can be + // merged + if (lhs == rhs) + return lhs; + return nullptr; +} + void Instruction::getAAMetadata(AAMDNodes &N, bool Merge) const { if (Merge) N.TBAA = @@ -537,6 +546,25 @@ MDNode::intersect(N.NoAlias, getMetadata(LLVMContext::MD_noalias)); else N.NoAlias = getMetadata(LLVMContext::MD_noalias); + if (const LoadInst *LI = dyn_cast(this)) { + if (LI->hasNoaliasSideChannelOperand()) { + if (Merge) { + N.NoAliasSideChannel = MergeSideChannel( + N.NoAliasSideChannel, LI->getNoaliasSideChannelOperand()); + } else { + N.NoAliasSideChannel = LI->getNoaliasSideChannelOperand(); + } + } + } else if (const StoreInst *SI = dyn_cast(this)) { + if (SI->hasNoaliasSideChannelOperand()) { + if (Merge) { + N.NoAliasSideChannel = MergeSideChannel( + N.NoAliasSideChannel, SI->getNoaliasSideChannelOperand()); + } else { + N.NoAliasSideChannel = SI->getNoaliasSideChannelOperand(); + } + } + } } static const MDNode *createAccessTag(const MDNode *AccessType) { Index: llvm/lib/Analysis/ValueTracking.cpp =================================================================== --- llvm/lib/Analysis/ValueTracking.cpp +++ llvm/lib/Analysis/ValueTracking.cpp @@ -513,7 +513,11 @@ case Intrinsic::invariant_end: case Intrinsic::lifetime_start: case Intrinsic::lifetime_end: + case Intrinsic::noalias_decl: case Intrinsic::noalias: + case Intrinsic::side_noalias: + case Intrinsic::noalias_arg_guard: + case Intrinsic::noalias_copy_guard: case Intrinsic::objectsize: case Intrinsic::ptr_annotation: case Intrinsic::var_annotation: @@ -3679,6 +3683,8 @@ const CallBase *Call, bool MustPreserveNullness) { return Call->getIntrinsicID() == Intrinsic::launder_invariant_group || Call->getIntrinsicID() == Intrinsic::strip_invariant_group || + Call->getIntrinsicID() == Intrinsic::noalias_arg_guard || + Call->getIntrinsicID() == Intrinsic::noalias_copy_guard || Call->getIntrinsicID() == Intrinsic::aarch64_irg || Call->getIntrinsicID() == Intrinsic::aarch64_tagp || (!MustPreserveNullness && @@ -3732,8 +3738,27 @@ return V; } else { if (auto *Call = dyn_cast(V)) { - if (NoAlias && Call->getIntrinsicID() == Intrinsic::noalias) - NoAlias->push_back(Call); + if (NoAlias) { + // We are gathering information for ScopedAANoAlias - + // Look through side.noalias intrinsic + if (Call->getIntrinsicID() == Intrinsic::side_noalias) { + NoAlias->push_back(Call); + V = Call->getArgOperand(0); + continue; + } + // Look trough noalias.arg.guard, and follow the sidechannel + if (Call->getIntrinsicID() == Intrinsic::noalias_arg_guard) { + V = Call->getArgOperand(1); + continue; + } + } else { + // We are not gathering information for SCopedAANoAlias - + // Look through noalias.arg.guard and follow the pointer path + if (Call->getIntrinsicID() == Intrinsic::noalias_arg_guard) { + V = Call->getArgOperand(0); + continue; + } + } // CaptureTracking can know about special capturing properties of some // intrinsics like launder.invariant.group, that can't be expressed with Index: llvm/lib/IR/Metadata.cpp =================================================================== --- llvm/lib/IR/Metadata.cpp +++ llvm/lib/IR/Metadata.cpp @@ -10,6 +10,7 @@ // //===----------------------------------------------------------------------===// +#include "llvm/IR/Metadata.h" #include "LLVMContextImpl.h" #include "MetadataImpl.h" #include "SymbolTableListTraitsImpl.h" @@ -37,8 +38,8 @@ #include "llvm/IR/GlobalObject.h" #include "llvm/IR/GlobalVariable.h" #include "llvm/IR/Instruction.h" +#include "llvm/IR/Instructions.h" #include "llvm/IR/LLVMContext.h" -#include "llvm/IR/Metadata.h" #include "llvm/IR/Module.h" #include "llvm/IR/TrackingMDRef.h" #include "llvm/IR/Type.h" @@ -1261,7 +1262,23 @@ void Instruction::setAAMetadata(const AAMDNodes &N) { setMetadata(LLVMContext::MD_tbaa, N.TBAA); setMetadata(LLVMContext::MD_alias_scope, N.Scope); - setMetadata(LLVMContext::MD_noalias, N.NoAlias); + if (!N.NoAliasSideChannel) + setMetadata(LLVMContext::MD_noalias, N.NoAlias); + // else postpone until setAAMetadataNoAliasSideChannel +} + +void Instruction::setAAMetadataNoAliasSideChannel(const AAMDNodes &N) { + // It is not correct to always propagate the noalias_sidechannel. + // 'setAAMetadata' must already have been called ! + if (N.NoAliasSideChannel) { + // postponed from setAAMetadata + setMetadata(LLVMContext::MD_noalias, N.NoAlias); + if (LoadInst *LI = dyn_cast(this)) { + LI->setNoaliasSideChannelOperand(N.NoAliasSideChannel); + } else if (StoreInst *SI = dyn_cast(this)) { + SI->setNoaliasSideChannelOperand(N.NoAliasSideChannel); + } + } } MDNode *Instruction::getMetadataImpl(unsigned KindID) const { Index: llvm/test/Analysis/ScopedNoAliasAA/basic-domains.ll =================================================================== --- llvm/test/Analysis/ScopedNoAliasAA/basic-domains.ll +++ llvm/test/Analysis/ScopedNoAliasAA/basic-domains.ll @@ -52,4 +52,3 @@ ; CHECK: NoAlias: store float %1, float* %arrayidx.i2, align 4, !noalias !6 <-> store float %0, float* %arrayidx.i, align 4, !noalias !6 ; CHECK: NoAlias: store float %2, float* %arrayidx.i3, align 4, !noalias !7 <-> store float %0, float* %arrayidx.i, align 4, !noalias !6 ; CHECK: NoAlias: store float %2, float* %arrayidx.i3, align 4, !noalias !7 <-> store float %1, float* %arrayidx.i2, align 4, !noalias !6 - Index: llvm/test/Analysis/ScopedNoAliasAA/basic2.ll =================================================================== --- llvm/test/Analysis/ScopedNoAliasAA/basic2.ll +++ llvm/test/Analysis/ScopedNoAliasAA/basic2.ll @@ -38,4 +38,3 @@ !3 = !{!3, !2, !"some other scope"} !4 = !{!1} !5 = !{!3} - Index: llvm/test/Analysis/ScopedNoAliasAA/noalias-calls.ll =================================================================== --- llvm/test/Analysis/ScopedNoAliasAA/noalias-calls.ll +++ llvm/test/Analysis/ScopedNoAliasAA/noalias-calls.ll @@ -12,40 +12,65 @@ define void @foo(i8* nocapture %a, i8* nocapture readonly %c, i8* nocapture %b) #2 { entry: %l.i = alloca i8, i32 512, align 1 - %0 = call i8* @llvm.noalias.p0i8(i8* %a, metadata !0) #0 - %1 = call i8* @llvm.noalias.p0i8(i8* %c, metadata !3) #0 - call void @llvm.memcpy.p0i8.p0i8.i64(i8* %0, i8* %b, i64 16, i1 false) #1, !noalias !5 - call void @llvm.memcpy.p0i8.p0i8.i64(i8* %b, i8* %1, i64 16, i1 false) #1, !noalias !5 - call void @llvm.memcpy.p0i8.p0i8.i64(i8* %0, i8* %1, i64 16, i1 false) #1, !noalias !5 + %side.a = call i8* @llvm.side.noalias.p0i8.p0i8.p0p0i8.p0p0i8.i32(i8* %a, i8* null, i8** null, i8** null, i32 0, metadata !0) #0 + %side.b = call i8* @llvm.side.noalias.p0i8.p0i8.p0p0i8.p0p0i8.i32(i8* %c, i8* null, i8** null, i8** null, i32 0, metadata !3) #0 + %a.guard = call i8* @llvm.noalias.arg.guard.p0i8.p0i8(i8* %a, i8* %side.a) + %b.guard = call i8* @llvm.noalias.arg.guard.p0i8.p0i8(i8* %b, i8* %side.b) + call void @llvm.memcpy.p0i8.p0i8.i64(i8* %a.guard, i8* %b, i64 16, i1 false) #1, !noalias !5 + call void @llvm.memcpy.p0i8.p0i8.i64(i8* %b, i8* %b.guard, i64 16, i1 false) #1, !noalias !5 + call void @llvm.memcpy.p0i8.p0i8.i64(i8* %a.guard, i8* %b.guard, i64 16, i1 false) #1, !noalias !5 call void @hey() #1, !noalias !5 - call void @llvm.memcpy.p0i8.p0i8.i64(i8* %l.i, i8* %1, i64 16, i1 false) #1, !noalias !5 + call void @llvm.memcpy.p0i8.p0i8.i64(i8* %l.i, i8* %b.guard, i64 16, i1 false) #1, !noalias !5 ret void } ; CHECK-LABEL: Function: foo: -; CHECK: Just Ref: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %0, i8* %b, i64 16, i1 false) #1, !noalias !5 <-> call void @llvm.memcpy.p0i8.p0i8.i64(i8* %b, i8* %1, i64 16, i1 false) #1, !noalias !5 -; CHECK: Just Mod: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %0, i8* %b, i64 16, i1 false) #1, !noalias !5 <-> call void @llvm.memcpy.p0i8.p0i8.i64(i8* %0, i8* %1, i64 16, i1 false) #1, !noalias !5 -; CHECK: Just Ref: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %0, i8* %b, i64 16, i1 false) #1, !noalias !5 <-> call void @hey() #1, !noalias !5 -; CHECK: NoModRef: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %0, i8* %b, i64 16, i1 false) #1, !noalias !5 <-> call void @llvm.memcpy.p0i8.p0i8.i64(i8* %l.i, i8* %1, i64 16, i1 false) #1, !noalias !5 -; CHECK: Just Mod: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %b, i8* %1, i64 16, i1 false) #1, !noalias !5 <-> call void @llvm.memcpy.p0i8.p0i8.i64(i8* %0, i8* %b, i64 16, i1 false) #1, !noalias !5 -; CHECK: NoModRef: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %b, i8* %1, i64 16, i1 false) #1, !noalias !5 <-> call void @llvm.memcpy.p0i8.p0i8.i64(i8* %0, i8* %1, i64 16, i1 false) #1, !noalias !5 -; CHECK: Just Mod: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %b, i8* %1, i64 16, i1 false) #1, !noalias !5 <-> call void @hey() #1, !noalias !5 -; CHECK: NoModRef: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %b, i8* %1, i64 16, i1 false) #1, !noalias !5 <-> call void @llvm.memcpy.p0i8.p0i8.i64(i8* %l.i, i8* %1, i64 16, i1 false) #1, !noalias !5 -; CHECK: Just Mod: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %0, i8* %1, i64 16, i1 false) #1, !noalias !5 <-> call void @llvm.memcpy.p0i8.p0i8.i64(i8* %0, i8* %b, i64 16, i1 false) #1, !noalias !5 -; CHECK: NoModRef: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %0, i8* %1, i64 16, i1 false) #1, !noalias !5 <-> call void @llvm.memcpy.p0i8.p0i8.i64(i8* %b, i8* %1, i64 16, i1 false) #1, !noalias !5 -; CHECK: NoModRef: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %0, i8* %1, i64 16, i1 false) #1, !noalias !5 <-> call void @hey() #1, !noalias !5 -; CHECK: NoModRef: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %0, i8* %1, i64 16, i1 false) #1, !noalias !5 <-> call void @llvm.memcpy.p0i8.p0i8.i64(i8* %l.i, i8* %1, i64 16, i1 false) #1, !noalias !5 -; CHECK: Just Mod: call void @hey() #1, !noalias !5 <-> call void @llvm.memcpy.p0i8.p0i8.i64(i8* %0, i8* %b, i64 16, i1 false) #1, !noalias !5 -; CHECK: Both ModRef: call void @hey() #1, !noalias !5 <-> call void @llvm.memcpy.p0i8.p0i8.i64(i8* %b, i8* %1, i64 16, i1 false) #1, !noalias !5 -; CHECK: NoModRef: call void @hey() #1, !noalias !5 <-> call void @llvm.memcpy.p0i8.p0i8.i64(i8* %0, i8* %1, i64 16, i1 false) #1, !noalias !5 -; CHECK: NoModRef: call void @hey() #1, !noalias !5 <-> call void @llvm.memcpy.p0i8.p0i8.i64(i8* %l.i, i8* %1, i64 16, i1 false) #1, !noalias !5 -; CHECK: NoModRef: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %l.i, i8* %1, i64 16, i1 false) #1, !noalias !5 <-> call void @llvm.memcpy.p0i8.p0i8.i64(i8* %0, i8* %b, i64 16, i1 false) #1, !noalias !5 -; CHECK: NoModRef: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %l.i, i8* %1, i64 16, i1 false) #1, !noalias !5 <-> call void @llvm.memcpy.p0i8.p0i8.i64(i8* %b, i8* %1, i64 16, i1 false) #1, !noalias !5 -; CHECK: NoModRef: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %l.i, i8* %1, i64 16, i1 false) #1, !noalias !5 <-> call void @llvm.memcpy.p0i8.p0i8.i64(i8* %0, i8* %1, i64 16, i1 false) #1, !noalias !5 -; CHECK: NoModRef: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %l.i, i8* %1, i64 16, i1 false) #1, !noalias !5 <-> call void @hey() #1, !noalias !5 +;@ JDO_FIXME_NOW: not sure where to look for this, but there is a discripancy between the wanted vs observed +; WANTED: Just Ref: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %0, i8* %b, i64 16, i1 false) #1, !noalias !5 <-> call void @llvm.memcpy.p0i8.p0i8.i64(i8* %b, i8* %1, i64 16, i1 false) #1, !noalias !5 +; WANTED: Just Mod: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %0, i8* %b, i64 16, i1 false) #1, !noalias !5 <-> call void @llvm.memcpy.p0i8.p0i8.i64(i8* %0, i8* %1, i64 16, i1 false) #1, !noalias !5 +; WANTED: Just Ref: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %0, i8* %b, i64 16, i1 false) #1, !noalias !5 <-> call void @hey() #1, !noalias !5 +; WANTED: NoModRef: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %0, i8* %b, i64 16, i1 false) #1, !noalias !5 <-> call void @llvm.memcpy.p0i8.p0i8.i64(i8* %l.i, i8* %1, i64 16, i1 false) #1, !noalias !5 +; WANTED: Just Mod: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %b, i8* %1, i64 16, i1 false) #1, !noalias !5 <-> call void @llvm.memcpy.p0i8.p0i8.i64(i8* %0, i8* %b, i64 16, i1 false) #1, !noalias !5 +; WANTED: NoModRef: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %b, i8* %1, i64 16, i1 false) #1, !noalias !5 <-> call void @llvm.memcpy.p0i8.p0i8.i64(i8* %0, i8* %1, i64 16, i1 false) #1, !noalias !5 +; WANTED: Just Mod: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %b, i8* %1, i64 16, i1 false) #1, !noalias !5 <-> call void @hey() #1, !noalias !5 +; WANTED: NoModRef: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %b, i8* %1, i64 16, i1 false) #1, !noalias !5 <-> call void @llvm.memcpy.p0i8.p0i8.i64(i8* %l.i, i8* %1, i64 16, i1 false) #1, !noalias !5 +; WANTED: Just Mod: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %0, i8* %1, i64 16, i1 false) #1, !noalias !5 <-> call void @llvm.memcpy.p0i8.p0i8.i64(i8* %0, i8* %b, i64 16, i1 false) #1, !noalias !5 +; WANTED: NoModRef: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %0, i8* %1, i64 16, i1 false) #1, !noalias !5 <-> call void @llvm.memcpy.p0i8.p0i8.i64(i8* %b, i8* %1, i64 16, i1 false) #1, !noalias !5 +; WANTED: NoModRef: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %0, i8* %1, i64 16, i1 false) #1, !noalias !5 <-> call void @hey() #1, !noalias !5 +; WANTED: NoModRef: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %0, i8* %1, i64 16, i1 false) #1, !noalias !5 <-> call void @llvm.memcpy.p0i8.p0i8.i64(i8* %l.i, i8* %1, i64 16, i1 false) #1, !noalias !5 +; WANTED: Just Mod: call void @hey() #1, !noalias !5 <-> call void @llvm.memcpy.p0i8.p0i8.i64(i8* %0, i8* %b, i64 16, i1 false) #1, !noalias !5 +; WANTED: Both ModRef: call void @hey() #1, !noalias !5 <-> call void @llvm.memcpy.p0i8.p0i8.i64(i8* %b, i8* %1, i64 16, i1 false) #1, !noalias !5 +; WANTED: NoModRef: call void @hey() #1, !noalias !5 <-> call void @llvm.memcpy.p0i8.p0i8.i64(i8* %0, i8* %1, i64 16, i1 false) #1, !noalias !5 +; WANTED: NoModRef: call void @hey() #1, !noalias !5 <-> call void @llvm.memcpy.p0i8.p0i8.i64(i8* %l.i, i8* %1, i64 16, i1 false) #1, !noalias !5 +; WANTED: NoModRef: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %l.i, i8* %1, i64 16, i1 false) #1, !noalias !5 <-> call void @llvm.memcpy.p0i8.p0i8.i64(i8* %0, i8* %b, i64 16, i1 false) #1, !noalias !5 +; WANTED: NoModRef: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %l.i, i8* %1, i64 16, i1 false) #1, !noalias !5 <-> call void @llvm.memcpy.p0i8.p0i8.i64(i8* %b, i8* %1, i64 16, i1 false) #1, !noalias !5 +; WANTED: NoModRef: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %l.i, i8* %1, i64 16, i1 false) #1, !noalias !5 <-> call void @llvm.memcpy.p0i8.p0i8.i64(i8* %0, i8* %1, i64 16, i1 false) #1, !noalias !5 +; WANTED: NoModRef: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %l.i, i8* %1, i64 16, i1 false) #1, !noalias !5 <-> call void @hey() #1, !noalias !5 -; Function Attrs: nounwind -declare i8* @llvm.noalias.p0i8(i8*, metadata) #0 +; NOTE: OBSERVED: +; CHECK: Just Ref: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %a.guard, i8* %b, i64 16, i1 false) #1, !noalias !5 <-> call void @llvm.memcpy.p0i8.p0i8.i64(i8* %b, i8* %b.guard, i64 16, i1 false) #1, !noalias !5 +; CHECK: Just Mod: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %a.guard, i8* %b, i64 16, i1 false) #1, !noalias !5 <-> call void @llvm.memcpy.p0i8.p0i8.i64(i8* %a.guard, i8* %b.guard, i64 16, i1 false) #1, !noalias !5 +; CHECK: Both ModRef: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %a.guard, i8* %b, i64 16, i1 false) #1, !noalias !5 <-> call void @hey() #1, !noalias !5 +; CHECK: NoModRef: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %a.guard, i8* %b, i64 16, i1 false) #1, !noalias !5 <-> call void @llvm.memcpy.p0i8.p0i8.i64(i8* %l.i, i8* %b.guard, i64 16, i1 false) #1, !noalias !5 +; CHECK: Both ModRef: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %b, i8* %b.guard, i64 16, i1 false) #1, !noalias !5 <-> call void @llvm.memcpy.p0i8.p0i8.i64(i8* %a.guard, i8* %b, i64 16, i1 false) #1, !noalias !5 +; CHECK: Both ModRef: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %b, i8* %b.guard, i64 16, i1 false) #1, !noalias !5 <-> call void @llvm.memcpy.p0i8.p0i8.i64(i8* %a.guard, i8* %b.guard, i64 16, i1 false) #1, !noalias !5 +; CHECK: Both ModRef: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %b, i8* %b.guard, i64 16, i1 false) #1, !noalias !5 <-> call void @hey() #1, !noalias !5 +; CHECK: NoModRef: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %b, i8* %b.guard, i64 16, i1 false) #1, !noalias !5 <-> call void @llvm.memcpy.p0i8.p0i8.i64(i8* %l.i, i8* %b.guard, i64 16, i1 false) #1, !noalias !5 +; CHECK: Just Mod: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %a.guard, i8* %b.guard, i64 16, i1 false) #1, !noalias !5 <-> call void @llvm.memcpy.p0i8.p0i8.i64(i8* %a.guard, i8* %b, i64 16, i1 false) #1, !noalias !5 +; CHECK: Just Ref: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %a.guard, i8* %b.guard, i64 16, i1 false) #1, !noalias !5 <-> call void @llvm.memcpy.p0i8.p0i8.i64(i8* %b, i8* %b.guard, i64 16, i1 false) #1, !noalias !5 +; CHECK: Both ModRef: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %a.guard, i8* %b.guard, i64 16, i1 false) #1, !noalias !5 <-> call void @hey() #1, !noalias !5 +; CHECK: NoModRef: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %a.guard, i8* %b.guard, i64 16, i1 false) #1, !noalias !5 <-> call void @llvm.memcpy.p0i8.p0i8.i64(i8* %l.i, i8* %b.guard, i64 16, i1 false) #1, !noalias !5 +; CHECK: Both ModRef: call void @hey() #1, !noalias !5 <-> call void @llvm.memcpy.p0i8.p0i8.i64(i8* %a.guard, i8* %b, i64 16, i1 false) #1, !noalias !5 +; CHECK: Both ModRef: call void @hey() #1, !noalias !5 <-> call void @llvm.memcpy.p0i8.p0i8.i64(i8* %b, i8* %b.guard, i64 16, i1 false) #1, !noalias !5 +; CHECK: Both ModRef: call void @hey() #1, !noalias !5 <-> call void @llvm.memcpy.p0i8.p0i8.i64(i8* %a.guard, i8* %b.guard, i64 16, i1 false) #1, !noalias !5 +; CHECK: Just Mod: call void @hey() #1, !noalias !5 <-> call void @llvm.memcpy.p0i8.p0i8.i64(i8* %l.i, i8* %b.guard, i64 16, i1 false) #1, !noalias !5 +; CHECK: Just Ref: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %l.i, i8* %b.guard, i64 16, i1 false) #1, !noalias !5 <-> call void @llvm.memcpy.p0i8.p0i8.i64(i8* %a.guard, i8* %b, i64 16, i1 false) #1, !noalias !5 +; CHECK: Just Ref: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %l.i, i8* %b.guard, i64 16, i1 false) #1, !noalias !5 <-> call void @llvm.memcpy.p0i8.p0i8.i64(i8* %b, i8* %b.guard, i64 16, i1 false) #1, !noalias !5 +; CHECK: Just Ref: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %l.i, i8* %b.guard, i64 16, i1 false) #1, !noalias !5 <-> call void @llvm.memcpy.p0i8.p0i8.i64(i8* %a.guard, i8* %b.guard, i64 16, i1 false) #1, !noalias !5 +; CHECK: Just Ref: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %l.i, i8* %b.guard, i64 16, i1 false) #1, !noalias !5 <-> call void @hey() #1, !noalias !5 + +declare i8* @llvm.side.noalias.p0i8.p0i8.p0p0i8.p0p0i8.i32(i8*, i8*, i8**, i8**, i32, metadata) nounwind readnone speculatable +declare i8* @llvm.noalias.arg.guard.p0i8.p0i8(i8*, i8*) nounwind readnone attributes #0 = { argmemonly nounwind } attributes #1 = { nounwind } Index: llvm/test/Analysis/ScopedNoAliasAA/noalias-dup-scope.ll =================================================================== --- llvm/test/Analysis/ScopedNoAliasAA/noalias-dup-scope.ll +++ llvm/test/Analysis/ScopedNoAliasAA/noalias-dup-scope.ll @@ -13,12 +13,16 @@ define i32* @foo() #0 { entry: %0 = load i32*, i32** @a, align 8, !tbaa !1, !noalias !5 - %1 = tail call i32* @llvm.noalias.p0i32(i32* %0, metadata !5) #0 + %1 = call i32* @llvm.side.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32* %0, i8* null, i32** @a, i32** null, i32 0, metadata !5) #0 + %2 = tail call i32* @llvm.noalias.arg.guard.p0i32.p0i32(i32* %0, i32* %1) #0 ret i32* %1 } ; Function Attrs: nounwind -declare i32* @llvm.noalias.p0i32(i32*, metadata) #0 +declare i32* @llvm.side.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32*, i8*, i32**, i32**, i32, metadata) #0 + +; Function Attrs: nounwind +declare i32* @llvm.noalias.arg.guard.p0i32.p0i32(i32*, i32*) #0 ; Function Attrs: nounwind define i32* @foo1(i32 signext %b) #0 { @@ -27,105 +31,111 @@ br i1 %tobool, label %if.else, label %if.then if.then: ; preds = %entry - %0 = load i32*, i32** @a, align 8, !tbaa !1, !noalias !8 - %1 = tail call i32* @llvm.noalias.p0i32(i32* %0, metadata !12) #0 - %2 = load i32, i32* %1, align 4, !tbaa !13, !noalias !8 - %3 = load i32, i32* @r, align 4, !tbaa !13, !noalias !8 + %0 = load i32*, i32** @a, noalias_sidechannel i32** null, align 8, !tbaa !1, !noalias !8 + %1 = tail call i32* @llvm.side.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32* %0, i8* null, i32** @a, i32** null, i32 0, metadata !12) #0 + %2 = load i32, i32* %0, noalias_sidechannel i32* %1, align 4, !tbaa !13, !noalias !8 + %3 = load i32, i32* @r, noalias_sidechannel i32* null, align 4, !tbaa !13, !noalias !8 %add = add nsw i32 %3, %2 - store i32 %add, i32* @r, align 4, !tbaa !13, !noalias !8 - tail call void @ex1(i32* %1) #0, !noalias !8 - %incdec.ptr = getelementptr inbounds i32, i32* %1, i64 1 - %4 = tail call i32* @llvm.noalias.p0i32(i32* %incdec.ptr, metadata !12) #0 - %5 = load i32, i32* @r, align 4, !tbaa !13, !noalias !8 - store i32 %5, i32* %4, align 4, !tbaa !13, !noalias !8 - tail call void @ex1(i32* %4) #0, !noalias !8 + store i32 %add, i32* @r, noalias_sidechannel i32* null, align 4, !tbaa !13, !noalias !8 + %guard.1 = tail call i32* @llvm.noalias.arg.guard.p0i32.p0i32(i32* %0, i32* %1) #0 + tail call void @ex1(i32* %guard.1) #0, !noalias !8 + %incdec.ptr = getelementptr inbounds i32, i32* %0, i64 1 + %4 = tail call i32* @llvm.side.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32* %0, i8* null, i32** @a, i32** null, i32 0, metadata !12) #0 + %5 = load i32, i32* @r, noalias_sidechannel i32* null, align 4, !tbaa !13, !noalias !8 + store i32 %5, i32* %incdec.ptr, noalias_sidechannel i32* %4, align 4, !tbaa !13, !noalias !8 + %guard.5 = tail call i32* @llvm.noalias.arg.guard.p0i32.p0i32(i32* %incdec.ptr, i32* %4) #0 + tail call void @ex1(i32* %guard.5) #0, !noalias !8 %idx.ext = sext i32 %b to i64 - %add.ptr = getelementptr inbounds i32, i32* %4, i64 %idx.ext - %6 = tail call i32* @llvm.noalias.p0i32(i32* %add.ptr, metadata !12) #0 - %7 = load i32, i32* @r, align 4, !tbaa !13, !noalias !8 - store i32 %7, i32* %6, align 4, !tbaa !13, !noalias !8 - tail call void @ex1(i32* %6) #0, !noalias !8 - %8 = load i32*, i32** @a2, align 8, !tbaa !1, !noalias !8 - %9 = tail call i32* @llvm.noalias.p0i32(i32* %8, metadata !15) #0 - %10 = load i32, i32* @r, align 4, !tbaa !13, !noalias !8 - store i32 %10, i32* %9, align 4, !tbaa !13, !noalias !8 - tail call void @ex1(i32* %9) #0, !noalias !8 + %add.ptr = getelementptr inbounds i32, i32* %incdec.ptr, i64 %idx.ext + %6 = tail call i32* @llvm.side.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32* %0, i8* null, i32** @a, i32** null, i32 0, metadata !12) #0 + %7 = load i32, i32* @r, noalias_sidechannel i32* null, align 4, !tbaa !13, !noalias !8 + store i32 %7, i32* %add.ptr, noalias_sidechannel i32* %6, align 4, !tbaa !13, !noalias !8 + %guard.6 = tail call i32* @llvm.noalias.arg.guard.p0i32.p0i32(i32* %add.ptr, i32* %6) #0 + tail call void @ex1(i32* %guard.6) #0, !noalias !8 + %8 = load i32*, i32** @a2, noalias_sidechannel i32** null, align 8, !tbaa !1, !noalias !8 + %9 = tail call i32* @llvm.side.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32* %8, i8* null, i32** @a2, i32** null, i32 0, metadata !15) #0 + %10 = load i32, i32* @r, noalias_sidechannel i32* null, align 4, !tbaa !13, !noalias !8 + store i32 %10, i32* %8, noalias_sidechannel i32* %9, align 4, !tbaa !13, !noalias !8 + %guard.9 = tail call i32* @llvm.noalias.arg.guard.p0i32.p0i32(i32* %8, i32* %9) #0 + tail call void @ex1(i32* %guard.9) #0, !noalias !8 br label %if.end if.else: ; preds = %entry - %11 = load i32*, i32** @a2, align 8, !tbaa !1, !noalias !12 - %12 = tail call i32* @llvm.noalias.p0i32(i32* %11, metadata !12) #0 - %13 = load i32, i32* %12, align 4, !tbaa !13, !noalias !12 - %14 = load i32, i32* @r, align 4, !tbaa !13, !noalias !12 + %11 = load i32*, i32** @a2, noalias_sidechannel i32** null, align 8, !tbaa !1, !noalias !12 + %12 = tail call i32* @llvm.side.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32* %11, i8* null, i32** @a2, i32** null, i32 0, metadata !12) #0 + %13 = load i32, i32* %11, noalias_sidechannel i32* %12, align 4, !tbaa !13, !noalias !12 + %14 = load i32, i32* @r, noalias_sidechannel i32* null, align 4, !tbaa !13, !noalias !12 %add1 = add nsw i32 %14, %13 - store i32 %add1, i32* @r, align 4, !tbaa !13, !noalias !12 + store i32 %add1, i32* @r, noalias_sidechannel i32* null, align 4, !tbaa !13, !noalias !12 br label %if.end if.end: ; preds = %if.else, %if.then - %x.0 = phi i32* [ %6, %if.then ], [ %12, %if.else ] - ret i32* %x.0 + %x.0 = phi i32* [ %0, %if.then ], [ %11, %if.else ] + %side.x.0 = phi i32* [ %6, %if.then ], [ %12, %if.else ] + %x.0.guard = tail call i32* @llvm.noalias.arg.guard.p0i32.p0i32(i32* %x.0, i32* %side.x.0) #0 + ret i32* %x.0.guard } -; WITHDT: NoAlias: %0 = load i32*, i32** @a, align 8, !tbaa !1, !noalias !5 <-> store i32 %add, i32* @r, align 4, !tbaa !10, !noalias !5 -; WITHDT: NoAlias: %0 = load i32*, i32** @a, align 8, !tbaa !1, !noalias !5 <-> store i32 %5, i32* %4, align 4, !tbaa !10, !noalias !5 -; WITHDT: NoAlias: %0 = load i32*, i32** @a, align 8, !tbaa !1, !noalias !5 <-> store i32 %7, i32* %6, align 4, !tbaa !10, !noalias !5 -; WITHDT: NoAlias: %0 = load i32*, i32** @a, align 8, !tbaa !1, !noalias !5 <-> store i32 %10, i32* %9, align 4, !tbaa !10, !noalias !5 -; WITHDT: NoAlias: %0 = load i32*, i32** @a, align 8, !tbaa !1, !noalias !5 <-> store i32 %add1, i32* @r, align 4, !tbaa !10, !noalias !9 -; WITHDT: NoAlias: %2 = load i32, i32* %1, align 4, !tbaa !10, !noalias !5 <-> store i32 %add, i32* @r, align 4, !tbaa !10, !noalias !5 -; WITHDT: NoAlias: %2 = load i32, i32* %1, align 4, !tbaa !10, !noalias !5 <-> store i32 %5, i32* %4, align 4, !tbaa !10, !noalias !5 -; WITHDT: NoAlias: %2 = load i32, i32* %1, align 4, !tbaa !10, !noalias !5 <-> store i32 %7, i32* %6, align 4, !tbaa !10, !noalias !5 -; WITHDT: NoAlias: %2 = load i32, i32* %1, align 4, !tbaa !10, !noalias !5 <-> store i32 %10, i32* %9, align 4, !tbaa !10, !noalias !5 -; WITHDT: NoAlias: %2 = load i32, i32* %1, align 4, !tbaa !10, !noalias !5 <-> store i32 %add1, i32* @r, align 4, !tbaa !10, !noalias !9 -; WITHDT: MustAlias: %3 = load i32, i32* @r, align 4, !tbaa !10, !noalias !5 <-> store i32 %add, i32* @r, align 4, !tbaa !10, !noalias !5 -; WITHDT: NoAlias: %3 = load i32, i32* @r, align 4, !tbaa !10, !noalias !5 <-> store i32 %5, i32* %4, align 4, !tbaa !10, !noalias !5 -; WITHDT: NoAlias: %3 = load i32, i32* @r, align 4, !tbaa !10, !noalias !5 <-> store i32 %7, i32* %6, align 4, !tbaa !10, !noalias !5 -; WITHDT: NoAlias: %3 = load i32, i32* @r, align 4, !tbaa !10, !noalias !5 <-> store i32 %10, i32* %9, align 4, !tbaa !10, !noalias !5 -; WITHDT: MustAlias: %3 = load i32, i32* @r, align 4, !tbaa !10, !noalias !5 <-> store i32 %add1, i32* @r, align 4, !tbaa !10, !noalias !9 -; WITHDT: MustAlias: %5 = load i32, i32* @r, align 4, !tbaa !10, !noalias !5 <-> store i32 %add, i32* @r, align 4, !tbaa !10, !noalias !5 -; WITHDT: NoAlias: %5 = load i32, i32* @r, align 4, !tbaa !10, !noalias !5 <-> store i32 %5, i32* %4, align 4, !tbaa !10, !noalias !5 -; WITHDT: NoAlias: %5 = load i32, i32* @r, align 4, !tbaa !10, !noalias !5 <-> store i32 %7, i32* %6, align 4, !tbaa !10, !noalias !5 -; WITHDT: NoAlias: %5 = load i32, i32* @r, align 4, !tbaa !10, !noalias !5 <-> store i32 %10, i32* %9, align 4, !tbaa !10, !noalias !5 -; WITHDT: MustAlias: %5 = load i32, i32* @r, align 4, !tbaa !10, !noalias !5 <-> store i32 %add1, i32* @r, align 4, !tbaa !10, !noalias !9 -; WITHDT: MustAlias: %7 = load i32, i32* @r, align 4, !tbaa !10, !noalias !5 <-> store i32 %add, i32* @r, align 4, !tbaa !10, !noalias !5 -; WITHDT: NoAlias: %7 = load i32, i32* @r, align 4, !tbaa !10, !noalias !5 <-> store i32 %5, i32* %4, align 4, !tbaa !10, !noalias !5 -; WITHDT: NoAlias: %7 = load i32, i32* @r, align 4, !tbaa !10, !noalias !5 <-> store i32 %7, i32* %6, align 4, !tbaa !10, !noalias !5 -; WITHDT: NoAlias: %7 = load i32, i32* @r, align 4, !tbaa !10, !noalias !5 <-> store i32 %10, i32* %9, align 4, !tbaa !10, !noalias !5 -; WITHDT: MustAlias: %7 = load i32, i32* @r, align 4, !tbaa !10, !noalias !5 <-> store i32 %add1, i32* @r, align 4, !tbaa !10, !noalias !9 -; WITHDT: NoAlias: %8 = load i32*, i32** @a2, align 8, !tbaa !1, !noalias !5 <-> store i32 %add, i32* @r, align 4, !tbaa !10, !noalias !5 -; WITHDT: NoAlias: %8 = load i32*, i32** @a2, align 8, !tbaa !1, !noalias !5 <-> store i32 %5, i32* %4, align 4, !tbaa !10, !noalias !5 -; WITHDT: NoAlias: %8 = load i32*, i32** @a2, align 8, !tbaa !1, !noalias !5 <-> store i32 %7, i32* %6, align 4, !tbaa !10, !noalias !5 -; WITHDT: NoAlias: %8 = load i32*, i32** @a2, align 8, !tbaa !1, !noalias !5 <-> store i32 %10, i32* %9, align 4, !tbaa !10, !noalias !5 -; WITHDT: NoAlias: %8 = load i32*, i32** @a2, align 8, !tbaa !1, !noalias !5 <-> store i32 %add1, i32* @r, align 4, !tbaa !10, !noalias !9 -; WITHDT: MustAlias: %10 = load i32, i32* @r, align 4, !tbaa !10, !noalias !5 <-> store i32 %add, i32* @r, align 4, !tbaa !10, !noalias !5 -; WITHDT: NoAlias: %10 = load i32, i32* @r, align 4, !tbaa !10, !noalias !5 <-> store i32 %5, i32* %4, align 4, !tbaa !10, !noalias !5 -; WITHDT: NoAlias: %10 = load i32, i32* @r, align 4, !tbaa !10, !noalias !5 <-> store i32 %7, i32* %6, align 4, !tbaa !10, !noalias !5 -; WITHDT: NoAlias: %10 = load i32, i32* @r, align 4, !tbaa !10, !noalias !5 <-> store i32 %10, i32* %9, align 4, !tbaa !10, !noalias !5 -; WITHDT: MustAlias: %10 = load i32, i32* @r, align 4, !tbaa !10, !noalias !5 <-> store i32 %add1, i32* @r, align 4, !tbaa !10, !noalias !9 -; WITHDT: NoAlias: %11 = load i32*, i32** @a2, align 8, !tbaa !1, !noalias !9 <-> store i32 %add, i32* @r, align 4, !tbaa !10, !noalias !5 -; WITHDT: NoAlias: %11 = load i32*, i32** @a2, align 8, !tbaa !1, !noalias !9 <-> store i32 %5, i32* %4, align 4, !tbaa !10, !noalias !5 -; WITHDT: NoAlias: %11 = load i32*, i32** @a2, align 8, !tbaa !1, !noalias !9 <-> store i32 %7, i32* %6, align 4, !tbaa !10, !noalias !5 -; WITHDT: MayAlias: %11 = load i32*, i32** @a2, align 8, !tbaa !1, !noalias !9 <-> store i32 %10, i32* %9, align 4, !tbaa !10, !noalias !5 -; WITHDT: NoAlias: %11 = load i32*, i32** @a2, align 8, !tbaa !1, !noalias !9 <-> store i32 %add1, i32* @r, align 4, !tbaa !10, !noalias !9 -; WITHDT: NoAlias: %13 = load i32, i32* %12, align 4, !tbaa !10, !noalias !9 <-> store i32 %add, i32* @r, align 4, !tbaa !10, !noalias !5 -; WITHDT: MayAlias: %13 = load i32, i32* %12, align 4, !tbaa !10, !noalias !9 <-> store i32 %5, i32* %4, align 4, !tbaa !10, !noalias !5 -; WITHDT: MayAlias: %13 = load i32, i32* %12, align 4, !tbaa !10, !noalias !9 <-> store i32 %7, i32* %6, align 4, !tbaa !10, !noalias !5 -; WITHDT: MayAlias: %13 = load i32, i32* %12, align 4, !tbaa !10, !noalias !9 <-> store i32 %10, i32* %9, align 4, !tbaa !10, !noalias !5 -; WITHDT: NoAlias: %13 = load i32, i32* %12, align 4, !tbaa !10, !noalias !9 <-> store i32 %add1, i32* @r, align 4, !tbaa !10, !noalias !9 -; WITHDT: MustAlias: %14 = load i32, i32* @r, align 4, !tbaa !10, !noalias !9 <-> store i32 %add, i32* @r, align 4, !tbaa !10, !noalias !5 -; WITHDT: NoAlias: %14 = load i32, i32* @r, align 4, !tbaa !10, !noalias !9 <-> store i32 %5, i32* %4, align 4, !tbaa !10, !noalias !5 -; WITHDT: NoAlias: %14 = load i32, i32* @r, align 4, !tbaa !10, !noalias !9 <-> store i32 %7, i32* %6, align 4, !tbaa !10, !noalias !5 -; WITHDT: MayAlias: %14 = load i32, i32* @r, align 4, !tbaa !10, !noalias !9 <-> store i32 %10, i32* %9, align 4, !tbaa !10, !noalias !5 -; WITHDT: MustAlias: %14 = load i32, i32* @r, align 4, !tbaa !10, !noalias !9 <-> store i32 %add1, i32* @r, align 4, !tbaa !10, !noalias !9 -; WITHDT: NoAlias: store i32 %5, i32* %4, align 4, !tbaa !10, !noalias !5 <-> store i32 %add, i32* @r, align 4, !tbaa !10, !noalias !5 -; WITHDT: NoAlias: store i32 %7, i32* %6, align 4, !tbaa !10, !noalias !5 <-> store i32 %add, i32* @r, align 4, !tbaa !10, !noalias !5 -; WITHDT: MayAlias: store i32 %7, i32* %6, align 4, !tbaa !10, !noalias !5 <-> store i32 %5, i32* %4, align 4, !tbaa !10, !noalias !5 -; WITHDT: NoAlias: store i32 %10, i32* %9, align 4, !tbaa !10, !noalias !5 <-> store i32 %add, i32* @r, align 4, !tbaa !10, !noalias !5 -; WITHDT: NoAlias: store i32 %10, i32* %9, align 4, !tbaa !10, !noalias !5 <-> store i32 %5, i32* %4, align 4, !tbaa !10, !noalias !5 -; WITHDT: NoAlias: store i32 %10, i32* %9, align 4, !tbaa !10, !noalias !5 <-> store i32 %7, i32* %6, align 4, !tbaa !10, !noalias !5 -; WITHDT: MustAlias: store i32 %add1, i32* @r, align 4, !tbaa !10, !noalias !9 <-> store i32 %add, i32* @r, align 4, !tbaa !10, !noalias !5 -; WITHDT: NoAlias: store i32 %add1, i32* @r, align 4, !tbaa !10, !noalias !9 <-> store i32 %5, i32* %4, align 4, !tbaa !10, !noalias !5 -; WITHDT: NoAlias: store i32 %add1, i32* @r, align 4, !tbaa !10, !noalias !9 <-> store i32 %7, i32* %6, align 4, !tbaa !10, !noalias !5 -; WITHDT: MayAlias: store i32 %add1, i32* @r, align 4, !tbaa !10, !noalias !9 <-> store i32 %10, i32* %9, align 4, !tbaa !10, !noalias !5 +; WITHDT: NoAlias: %0 = load i32*, i32** @a, noalias_sidechannel i32** null, align 8, !tbaa !1, !noalias !5 <-> store i32 %add, i32* @r, noalias_sidechannel i32* null, align 4, !tbaa !10, !noalias !5 +; WITHDT: NoAlias: %0 = load i32*, i32** @a, noalias_sidechannel i32** null, align 8, !tbaa !1, !noalias !5 <-> store i32 %5, i32* %incdec.ptr, noalias_sidechannel i32* %4, align 4, !tbaa !10, !noalias !5 +; WITHDT: NoAlias: %0 = load i32*, i32** @a, noalias_sidechannel i32** null, align 8, !tbaa !1, !noalias !5 <-> store i32 %7, i32* %add.ptr, noalias_sidechannel i32* %6, align 4, !tbaa !10, !noalias !5 +; WITHDT: NoAlias: %0 = load i32*, i32** @a, noalias_sidechannel i32** null, align 8, !tbaa !1, !noalias !5 <-> store i32 %10, i32* %8, noalias_sidechannel i32* %9, align 4, !tbaa !10, !noalias !5 +; WITHDT: NoAlias: %0 = load i32*, i32** @a, noalias_sidechannel i32** null, align 8, !tbaa !1, !noalias !5 <-> store i32 %add1, i32* @r, noalias_sidechannel i32* null, align 4, !tbaa !10, !noalias !9 +; WITHDT: NoAlias: %2 = load i32, i32* %0, noalias_sidechannel i32* %1, align 4, !tbaa !10, !noalias !5 <-> store i32 %add, i32* @r, noalias_sidechannel i32* null, align 4, !tbaa !10, !noalias !5 +; WITHDT: NoAlias: %2 = load i32, i32* %0, noalias_sidechannel i32* %1, align 4, !tbaa !10, !noalias !5 <-> store i32 %5, i32* %incdec.ptr, noalias_sidechannel i32* %4, align 4, !tbaa !10, !noalias !5 +; WITHDT: MayAlias: %2 = load i32, i32* %0, noalias_sidechannel i32* %1, align 4, !tbaa !10, !noalias !5 <-> store i32 %7, i32* %add.ptr, noalias_sidechannel i32* %6, align 4, !tbaa !10, !noalias !5 +; WITHDT: NoAlias: %2 = load i32, i32* %0, noalias_sidechannel i32* %1, align 4, !tbaa !10, !noalias !5 <-> store i32 %10, i32* %8, noalias_sidechannel i32* %9, align 4, !tbaa !10, !noalias !5 +; WITHDT: NoAlias: %2 = load i32, i32* %0, noalias_sidechannel i32* %1, align 4, !tbaa !10, !noalias !5 <-> store i32 %add1, i32* @r, noalias_sidechannel i32* null, align 4, !tbaa !10, !noalias !9 +; WITHDT: MustAlias: %3 = load i32, i32* @r, noalias_sidechannel i32* null, align 4, !tbaa !10, !noalias !5 <-> store i32 %add, i32* @r, noalias_sidechannel i32* null, align 4, !tbaa !10, !noalias !5 +; WITHDT: NoAlias: %3 = load i32, i32* @r, noalias_sidechannel i32* null, align 4, !tbaa !10, !noalias !5 <-> store i32 %5, i32* %incdec.ptr, noalias_sidechannel i32* %4, align 4, !tbaa !10, !noalias !5 +; WITHDT: NoAlias: %3 = load i32, i32* @r, noalias_sidechannel i32* null, align 4, !tbaa !10, !noalias !5 <-> store i32 %7, i32* %add.ptr, noalias_sidechannel i32* %6, align 4, !tbaa !10, !noalias !5 +; WITHDT: NoAlias: %3 = load i32, i32* @r, noalias_sidechannel i32* null, align 4, !tbaa !10, !noalias !5 <-> store i32 %10, i32* %8, noalias_sidechannel i32* %9, align 4, !tbaa !10, !noalias !5 +; WITHDT: MustAlias: %3 = load i32, i32* @r, noalias_sidechannel i32* null, align 4, !tbaa !10, !noalias !5 <-> store i32 %add1, i32* @r, noalias_sidechannel i32* null, align 4, !tbaa !10, !noalias !9 +; WITHDT: MustAlias: %5 = load i32, i32* @r, noalias_sidechannel i32* null, align 4, !tbaa !10, !noalias !5 <-> store i32 %add, i32* @r, noalias_sidechannel i32* null, align 4, !tbaa !10, !noalias !5 +; WITHDT: NoAlias: %5 = load i32, i32* @r, noalias_sidechannel i32* null, align 4, !tbaa !10, !noalias !5 <-> store i32 %5, i32* %incdec.ptr, noalias_sidechannel i32* %4, align 4, !tbaa !10, !noalias !5 +; WITHDT: NoAlias: %5 = load i32, i32* @r, noalias_sidechannel i32* null, align 4, !tbaa !10, !noalias !5 <-> store i32 %7, i32* %add.ptr, noalias_sidechannel i32* %6, align 4, !tbaa !10, !noalias !5 +; WITHDT: NoAlias: %5 = load i32, i32* @r, noalias_sidechannel i32* null, align 4, !tbaa !10, !noalias !5 <-> store i32 %10, i32* %8, noalias_sidechannel i32* %9, align 4, !tbaa !10, !noalias !5 +; WITHDT: MustAlias: %5 = load i32, i32* @r, noalias_sidechannel i32* null, align 4, !tbaa !10, !noalias !5 <-> store i32 %add1, i32* @r, noalias_sidechannel i32* null, align 4, !tbaa !10, !noalias !9 +; WITHDT: MustAlias: %7 = load i32, i32* @r, noalias_sidechannel i32* null, align 4, !tbaa !10, !noalias !5 <-> store i32 %add, i32* @r, noalias_sidechannel i32* null, align 4, !tbaa !10, !noalias !5 +; WITHDT: NoAlias: %7 = load i32, i32* @r, noalias_sidechannel i32* null, align 4, !tbaa !10, !noalias !5 <-> store i32 %5, i32* %incdec.ptr, noalias_sidechannel i32* %4, align 4, !tbaa !10, !noalias !5 +; WITHDT: NoAlias: %7 = load i32, i32* @r, noalias_sidechannel i32* null, align 4, !tbaa !10, !noalias !5 <-> store i32 %7, i32* %add.ptr, noalias_sidechannel i32* %6, align 4, !tbaa !10, !noalias !5 +; WITHDT: NoAlias: %7 = load i32, i32* @r, noalias_sidechannel i32* null, align 4, !tbaa !10, !noalias !5 <-> store i32 %10, i32* %8, noalias_sidechannel i32* %9, align 4, !tbaa !10, !noalias !5 +; WITHDT: MustAlias: %7 = load i32, i32* @r, noalias_sidechannel i32* null, align 4, !tbaa !10, !noalias !5 <-> store i32 %add1, i32* @r, noalias_sidechannel i32* null, align 4, !tbaa !10, !noalias !9 +; WITHDT: NoAlias: %8 = load i32*, i32** @a2, noalias_sidechannel i32** null, align 8, !tbaa !1, !noalias !5 <-> store i32 %add, i32* @r, noalias_sidechannel i32* null, align 4, !tbaa !10, !noalias !5 +; WITHDT: NoAlias: %8 = load i32*, i32** @a2, noalias_sidechannel i32** null, align 8, !tbaa !1, !noalias !5 <-> store i32 %5, i32* %incdec.ptr, noalias_sidechannel i32* %4, align 4, !tbaa !10, !noalias !5 +; WITHDT: NoAlias: %8 = load i32*, i32** @a2, noalias_sidechannel i32** null, align 8, !tbaa !1, !noalias !5 <-> store i32 %7, i32* %add.ptr, noalias_sidechannel i32* %6, align 4, !tbaa !10, !noalias !5 +; WITHDT: NoAlias: %8 = load i32*, i32** @a2, noalias_sidechannel i32** null, align 8, !tbaa !1, !noalias !5 <-> store i32 %10, i32* %8, noalias_sidechannel i32* %9, align 4, !tbaa !10, !noalias !5 +; WITHDT: NoAlias: %8 = load i32*, i32** @a2, noalias_sidechannel i32** null, align 8, !tbaa !1, !noalias !5 <-> store i32 %add1, i32* @r, noalias_sidechannel i32* null, align 4, !tbaa !10, !noalias !9 +; WITHDT: MustAlias: %10 = load i32, i32* @r, noalias_sidechannel i32* null, align 4, !tbaa !10, !noalias !5 <-> store i32 %add, i32* @r, noalias_sidechannel i32* null, align 4, !tbaa !10, !noalias !5 +; WITHDT: NoAlias: %10 = load i32, i32* @r, noalias_sidechannel i32* null, align 4, !tbaa !10, !noalias !5 <-> store i32 %5, i32* %incdec.ptr, noalias_sidechannel i32* %4, align 4, !tbaa !10, !noalias !5 +; WITHDT: NoAlias: %10 = load i32, i32* @r, noalias_sidechannel i32* null, align 4, !tbaa !10, !noalias !5 <-> store i32 %7, i32* %add.ptr, noalias_sidechannel i32* %6, align 4, !tbaa !10, !noalias !5 +; WITHDT: NoAlias: %10 = load i32, i32* @r, noalias_sidechannel i32* null, align 4, !tbaa !10, !noalias !5 <-> store i32 %10, i32* %8, noalias_sidechannel i32* %9, align 4, !tbaa !10, !noalias !5 +; WITHDT: MustAlias: %10 = load i32, i32* @r, noalias_sidechannel i32* null, align 4, !tbaa !10, !noalias !5 <-> store i32 %add1, i32* @r, noalias_sidechannel i32* null, align 4, !tbaa !10, !noalias !9 +; WITHDT: NoAlias: %11 = load i32*, i32** @a2, noalias_sidechannel i32** null, align 8, !tbaa !1, !noalias !9 <-> store i32 %add, i32* @r, noalias_sidechannel i32* null, align 4, !tbaa !10, !noalias !5 +; WITHDT: NoAlias: %11 = load i32*, i32** @a2, noalias_sidechannel i32** null, align 8, !tbaa !1, !noalias !9 <-> store i32 %5, i32* %incdec.ptr, noalias_sidechannel i32* %4, align 4, !tbaa !10, !noalias !5 +; WITHDT: NoAlias: %11 = load i32*, i32** @a2, noalias_sidechannel i32** null, align 8, !tbaa !1, !noalias !9 <-> store i32 %7, i32* %add.ptr, noalias_sidechannel i32* %6, align 4, !tbaa !10, !noalias !5 +; WITHDT: MayAlias: %11 = load i32*, i32** @a2, noalias_sidechannel i32** null, align 8, !tbaa !1, !noalias !9 <-> store i32 %10, i32* %8, noalias_sidechannel i32* %9, align 4, !tbaa !10, !noalias !5 +; WITHDT: NoAlias: %11 = load i32*, i32** @a2, noalias_sidechannel i32** null, align 8, !tbaa !1, !noalias !9 <-> store i32 %add1, i32* @r, noalias_sidechannel i32* null, align 4, !tbaa !10, !noalias !9 +; WITHDT: NoAlias: %13 = load i32, i32* %11, noalias_sidechannel i32* %12, align 4, !tbaa !10, !noalias !9 <-> store i32 %add, i32* @r, noalias_sidechannel i32* null, align 4, !tbaa !10, !noalias !5 +; WITHDT: NoAlias: %13 = load i32, i32* %11, noalias_sidechannel i32* %12, align 4, !tbaa !10, !noalias !9 <-> store i32 %5, i32* %incdec.ptr, noalias_sidechannel i32* %4, align 4, !tbaa !10, !noalias !5 +; WITHDT: NoAlias: %13 = load i32, i32* %11, noalias_sidechannel i32* %12, align 4, !tbaa !10, !noalias !9 <-> store i32 %7, i32* %add.ptr, noalias_sidechannel i32* %6, align 4, !tbaa !10, !noalias !5 +; WITHDT: MayAlias: %13 = load i32, i32* %11, noalias_sidechannel i32* %12, align 4, !tbaa !10, !noalias !9 <-> store i32 %10, i32* %8, noalias_sidechannel i32* %9, align 4, !tbaa !10, !noalias !5 +; WITHDT: NoAlias: %13 = load i32, i32* %11, noalias_sidechannel i32* %12, align 4, !tbaa !10, !noalias !9 <-> store i32 %add1, i32* @r, noalias_sidechannel i32* null, align 4, !tbaa !10, !noalias !9 +; WITHDT: MustAlias: %14 = load i32, i32* @r, noalias_sidechannel i32* null, align 4, !tbaa !10, !noalias !9 <-> store i32 %add, i32* @r, noalias_sidechannel i32* null, align 4, !tbaa !10, !noalias !5 +; WITHDT: NoAlias: %14 = load i32, i32* @r, noalias_sidechannel i32* null, align 4, !tbaa !10, !noalias !9 <-> store i32 %5, i32* %incdec.ptr, noalias_sidechannel i32* %4, align 4, !tbaa !10, !noalias !5 +; WITHDT: NoAlias: %14 = load i32, i32* @r, noalias_sidechannel i32* null, align 4, !tbaa !10, !noalias !9 <-> store i32 %7, i32* %add.ptr, noalias_sidechannel i32* %6, align 4, !tbaa !10, !noalias !5 +; WITHDT: MayAlias: %14 = load i32, i32* @r, noalias_sidechannel i32* null, align 4, !tbaa !10, !noalias !9 <-> store i32 %10, i32* %8, noalias_sidechannel i32* %9, align 4, !tbaa !10, !noalias !5 +; WITHDT: MustAlias: %14 = load i32, i32* @r, noalias_sidechannel i32* null, align 4, !tbaa !10, !noalias !9 <-> store i32 %add1, i32* @r, noalias_sidechannel i32* null, align 4, !tbaa !10, !noalias !9 +; WITHDT: NoAlias: store i32 %5, i32* %incdec.ptr, noalias_sidechannel i32* %4, align 4, !tbaa !10, !noalias !5 <-> store i32 %add, i32* @r, noalias_sidechannel i32* null, align 4, !tbaa !10, !noalias !5 +; WITHDT: NoAlias: store i32 %7, i32* %add.ptr, noalias_sidechannel i32* %6, align 4, !tbaa !10, !noalias !5 <-> store i32 %add, i32* @r, noalias_sidechannel i32* null, align 4, !tbaa !10, !noalias !5 +; WITHDT: MayAlias: store i32 %7, i32* %add.ptr, noalias_sidechannel i32* %6, align 4, !tbaa !10, !noalias !5 <-> store i32 %5, i32* %incdec.ptr, noalias_sidechannel i32* %4, align 4, !tbaa !10, !noalias !5 +; WITHDT: NoAlias: store i32 %10, i32* %8, noalias_sidechannel i32* %9, align 4, !tbaa !10, !noalias !5 <-> store i32 %add, i32* @r, noalias_sidechannel i32* null, align 4, !tbaa !10, !noalias !5 +; WITHDT: NoAlias: store i32 %10, i32* %8, noalias_sidechannel i32* %9, align 4, !tbaa !10, !noalias !5 <-> store i32 %5, i32* %incdec.ptr, noalias_sidechannel i32* %4, align 4, !tbaa !10, !noalias !5 +; WITHDT: NoAlias: store i32 %10, i32* %8, noalias_sidechannel i32* %9, align 4, !tbaa !10, !noalias !5 <-> store i32 %7, i32* %add.ptr, noalias_sidechannel i32* %6, align 4, !tbaa !10, !noalias !5 +; WITHDT: MustAlias: store i32 %add1, i32* @r, noalias_sidechannel i32* null, align 4, !tbaa !10, !noalias !9 <-> store i32 %add, i32* @r, noalias_sidechannel i32* null, align 4, !tbaa !10, !noalias !5 +; WITHDT: NoAlias: store i32 %add1, i32* @r, noalias_sidechannel i32* null, align 4, !tbaa !10, !noalias !9 <-> store i32 %5, i32* %incdec.ptr, noalias_sidechannel i32* %4, align 4, !tbaa !10, !noalias !5 +; WITHDT: NoAlias: store i32 %add1, i32* @r, noalias_sidechannel i32* null, align 4, !tbaa !10, !noalias !9 <-> store i32 %7, i32* %add.ptr, noalias_sidechannel i32* %6, align 4, !tbaa !10, !noalias !5 +; WITHDT: MayAlias: store i32 %add1, i32* @r, noalias_sidechannel i32* null, align 4, !tbaa !10, !noalias !9 <-> store i32 %10, i32* %8, noalias_sidechannel i32* %9, align 4, !tbaa !10, !noalias !5 declare void @ex1(i32*) Index: llvm/test/Analysis/ScopedNoAliasAA/noalias.ll =================================================================== --- llvm/test/Analysis/ScopedNoAliasAA/noalias.ll +++ llvm/test/Analysis/ScopedNoAliasAA/noalias.ll @@ -3,55 +3,54 @@ target triple = "x86_64-unknown-linux-gnu" ; Function Attrs: nounwind uwtable -define void @foo(float* nocapture %a, float* nocapture readonly %c) #0 { +define void @foo(float* nocapture %a, float* nocapture readonly %c, i64 %i0, i64 %i1) #0 { entry: - %0 = call float* @llvm.noalias.p0f32(float* %a, metadata !0) #1 - %1 = load float, float* %c, align 4, !noalias !0 - %arrayidx.i = getelementptr inbounds float, float* %0, i64 5 - store float %1, float* %arrayidx.i, align 4, !noalias !0 - %2 = load float, float* %c, align 4 - %arrayidx = getelementptr inbounds float, float* %a, i64 7 - store float %2, float* %arrayidx, align 4 + %side.a = call float* @llvm.side.noalias.p0f32.p0i8.p0p0f32.p0p0f32.i32(float* %a, i8* null, float** null, float** null, i32 0, metadata !0) #1 + %0 = load float, float* %c, noalias_sidechannel float* null, align 4, !noalias !0 + %arrayidx.i = getelementptr inbounds float, float* %a, i64 %i0 + store float %0, float* %arrayidx.i, noalias_sidechannel float* %side.a, align 4, !noalias !0 + %1 = load float, float* %c, align 4 + %arrayidx = getelementptr inbounds float, float* %a, i64 %i1 + store float %1, float* %arrayidx, noalias_sidechannel float* null, align 4, !noalias !0 ret void } ; CHECK-LABEL: Function: foo: -; CHECK: NoAlias: %1 = load float, float* %c, align 4, !noalias !0 <-> store float %1, float* %arrayidx.i, align 4, !noalias !0 -; CHECK: MayAlias: %1 = load float, float* %c, align 4, !noalias !0 <-> store float %2, float* %arrayidx, align 4 -; CHECK: MayAlias: %2 = load float, float* %c, align 4 <-> store float %1, float* %arrayidx.i, align 4, !noalias !0 -; CHECK: MayAlias: %2 = load float, float* %c, align 4 <-> store float %2, float* %arrayidx, align 4 -; CHECK: NoAlias: store float %2, float* %arrayidx, align 4 <-> store float %1, float* %arrayidx.i, align 4, !noalias !0 +; CHECK: NoAlias: %0 = load float, float* %c, noalias_sidechannel float* null, align 4, !noalias !0 <-> store float %0, float* %arrayidx.i, noalias_sidechannel float* %side.a, align 4, !noalias !0 +; CHECK: MayAlias: %0 = load float, float* %c, noalias_sidechannel float* null, align 4, !noalias !0 <-> store float %1, float* %arrayidx, noalias_sidechannel float* null, align 4, !noalias !0 +; CHECK: MayAlias: %1 = load float, float* %c, align 4 <-> store float %0, float* %arrayidx.i, noalias_sidechannel float* %side.a, align 4, !noalias !0 +; CHECK: MayAlias: %1 = load float, float* %c, align 4 <-> store float %1, float* %arrayidx, noalias_sidechannel float* null, align 4, !noalias !0 +; CHECK: NoAlias: store float %1, float* %arrayidx, noalias_sidechannel float* null, align 4, !noalias !0 <-> store float %0, float* %arrayidx.i, noalias_sidechannel float* %side.a, align 4, !noalias !0 ; Function Attrs: nounwind uwtable -define void @foo2(float* nocapture %a, float* nocapture %b, float* nocapture readonly %c) #0 { +define void @foo2(float* nocapture %a, float* nocapture %b, float* nocapture readonly %c, i64 %i0, i64 %i1) #0 { entry: - %0 = call float* @llvm.noalias.p0f32(float* %a, metadata !3) #1 - %1 = call float* @llvm.noalias.p0f32(float* %b, metadata !6) #1 - %2 = load float, float* %c, align 4, !noalias !8 - %arrayidx.i = getelementptr inbounds float, float* %0, i64 5 - store float %2, float* %arrayidx.i, align 4, !noalias !8 - %arrayidx1.i = getelementptr inbounds float, float* %1, i64 8 - store float %2, float* %arrayidx1.i, align 4, !noalias !8 + %0 = call float* @llvm.side.noalias.p0f32.p0i8.p0p0f32.p0p0f32.i32(float* %a, i8* null, float** null, float** null, i32 0, metadata !3) #1 + %1 = call float* @llvm.side.noalias.p0f32.p0i8.p0p0f32.p0p0f32.i32(float* %b, i8* null, float** null, float** null, i32 0, metadata !6) #1 + %2 = load float, float* %c, noalias_sidechannel float* null, align 4, !noalias !8 + %arrayidx.i = getelementptr inbounds float, float* %a, i64 5 + store float %2, float* %arrayidx.i, noalias_sidechannel float* %0, align 4, !noalias !8 + %arrayidx1.i = getelementptr inbounds float, float* %b, i64 %i0 + store float %2, float* %arrayidx1.i, noalias_sidechannel float* %1, align 4, !noalias !8 %3 = load float, float* %c, align 4 - %arrayidx = getelementptr inbounds float, float* %a, i64 7 - store float %3, float* %arrayidx, align 4 + %arrayidx = getelementptr inbounds float, float* %a, i64 %i1 + store float %3, float* %arrayidx, noalias_sidechannel float* null, align 4, !noalias !8 ret void } ; CHECK-LABEL: Function: foo2: -; CHECK: NoAlias: %2 = load float, float* %c, align 4, !noalias !5 <-> store float %2, float* %arrayidx.i, align 4, !noalias !5 -; CHECK: NoAlias: %2 = load float, float* %c, align 4, !noalias !5 <-> store float %2, float* %arrayidx1.i, align 4, !noalias !5 -; CHECK: MayAlias: %2 = load float, float* %c, align 4, !noalias !5 <-> store float %3, float* %arrayidx, align 4 -; CHECK: MayAlias: %3 = load float, float* %c, align 4 <-> store float %2, float* %arrayidx.i, align 4, !noalias !5 -; CHECK: MayAlias: %3 = load float, float* %c, align 4 <-> store float %2, float* %arrayidx1.i, align 4, !noalias !5 -; CHECK: MayAlias: %3 = load float, float* %c, align 4 <-> store float %3, float* %arrayidx, align 4 -; CHECK: NoAlias: store float %2, float* %arrayidx1.i, align 4, !noalias !5 <-> store float %2, float* %arrayidx.i, align 4, !noalias !5 -; CHECK: NoAlias: store float %3, float* %arrayidx, align 4 <-> store float %2, float* %arrayidx.i, align 4, !noalias !5 -; CHECK: MayAlias: store float %3, float* %arrayidx, align 4 <-> store float %2, float* %arrayidx1.i, align 4, !noalias !5 +; CHECK: NoAlias: %2 = load float, float* %c, noalias_sidechannel float* null, align 4, !noalias !5 <-> store float %2, float* %arrayidx.i, noalias_sidechannel float* %0, align 4, !noalias !5 +; CHECK: NoAlias: %2 = load float, float* %c, noalias_sidechannel float* null, align 4, !noalias !5 <-> store float %2, float* %arrayidx1.i, noalias_sidechannel float* %1, align 4, !noalias !5 +; CHECK: MayAlias: %2 = load float, float* %c, noalias_sidechannel float* null, align 4, !noalias !5 <-> store float %3, float* %arrayidx, noalias_sidechannel float* null, align 4, !noalias !5 +; CHECK: MayAlias: %3 = load float, float* %c, align 4 <-> store float %2, float* %arrayidx.i, noalias_sidechannel float* %0, align 4, !noalias !5 +; CHECK: MayAlias: %3 = load float, float* %c, align 4 <-> store float %2, float* %arrayidx1.i, noalias_sidechannel float* %1, align 4, !noalias !5 +; CHECK: MayAlias: %3 = load float, float* %c, align 4 <-> store float %3, float* %arrayidx, noalias_sidechannel float* null, align 4, !noalias !5 +; CHECK: NoAlias: store float %2, float* %arrayidx1.i, noalias_sidechannel float* %1, align 4, !noalias !5 <-> store float %2, float* %arrayidx.i, noalias_sidechannel float* %0, align 4, !noalias !5 +; CHECK: NoAlias: store float %3, float* %arrayidx, noalias_sidechannel float* null, align 4, !noalias !5 <-> store float %2, float* %arrayidx.i, noalias_sidechannel float* %0, align 4, !noalias !5 +; CHECK: NoAlias: store float %3, float* %arrayidx, noalias_sidechannel float* null, align 4, !noalias !5 <-> store float %2, float* %arrayidx1.i, noalias_sidechannel float* %1, align 4, !noalias !5 -; Function Attrs: nounwind -declare float* @llvm.noalias.p0f32(float*, metadata) #1 +declare float* @llvm.side.noalias.p0f32.p0i8.p0p0f32.p0p0f32.i32(float*, i8*, float**, float**, i32, metadata ) nounwind attributes #0 = { nounwind uwtable } attributes #1 = { nounwind } Index: llvm/test/Analysis/ScopedNoAliasAA/noalias2.ll =================================================================== --- llvm/test/Analysis/ScopedNoAliasAA/noalias2.ll +++ llvm/test/Analysis/ScopedNoAliasAA/noalias2.ll @@ -5,84 +5,84 @@ ; Function Attrs: nounwind uwtable define void @foo(float* noalias nocapture %a, float* noalias nocapture readonly %c) #0 { entry: - %0 = call float* @llvm.noalias.p0f32(float* %a, metadata !0) #1 - %1 = call float* @llvm.noalias.p0f32(float* %c, metadata !3) #1 - %2 = load float, float* %1, align 4, !noalias !5 - %arrayidx.i = getelementptr inbounds float, float* %0, i64 5 - store float %2, float* %arrayidx.i, align 4, !noalias !5 - %3 = load float, float* %c, align 4 + %0 = call float* @llvm.side.noalias.p0f32.p0i8.p0p0f32.p0p0f32.i32(float* %a, i8* null, float** null, float** null, i32 0, metadata !0) #1 + %1 = call float* @llvm.side.noalias.p0f32.p0i8.p0p0f32.p0p0f32.i32(float* %c, i8* null, float** null, float** null, i32 0, metadata !3) #1 + %2 = load float, float* %c, noalias_sidechannel float* %1, align 4, !noalias !5 + %arrayidx.i = getelementptr inbounds float, float* %a, i64 5 + store float %2, float* %arrayidx.i, noalias_sidechannel float* %0, align 4, !noalias !5 + %3 = load float, float* %c, noalias_sidechannel float* null, align 4, !noalias !5 %arrayidx = getelementptr inbounds float, float* %a, i64 7 - store float %3, float* %arrayidx, align 4 + store float %3, float* %arrayidx, noalias_sidechannel float* null, align 4, !noalias !5 ret void } ; CHECK-LABEL: Function: foo: -; CHECK: NoAlias: %2 = load float, float* %1, align 4, !noalias !5 <-> store float %2, float* %arrayidx.i, align 4, !noalias !5 -; CHECK: NoAlias: %2 = load float, float* %1, align 4, !noalias !5 <-> store float %3, float* %arrayidx, align 4 -; CHECK: NoAlias: %3 = load float, float* %c, align 4 <-> store float %2, float* %arrayidx.i, align 4, !noalias !5 -; CHECK: NoAlias: %3 = load float, float* %c, align 4 <-> store float %3, float* %arrayidx, align 4 -; CHECK: NoAlias: store float %3, float* %arrayidx, align 4 <-> store float %2, float* %arrayidx.i, align 4, !noalias !5 +; CHECK: NoAlias: %2 = load float, float* %c, noalias_sidechannel float* %1, align 4, !noalias !5 <-> store float %2, float* %arrayidx.i, noalias_sidechannel float* %0, align 4, !noalias !5 +; CHECK: NoAlias: %2 = load float, float* %c, noalias_sidechannel float* %1, align 4, !noalias !5 <-> store float %3, float* %arrayidx, noalias_sidechannel float* null, align 4, !noalias !5 +; CHECK: NoAlias: %3 = load float, float* %c, noalias_sidechannel float* null, align 4, !noalias !5 <-> store float %2, float* %arrayidx.i, noalias_sidechannel float* %0, align 4, !noalias !5 +; CHECK: NoAlias: %3 = load float, float* %c, noalias_sidechannel float* null, align 4, !noalias !5 <-> store float %3, float* %arrayidx, noalias_sidechannel float* null, align 4, !noalias !5 +; CHECK: NoAlias: store float %3, float* %arrayidx, noalias_sidechannel float* null, align 4, !noalias !5 <-> store float %2, float* %arrayidx.i, noalias_sidechannel float* %0, align 4, !noalias !5 ; Function Attrs: nounwind uwtable define void @foo2(float* nocapture %a, float* nocapture %b, float* nocapture readonly %c) #0 { entry: - %0 = call float* @llvm.noalias.p0f32(float* %a, metadata !6) #1 - %1 = call float* @llvm.noalias.p0f32(float* %c, metadata !9) #1 - %2 = call float* @llvm.noalias.p0f32(float* %0, metadata !11) #1, !noalias !14 - %3 = call float* @llvm.noalias.p0f32(float* %1, metadata !15) #1, !noalias !14 - %4 = load float, float* %3, align 4, !noalias !17 - %arrayidx.i.i = getelementptr inbounds float, float* %2, i64 5 - store float %4, float* %arrayidx.i.i, align 4, !noalias !17 - %5 = load float, float* %1, align 4, !noalias !14 - %arrayidx.i = getelementptr inbounds float, float* %0, i64 7 - store float %5, float* %arrayidx.i, align 4, !noalias !14 - %6 = call float* @llvm.noalias.p0f32(float* %a, metadata !18) #1 - %7 = call float* @llvm.noalias.p0f32(float* %b, metadata !21) #1 - %8 = load float, float* %c, align 4, !noalias !23 - %arrayidx.i1 = getelementptr inbounds float, float* %6, i64 6 - store float %8, float* %arrayidx.i1, align 4, !noalias !23 - %arrayidx1.i = getelementptr inbounds float, float* %7, i64 8 - store float %8, float* %arrayidx1.i, align 4, !noalias !23 + %0 = call float* @llvm.side.noalias.p0f32.p0i8.p0p0f32.p0p0f32.i32(float* %a, i8* null, float** null, float** null, i32 0, metadata !6) #1 + %1 = call float* @llvm.side.noalias.p0f32.p0i8.p0p0f32.p0p0f32.i32(float* %c, i8* null, float** null, float** null, i32 0, metadata !9) #1 + %2 = call float* @llvm.side.noalias.p0f32.p0i8.p0p0f32.p0p0f32.i32(float* %0, i8* null, float** null, float** null, i32 0, metadata !11) #1, !noalias !14 + %3 = call float* @llvm.side.noalias.p0f32.p0i8.p0p0f32.p0p0f32.i32(float* %1, i8* null, float** null, float** null, i32 0, metadata !15) #1, !noalias !14 + %4 = load float, float* %c, noalias_sidechannel float* %3, align 4, !noalias !17 + %arrayidx.i.i = getelementptr inbounds float, float* %a, i64 5 + store float %4, float* %arrayidx.i.i, noalias_sidechannel float* %2, align 4, !noalias !17 + %5 = load float, float* %c, noalias_sidechannel float* %1, align 4, !noalias !14 + %arrayidx.i = getelementptr inbounds float, float* %a, i64 7 + store float %5, float* %arrayidx.i, noalias_sidechannel float* %0, align 4, !noalias !14 + %6 = call float* @llvm.side.noalias.p0f32.p0i8.p0p0f32.p0p0f32.i32(float* %a, i8* null, float** null, float** null, i32 0, metadata !18) #1 + %7 = call float* @llvm.side.noalias.p0f32.p0i8.p0p0f32.p0p0f32.i32(float* %b, i8* null, float** null, float** null, i32 0, metadata !21) #1 + %8 = load float, float* %c, noalias_sidechannel float* null, align 4, !noalias !23 + %arrayidx.i1 = getelementptr inbounds float, float* %a, i64 6 + store float %8, float* %arrayidx.i1, noalias_sidechannel float* %6, align 4, !noalias !23 + %arrayidx1.i = getelementptr inbounds float, float* %b, i64 8 + store float %8, float* %arrayidx1.i, noalias_sidechannel float* %7, align 4, !noalias !23 + ; %9 = load float, float* %c, noalias_sidechannel float* null, align 4, !noalias !23 %9 = load float, float* %c, align 4 %arrayidx = getelementptr inbounds float, float* %a, i64 7 - store float %9, float* %arrayidx, align 4 + store float %9, float* %arrayidx, noalias_sidechannel float* null, align 4, !noalias !23 ret void } ; CHECK-LABEL: Function: foo2: -; CHECK: NoAlias: %4 = load float, float* %3, align 4, !noalias !11 <-> store float %4, float* %arrayidx.i.i, align 4, !noalias !11 -; CHECK: NoAlias: %4 = load float, float* %3, align 4, !noalias !11 <-> store float %5, float* %arrayidx.i, align 4, !noalias !8 -; CHECK: MayAlias: %4 = load float, float* %3, align 4, !noalias !11 <-> store float %8, float* %arrayidx.i1, align 4, !noalias !17 -; CHECK: MayAlias: %4 = load float, float* %3, align 4, !noalias !11 <-> store float %8, float* %arrayidx1.i, align 4, !noalias !17 -; CHECK: MayAlias: %4 = load float, float* %3, align 4, !noalias !11 <-> store float %9, float* %arrayidx, align 4 -; CHECK: NoAlias: %5 = load float, float* %1, align 4, !noalias !8 <-> store float %4, float* %arrayidx.i.i, align 4, !noalias !11 -; CHECK: NoAlias: %5 = load float, float* %1, align 4, !noalias !8 <-> store float %5, float* %arrayidx.i, align 4, !noalias !8 -; CHECK: MayAlias: %5 = load float, float* %1, align 4, !noalias !8 <-> store float %8, float* %arrayidx.i1, align 4, !noalias !17 -; CHECK: MayAlias: %5 = load float, float* %1, align 4, !noalias !8 <-> store float %8, float* %arrayidx1.i, align 4, !noalias !17 -; CHECK: MayAlias: %5 = load float, float* %1, align 4, !noalias !8 <-> store float %9, float* %arrayidx, align 4 -; CHECK: MayAlias: %8 = load float, float* %c, align 4, !noalias !17 <-> store float %4, float* %arrayidx.i.i, align 4, !noalias !11 -; CHECK: MayAlias: %8 = load float, float* %c, align 4, !noalias !17 <-> store float %5, float* %arrayidx.i, align 4, !noalias !8 -; CHECK: NoAlias: %8 = load float, float* %c, align 4, !noalias !17 <-> store float %8, float* %arrayidx.i1, align 4, !noalias !17 -; CHECK: NoAlias: %8 = load float, float* %c, align 4, !noalias !17 <-> store float %8, float* %arrayidx1.i, align 4, !noalias !17 -; CHECK: MayAlias: %8 = load float, float* %c, align 4, !noalias !17 <-> store float %9, float* %arrayidx, align 4 -; CHECK: MayAlias: %9 = load float, float* %c, align 4 <-> store float %4, float* %arrayidx.i.i, align 4, !noalias !11 -; CHECK: MayAlias: %9 = load float, float* %c, align 4 <-> store float %5, float* %arrayidx.i, align 4, !noalias !8 -; CHECK: MayAlias: %9 = load float, float* %c, align 4 <-> store float %8, float* %arrayidx.i1, align 4, !noalias !17 -; CHECK: MayAlias: %9 = load float, float* %c, align 4 <-> store float %8, float* %arrayidx1.i, align 4, !noalias !17 -; CHECK: MayAlias: %9 = load float, float* %c, align 4 <-> store float %9, float* %arrayidx, align 4 -; CHECK: NoAlias: store float %5, float* %arrayidx.i, align 4, !noalias !8 <-> store float %4, float* %arrayidx.i.i, align 4, !noalias !11 -; CHECK: NoAlias: store float %8, float* %arrayidx.i1, align 4, !noalias !17 <-> store float %4, float* %arrayidx.i.i, align 4, !noalias !11 -; CHECK: NoAlias: store float %8, float* %arrayidx.i1, align 4, !noalias !17 <-> store float %5, float* %arrayidx.i, align 4, !noalias !8 -; CHECK: MayAlias: store float %8, float* %arrayidx1.i, align 4, !noalias !17 <-> store float %4, float* %arrayidx.i.i, align 4, !noalias !11 -; CHECK: MayAlias: store float %8, float* %arrayidx1.i, align 4, !noalias !17 <-> store float %5, float* %arrayidx.i, align 4, !noalias !8 -; CHECK: NoAlias: store float %8, float* %arrayidx1.i, align 4, !noalias !17 <-> store float %8, float* %arrayidx.i1, align 4, !noalias !17 -; CHECK: NoAlias: store float %9, float* %arrayidx, align 4 <-> store float %4, float* %arrayidx.i.i, align 4, !noalias !11 -; CHECK: MustAlias: store float %9, float* %arrayidx, align 4 <-> store float %5, float* %arrayidx.i, align 4, !noalias !8 -; CHECK: NoAlias: store float %9, float* %arrayidx, align 4 <-> store float %8, float* %arrayidx.i1, align 4, !noalias !17 -; CHECK: MayAlias: store float %9, float* %arrayidx, align 4 <-> store float %8, float* %arrayidx1.i, align 4, !noalias !17 +; CHECK: NoAlias: %4 = load float, float* %c, noalias_sidechannel float* %3, align 4, !noalias !11 <-> store float %4, float* %arrayidx.i.i, noalias_sidechannel float* %2, align 4, !noalias !11 +; CHECK: NoAlias: %4 = load float, float* %c, noalias_sidechannel float* %3, align 4, !noalias !11 <-> store float %5, float* %arrayidx.i, noalias_sidechannel float* %0, align 4, !noalias !8 +; CHECK: MayAlias: %4 = load float, float* %c, noalias_sidechannel float* %3, align 4, !noalias !11 <-> store float %8, float* %arrayidx.i1, noalias_sidechannel float* %6, align 4, !noalias !17 +; CHECK: MayAlias: %4 = load float, float* %c, noalias_sidechannel float* %3, align 4, !noalias !11 <-> store float %8, float* %arrayidx1.i, noalias_sidechannel float* %7, align 4, !noalias !17 +; CHECK: MayAlias: %4 = load float, float* %c, noalias_sidechannel float* %3, align 4, !noalias !11 <-> store float %9, float* %arrayidx, noalias_sidechannel float* null, align 4, !noalias !17 +; CHECK: NoAlias: %5 = load float, float* %c, noalias_sidechannel float* %1, align 4, !noalias !8 <-> store float %4, float* %arrayidx.i.i, noalias_sidechannel float* %2, align 4, !noalias !11 +; CHECK: NoAlias: %5 = load float, float* %c, noalias_sidechannel float* %1, align 4, !noalias !8 <-> store float %5, float* %arrayidx.i, noalias_sidechannel float* %0, align 4, !noalias !8 +; CHECK: MayAlias: %5 = load float, float* %c, noalias_sidechannel float* %1, align 4, !noalias !8 <-> store float %8, float* %arrayidx.i1, noalias_sidechannel float* %6, align 4, !noalias !17 +; CHECK: MayAlias: %5 = load float, float* %c, noalias_sidechannel float* %1, align 4, !noalias !8 <-> store float %8, float* %arrayidx1.i, noalias_sidechannel float* %7, align 4, !noalias !17 +; CHECK: MayAlias: %5 = load float, float* %c, noalias_sidechannel float* %1, align 4, !noalias !8 <-> store float %9, float* %arrayidx, noalias_sidechannel float* null, align 4, !noalias !17 +; CHECK: MayAlias: %8 = load float, float* %c, noalias_sidechannel float* null, align 4, !noalias !17 <-> store float %4, float* %arrayidx.i.i, noalias_sidechannel float* %2, align 4, !noalias !11 +; CHECK: MayAlias: %8 = load float, float* %c, noalias_sidechannel float* null, align 4, !noalias !17 <-> store float %5, float* %arrayidx.i, noalias_sidechannel float* %0, align 4, !noalias !8 +; CHECK: NoAlias: %8 = load float, float* %c, noalias_sidechannel float* null, align 4, !noalias !17 <-> store float %8, float* %arrayidx.i1, noalias_sidechannel float* %6, align 4, !noalias !17 +; CHECK: NoAlias: %8 = load float, float* %c, noalias_sidechannel float* null, align 4, !noalias !17 <-> store float %8, float* %arrayidx1.i, noalias_sidechannel float* %7, align 4, !noalias !17 +; CHECK: MayAlias: %8 = load float, float* %c, noalias_sidechannel float* null, align 4, !noalias !17 <-> store float %9, float* %arrayidx, noalias_sidechannel float* null, align 4, !noalias !17 +; CHECK: MayAlias: %9 = load float, float* %c, align 4 <-> store float %4, float* %arrayidx.i.i, noalias_sidechannel float* %2, align 4, !noalias !11 +; CHECK: MayAlias: %9 = load float, float* %c, align 4 <-> store float %5, float* %arrayidx.i, noalias_sidechannel float* %0, align 4, !noalias !8 +; CHECK: MayAlias: %9 = load float, float* %c, align 4 <-> store float %8, float* %arrayidx.i1, noalias_sidechannel float* %6, align 4, !noalias !17 +; CHECK: MayAlias: %9 = load float, float* %c, align 4 <-> store float %8, float* %arrayidx1.i, noalias_sidechannel float* %7, align 4, !noalias !17 +; CHECK: MayAlias: %9 = load float, float* %c, align 4 <-> store float %9, float* %arrayidx, noalias_sidechannel float* null, align 4, !noalias !17 +; CHECK: NoAlias: store float %5, float* %arrayidx.i, noalias_sidechannel float* %0, align 4, !noalias !8 <-> store float %4, float* %arrayidx.i.i, noalias_sidechannel float* %2, align 4, !noalias !11 +; CHECK: NoAlias: store float %8, float* %arrayidx.i1, noalias_sidechannel float* %6, align 4, !noalias !17 <-> store float %4, float* %arrayidx.i.i, noalias_sidechannel float* %2, align 4, !noalias !11 +; CHECK: NoAlias: store float %8, float* %arrayidx.i1, noalias_sidechannel float* %6, align 4, !noalias !17 <-> store float %5, float* %arrayidx.i, noalias_sidechannel float* %0, align 4, !noalias !8 +; CHECK: MayAlias: store float %8, float* %arrayidx1.i, noalias_sidechannel float* %7, align 4, !noalias !17 <-> store float %4, float* %arrayidx.i.i, noalias_sidechannel float* %2, align 4, !noalias !11 +; CHECK: MayAlias: store float %8, float* %arrayidx1.i, noalias_sidechannel float* %7, align 4, !noalias !17 <-> store float %5, float* %arrayidx.i, noalias_sidechannel float* %0, align 4, !noalias !8 +; CHECK: NoAlias: store float %8, float* %arrayidx1.i, noalias_sidechannel float* %7, align 4, !noalias !17 <-> store float %8, float* %arrayidx.i1, noalias_sidechannel float* %6, align 4, !noalias !17 +; CHECK: NoAlias: store float %9, float* %arrayidx, noalias_sidechannel float* null, align 4, !noalias !17 <-> store float %4, float* %arrayidx.i.i, noalias_sidechannel float* %2, align 4, !noalias !11 +; CHECK: MustAlias: store float %9, float* %arrayidx, noalias_sidechannel float* null, align 4, !noalias !17 <-> store float %5, float* %arrayidx.i, noalias_sidechannel float* %0, align 4, !noalias !8 +; CHECK: NoAlias: store float %9, float* %arrayidx, noalias_sidechannel float* null, align 4, !noalias !17 <-> store float %8, float* %arrayidx.i1, noalias_sidechannel float* %6, align 4, !noalias !17 +; CHECK: NoAlias: store float %9, float* %arrayidx, noalias_sidechannel float* null, align 4, !noalias !17 <-> store float %8, float* %arrayidx1.i, noalias_sidechannel float* %7, align 4, !noalias !17 -; Function Attrs: nounwind -declare float* @llvm.noalias.p0f32(float*, metadata) #1 +declare float* @llvm.side.noalias.p0f32.p0i8.p0p0f32.p0p0f32.i32(float*, i8*, float**, float**, i32, metadata ) nounwind attributes #0 = { nounwind uwtable } attributes #1 = { nounwind } Index: llvm/test/Analysis/ScopedNoAliasAA/noalias_basics.ll =================================================================== --- /dev/null +++ llvm/test/Analysis/ScopedNoAliasAA/noalias_basics.ll @@ -0,0 +1,142 @@ +; RUN: opt < %s -basicaa -scoped-noalias -aa-eval -evaluate-aa-metadata -print-all-alias-modref-info -disable-output 2>&1 | FileCheck %s +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +; Function Attrs: nofree norecurse nounwind uwtable writeonly +define dso_local void @test_p_p(i32* nocapture %_pA, i32* nocapture %_pB) local_unnamed_addr #0 { +entry: + store i32 42, i32* %_pA, align 4, !tbaa !2 + store i32 99, i32* %_pB, align 4, !tbaa !2 + ret void +} +; CHECK-LABEL: Function: test_p_p: +; CHECK: MayAlias: store i32 99, i32* %_pB, align 4, !tbaa !2 <-> store i32 42, i32* %_pA, align 4, !tbaa !2 + +; Function Attrs: nounwind uwtable +define dso_local void @test_rp_p(i32* nocapture %_pA, i32* nocapture %_pB) local_unnamed_addr #1 { +entry: + %0 = tail call i8* @llvm.noalias.decl.p0i8.p0p0i32.i32(i32** null, i32 0, metadata !6) + %1 = tail call i32* @llvm.side.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32* %_pA, i8* %0, i32** null, i32** undef, i32 0, metadata !6), !tbaa !9, !noalias !6 + store i32 42, i32* %_pA, noalias_sidechannel i32* %1, align 4, !tbaa !2, !noalias !6 + store i32 99, i32* %_pB, noalias_sidechannel i32* undef, align 4, !tbaa !2, !noalias !6 + ret void +} +; CHECK-LABEL: Function: test_rp_p: +; CHECK: NoAlias: store i32 99, i32* %_pB, noalias_sidechannel i32* undef, align 4, !tbaa !9, !noalias !2 <-> store i32 42, i32* %_pA, noalias_sidechannel i32* %1, align 4, !tbaa !9, !noalias !2 + +; Function Attrs: argmemonly nounwind +declare i8* @llvm.noalias.decl.p0i8.p0p0i32.i32(i32**, i32, metadata) #2 + +; Function Attrs: nounwind uwtable +define dso_local void @test_rp_rp_00(i32* nocapture %_pA, i32* nocapture %_pB) local_unnamed_addr #1 { +entry: + %0 = tail call i8* @llvm.noalias.decl.p0i8.p0p0i32.i32(i32** null, i32 0, metadata !11) + %1 = tail call i8* @llvm.noalias.decl.p0i8.p0p0i32.i32(i32** null, i32 0, metadata !14) + %2 = tail call i32* @llvm.side.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32* %_pA, i8* %0, i32** null, i32** undef, i32 0, metadata !11), !tbaa !9, !noalias !16 + store i32 42, i32* %_pA, noalias_sidechannel i32* %2, align 4, !tbaa !2, !noalias !16 + %3 = tail call i32* @llvm.side.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32* %_pB, i8* %1, i32** null, i32** undef, i32 0, metadata !14), !tbaa !9, !noalias !16 + store i32 99, i32* %_pB, noalias_sidechannel i32* %3, align 4, !tbaa !2, !noalias !16 + ret void +} +; CHECK-LABEL: Function: test_rp_rp_00: +; CHECK: NoAlias: store i32 99, i32* %_pB, noalias_sidechannel i32* %3, align 4, !tbaa !12, !noalias !11 <-> store i32 42, i32* %_pA, noalias_sidechannel i32* %2, align 4, !tbaa !12, !noalias !11 + +; Now test variants: {objectP, objectID, Scope } +; NOTE: in the following tests, the Scope information is recycled from previous tests + +; Same info -> MayAlias +; Function Attrs: nounwind uwtable +define dso_local void @test_rp_rp_01(i32* nocapture %_pA, i32* nocapture %_pB) local_unnamed_addr #1 { +entry: + %a.p = alloca i32*, align 8 + %b.p = alloca i32*, align 8 + %0 = tail call i8* @llvm.noalias.decl.p0i8.p0p0i32.i32(i32** %a.p, i32 0, metadata !11) + %1 = tail call i8* @llvm.noalias.decl.p0i8.p0p0i32.i32(i32** %b.p, i32 0, metadata !11) + %2 = tail call i32* @llvm.side.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32* %_pA, i8* null, i32** %a.p, i32** undef, i32 0, metadata !11), !tbaa !9, !noalias !16 + store i32 42, i32* %_pA, noalias_sidechannel i32* %2, align 4, !tbaa !2, !noalias !16 + %3 = tail call i32* @llvm.side.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32* %_pB, i8* null, i32** %a.p, i32** undef, i32 0, metadata !11), !tbaa !9, !noalias !16 + store i32 99, i32* %_pB, noalias_sidechannel i32* %3, align 4, !tbaa !2, !noalias !16 + ret void +} +; CHECK-LABEL: Function: test_rp_rp_01: +; CHECK: MayAlias: store i32 99, i32* %_pB, noalias_sidechannel i32* %3, align 4, !tbaa !11, !noalias !9 <-> store i32 42, i32* %_pA, noalias_sidechannel i32* %2, align 4, !tbaa !11, !noalias !9 + +; Variants with different info -> NoAlias + +; Function Attrs: nounwind uwtable +define dso_local void @test_rp_rp_02(i32* nocapture %_pA, i32* nocapture %_pB) local_unnamed_addr #1 { +entry: + %a.p = alloca i32*, align 8 + %b.p = alloca i32*, align 8 + %0 = tail call i8* @llvm.noalias.decl.p0i8.p0p0i32.i32(i32** %a.p, i32 0, metadata !11) + %1 = tail call i8* @llvm.noalias.decl.p0i8.p0p0i32.i32(i32** %b.p, i32 0, metadata !11) + %2 = tail call i32* @llvm.side.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32* %_pA, i8* null, i32** %a.p, i32** undef, i32 0, metadata !11), !tbaa !9, !noalias !16 + store i32 42, i32* %_pA, noalias_sidechannel i32* %2, align 4, !tbaa !2, !noalias !16 + %3 = tail call i32* @llvm.side.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32* %_pB, i8* null, i32** %b.p, i32** undef, i32 0, metadata !11), !tbaa !9, !noalias !16 + store i32 99, i32* %_pB, noalias_sidechannel i32* %3, align 4, !tbaa !2, !noalias !16 + ret void +} +; CHECK-LABEL: Function: test_rp_rp_02: +; CHECK: NoAlias: store i32 99, i32* %_pB, noalias_sidechannel i32* %3, align 4, !tbaa !11, !noalias !9 <-> store i32 42, i32* %_pA, noalias_sidechannel i32* %2, align 4, !tbaa !11, !noalias !9 + +; Function Attrs: nounwind uwtable +define dso_local void @test_rp_rp_03(i32* nocapture %_pA, i32* nocapture %_pB) local_unnamed_addr #1 { +entry: + %a.p = alloca i32*, align 8 + %b.p = alloca i32*, align 8 + %0 = tail call i8* @llvm.noalias.decl.p0i8.p0p0i32.i32(i32** %a.p, i32 0, metadata !11) + %1 = tail call i8* @llvm.noalias.decl.p0i8.p0p0i32.i32(i32** %b.p, i32 0, metadata !11) + %2 = tail call i32* @llvm.side.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32* %_pA, i8* null, i32** %a.p, i32** undef, i32 0, metadata !11), !tbaa !9, !noalias !16 + store i32 42, i32* %_pA, noalias_sidechannel i32* %2, align 4, !tbaa !2, !noalias !16 + %3 = tail call i32* @llvm.side.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32* %_pB, i8* null, i32** %a.p, i32** undef, i32 1, metadata !11), !tbaa !9, !noalias !16 + store i32 99, i32* %_pB, noalias_sidechannel i32* %3, align 4, !tbaa !2, !noalias !16 + ret void +} +; CHECK-LABEL: Function: test_rp_rp_03: +; CHECK: NoAlias: store i32 99, i32* %_pB, noalias_sidechannel i32* %3, align 4, !tbaa !11, !noalias !9 <-> store i32 42, i32* %_pA, noalias_sidechannel i32* %2, align 4, !tbaa !11, !noalias !9 + +; Function Attrs: nounwind uwtable +define dso_local void @test_rp_rp_04(i32* nocapture %_pA, i32* nocapture %_pB) local_unnamed_addr #1 { +entry: + %a.p = alloca i32*, align 8 + %b.p = alloca i32*, align 8 + %0 = tail call i8* @llvm.noalias.decl.p0i8.p0p0i32.i32(i32** %a.p, i32 0, metadata !11) + %1 = tail call i8* @llvm.noalias.decl.p0i8.p0p0i32.i32(i32** %b.p, i32 0, metadata !11) + %2 = tail call i32* @llvm.side.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32* %_pA, i8* null, i32** %a.p, i32** undef, i32 0, metadata !11), !tbaa !9, !noalias !16 + store i32 42, i32* %_pA, noalias_sidechannel i32* %2, align 4, !tbaa !2, !noalias !16 + %3 = tail call i32* @llvm.side.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32* %_pB, i8* null, i32** %a.p, i32** undef, i32 0, metadata !14), !tbaa !9, !noalias !16 + store i32 99, i32* %_pB, noalias_sidechannel i32* %3, align 4, !tbaa !2, !noalias !16 + ret void +} +; CHECK-LABEL: Function: test_rp_rp_04: +; CHECK: NoAlias: store i32 99, i32* %_pB, noalias_sidechannel i32* %3, align 4, !tbaa !11, !noalias !9 <-> store i32 42, i32* %_pA, noalias_sidechannel i32* %2, align 4, !tbaa !11, !noalias !9 + + +; Function Attrs: nounwind readnone speculatable +declare i32* @llvm.side.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32*, i8*, i32**, i32**, i32, metadata) #3 + +attributes #0 = { nofree norecurse nounwind uwtable writeonly "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { nounwind uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #2 = { argmemonly nounwind } +attributes #3 = { nounwind readnone speculatable } + +!llvm.module.flags = !{!0} +!llvm.ident = !{!1} + +!0 = !{i32 1, !"wchar_size", i32 4} +!1 = !{!"clang"} +!2 = !{!3, !3, i64 0} +!3 = !{!"int", !4, i64 0} +!4 = !{!"omnipotent char", !5, i64 0} +!5 = !{!"Simple C/C++ TBAA"} +!6 = !{!7} +!7 = distinct !{!7, !8, !"test_rp_p: pA"} +!8 = distinct !{!8, !"test_rp_p"} +!9 = !{!10, !10, i64 0} +!10 = !{!"any pointer", !4, i64 0} +!11 = !{!12} +!12 = distinct !{!12, !13, !"test_rp_rp: pA"} +!13 = distinct !{!13, !"test_rp_rp"} +!14 = !{!15} +!15 = distinct !{!15, !13, !"test_rp_rp: pB"} +!16 = !{!12, !15} Index: llvm/test/Analysis/ScopedNoAliasAA/noalias_member.ll =================================================================== --- /dev/null +++ llvm/test/Analysis/ScopedNoAliasAA/noalias_member.ll @@ -0,0 +1,64 @@ +; RUN: opt < %s -basicaa -scoped-noalias -aa-eval -evaluate-aa-metadata -print-all-alias-modref-info -disable-output 2>&1 | FileCheck %s +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +%struct.FOO = type { i32*, i32* } + +; Function Attrs: nofree nounwind +define dso_local void @test_prp0_prp1(i32** nocapture %_pA) local_unnamed_addr #0 !noalias !2 { +entry: + %0 = load i32*, i32** %_pA, noalias_sidechannel i32** undef, align 4, !tbaa !5, !noalias !2 + %1 = tail call i32* @llvm.side.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32* %0, i8* null, i32** %_pA, i32** undef, i32 0, metadata !2), !tbaa !5, !noalias !2 + %arrayidx1 = getelementptr inbounds i32*, i32** %_pA, i32 1 + %2 = load i32*, i32** %arrayidx1, noalias_sidechannel i32** undef, align 4, !tbaa !5, !noalias !2 + %3 = tail call i32* @llvm.side.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32* %2, i8* null, i32** nonnull %arrayidx1, i32** undef, i32 0, metadata !2), !tbaa !5, !noalias !2 + store i32 42, i32* %0, noalias_sidechannel i32* %1, align 4, !tbaa !9, !noalias !2 + store i32 99, i32* %2, noalias_sidechannel i32* %3, align 4, !tbaa !9, !noalias !2 + ret void +} +; CHECK-LABEL: Function: test_prp0_prp1: +; CHECK: NoAlias: store i32 99, i32* %2, noalias_sidechannel i32* %3, align 4, !tbaa !9, !noalias !2 <-> store i32 42, i32* %0, noalias_sidechannel i32* %1, align 4, !tbaa !9, !noalias !2 + +; Function Attrs: nofree nounwind +define dso_local void @test_prS0_prS1(%struct.FOO* nocapture %_pS) local_unnamed_addr #0 !noalias !11 { +entry: + %mpA = getelementptr inbounds %struct.FOO, %struct.FOO* %_pS, i32 0, i32 0 + %0 = load i32*, i32** %mpA, noalias_sidechannel i32** undef, align 4, !tbaa !14, !noalias !11 + %1 = tail call i32* @llvm.side.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32* %0, i8* null, i32** %mpA, i32** undef, i32 0, metadata !11), !tbaa !14, !noalias !11 + %mpB = getelementptr inbounds %struct.FOO, %struct.FOO* %_pS, i32 0, i32 1 + %2 = load i32*, i32** %mpB, noalias_sidechannel i32** undef, align 4, !tbaa !16, !noalias !11 + %3 = tail call i32* @llvm.side.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32* %2, i8* null, i32** nonnull %mpB, i32** undef, i32 0, metadata !11), !tbaa !16, !noalias !11 + store i32 42, i32* %0, noalias_sidechannel i32* %1, align 4, !tbaa !9, !noalias !11 + store i32 99, i32* %2, noalias_sidechannel i32* %3, align 4, !tbaa !9, !noalias !11 + ret void +} +; CHECK-LABEL: Function: test_prS0_prS1: +; CHECK: NoAlias: store i32 99, i32* %2, noalias_sidechannel i32* %3, align 4, !tbaa !11, !noalias !2 <-> store i32 42, i32* %0, noalias_sidechannel i32* %1, align 4, !tbaa !11, !noalias !2 + + +; Function Attrs: nounwind readnone speculatable +declare i32* @llvm.side.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32*, i8*, i32**, i32**, i32, metadata) #1 + +attributes #0 = { nofree nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { nounwind readnone speculatable } + +!llvm.module.flags = !{!0} +!llvm.ident = !{!1} + +!0 = !{i32 1, !"wchar_size", i32 4} +!1 = !{!"clang"} +!2 = !{!3} +!3 = distinct !{!3, !4, !"test_prp0_prp1: unknown scope"} +!4 = distinct !{!4, !"test_prp0_prp1"} +!5 = !{!6, !6, i64 0, i64 4} +!6 = !{!7, i64 4, !"any pointer"} +!7 = !{!8, i64 1, !"omnipotent char"} +!8 = !{!"Simple C/C++ TBAA"} +!9 = !{!10, !10, i64 0, i64 4} +!10 = !{!7, i64 4, !"int"} +!11 = !{!12} +!12 = distinct !{!12, !13, !"test_prS0_prS1: unknown scope"} +!13 = distinct !{!13, !"test_prS0_prS1"} +!14 = !{!15, !6, i64 0, i64 4} +!15 = !{!7, i64 8, !"FOO", !6, i64 0, i64 4, !6, i64 4, i64 4} +!16 = !{!15, !6, i64 4, i64 4} Index: llvm/test/Analysis/ScopedNoAliasAA/noalias_phi.ll =================================================================== --- /dev/null +++ llvm/test/Analysis/ScopedNoAliasAA/noalias_phi.ll @@ -0,0 +1,230 @@ +; RUN: opt < %s -basicaa -scoped-noalias -aa-eval -evaluate-aa-metadata -print-all-alias-modref-info -disable-output 2>&1 | FileCheck %s +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +; Function Attrs: nofree norecurse nounwind writeonly +define dso_local void @test_phi_p_p_p(i32* nocapture %_pA, i32* nocapture %_pB, i32* nocapture %_pC, i32 %c) local_unnamed_addr #0 { +entry: + %tobool = icmp eq i32 %c, 0 + br i1 %tobool, label %cond.false, label %cond.true + +cond.true: ; preds = %entry + br label %cond.end + +cond.false: ; preds = %entry + br label %cond.end + +cond.end: ; preds = %cond.false, %cond.true + %cond = phi i32* [ %_pA, %cond.true ], [ %_pB, %cond.false ] + store i32 42, i32* %cond, noalias_sidechannel i32* undef, align 4, !tbaa !2 + store i32 99, i32* %_pC, noalias_sidechannel i32* undef, align 4, !tbaa !2 + ret void +} +; CHECK-LABEL: Function: test_phi_p_p_p: +; CHECK: MayAlias: store i32 99, i32* %_pC, noalias_sidechannel i32* undef, align 4, !tbaa !2 <-> store i32 42, i32* %cond, noalias_sidechannel i32* undef, align 4, !tbaa !2 + +; Function Attrs: nounwind +define dso_local void @test_phi_rp_p_p(i32* nocapture %_pA, i32* nocapture %_pB, i32* nocapture %_pC, i32 %c) local_unnamed_addr #1 { +entry: + %0 = tail call i8* @llvm.noalias.decl.p0i8.p0p0i32.i32(i32** null, i32 0, metadata !6) + %tobool = icmp ne i32 %c, 0 + %1 = tail call i32* @llvm.side.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32* %_pA, i8* %0, i32** null, i32** undef, i32 0, metadata !6) + br i1 %tobool, label %cond.false, label %cond.true + +cond.true: ; preds = %entry + br label %cond.end + +cond.false: ; preds = %entry + br label %cond.end + +cond.end: ; preds = %cond.false, %cond.true + %cond = phi i32* [ %_pA, %cond.true ], [ %_pB, %cond.false ] + %side.cond = phi i32* [ %1, %cond.true ], [ %_pB, %cond.false ] + store i32 42, i32* %cond, noalias_sidechannel i32* %side.cond, align 4, !tbaa !2, !noalias !6 + store i32 99, i32* %_pC, noalias_sidechannel i32* undef, align 4, !tbaa !2, !noalias !6 + ret void +} +; CHECK-LABEL: Function: test_phi_rp_p_p: +; CHECK: MayAlias: store i32 99, i32* %_pC, noalias_sidechannel i32* undef, align 4, !tbaa !5, !noalias !2 <-> store i32 42, i32* %cond, noalias_sidechannel i32* %side.cond, align 4, !tbaa !5, !noalias !2 + + +; Function Attrs: argmemonly nounwind +declare i8* @llvm.noalias.decl.p0i8.p0p0i32.i32(i32**, i32, metadata) #2 + +; Function Attrs: nounwind +define dso_local void @test_phi_p_rp_p(i32* nocapture %_pA, i32* nocapture %_pB, i32* nocapture %_pC, i32 %c) local_unnamed_addr #1 { +entry: + %0 = tail call i8* @llvm.noalias.decl.p0i8.p0p0i32.i32(i32** null, i32 0, metadata !9) + %tobool = icmp ne i32 %c, 0 + %1 = tail call i32* @llvm.side.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32* %_pB, i8* %0, i32** null, i32** undef, i32 0, metadata !9) + br i1 %tobool, label %cond.false, label %cond.true + +cond.true: ; preds = %entry + br label %cond.end + +cond.false: ; preds = %entry + br label %cond.end + +cond.end: ; preds = %cond.false, %cond.true + %cond = phi i32* [ %_pA, %cond.true ], [ %_pB, %cond.false ] + %side.cond = phi i32* [ %_pA, %cond.true ], [ %1, %cond.false ] + store i32 42, i32* %cond, noalias_sidechannel i32* %side.cond, align 4, !tbaa !2, !noalias !9 + store i32 99, i32* %_pC, noalias_sidechannel i32* undef, align 4, !tbaa !2, !noalias !9 + ret void +} +; CHECK-LABEL: Function: test_phi_p_rp_p: +; CHECK: MayAlias: store i32 99, i32* %_pC, noalias_sidechannel i32* undef, align 4, !tbaa !5, !noalias !2 <-> store i32 42, i32* %cond, noalias_sidechannel i32* %side.cond, align 4, !tbaa !5, !noalias !2 + +; Function Attrs: nounwind +define dso_local void @test_phi_rp_rp_p(i32* nocapture %_pA, i32* nocapture %_pB, i32* nocapture %_pC, i32 %c) local_unnamed_addr #1 { +entry: + %0 = tail call i8* @llvm.noalias.decl.p0i8.p0p0i32.i32(i32** null, i32 0, metadata !12) + %1 = tail call i8* @llvm.noalias.decl.p0i8.p0p0i32.i32(i32** null, i32 0, metadata !15) + %tobool = icmp ne i32 %c, 0 + %2 = tail call i32* @llvm.side.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32* %_pA, i8* %0, i32** null, i32** undef, i32 0, metadata !12) + %3 = tail call i32* @llvm.side.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32* %_pB, i8* %1, i32** null, i32** undef, i32 0, metadata !15) + br i1 %tobool, label %cond.false, label %cond.true + +cond.true: ; preds = %entry + br label %cond.end + +cond.false: ; preds = %entry + br label %cond.end + +cond.end: ; preds = %cond.false, %cond.true + %cond = phi i32* [ %_pA, %cond.true ], [ %_pB, %cond.false ] + %side.cond = phi i32* [ %2, %cond.true ], [ %3, %cond.false ] + store i32 42, i32* %cond, noalias_sidechannel i32* %side.cond, align 4, !tbaa !2, !noalias !17 + store i32 99, i32* %_pC, noalias_sidechannel i32* undef, align 4, !tbaa !2, !noalias !17 + ret void +} +; CHECK-LABEL: Function: test_phi_rp_rp_p: +; CHECK: NoAlias: store i32 99, i32* %_pC, noalias_sidechannel i32* undef, align 4, !tbaa !7, !noalias !11 <-> store i32 42, i32* %cond, noalias_sidechannel i32* %side.cond, align 4, !tbaa !7, !noalias !11 + +; Function Attrs: nounwind +define dso_local void @test_phi_p_p_rp(i32* nocapture %_pA, i32* nocapture %_pB, i32* nocapture %_pC, i32 %c) local_unnamed_addr #1 { +entry: + %0 = tail call i8* @llvm.noalias.decl.p0i8.p0p0i32.i32(i32** null, i32 0, metadata !18) + %tobool = icmp eq i32 %c, 0 + br i1 %tobool, label %cond.false, label %cond.true + +cond.true: ; preds = %entry + br label %cond.end + +cond.false: ; preds = %entry + br label %cond.end + +cond.end: ; preds = %cond.false, %cond.true + %cond = phi i32* [ %_pA, %cond.true ], [ %_pB, %cond.false ] + store i32 42, i32* %cond, noalias_sidechannel i32* undef, align 4, !tbaa !2, !noalias !18 + %1 = tail call i32* @llvm.side.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32* %_pC, i8* %0, i32** null, i32** undef, i32 0, metadata !18), !tbaa !21, !noalias !18 + store i32 99, i32* %_pC, noalias_sidechannel i32* %1, align 4, !tbaa !2, !noalias !18 + ret void +} +; CHECK-LABEL: Function: test_phi_p_p_rp: +; CHECK: NoAlias: store i32 99, i32* %_pC, noalias_sidechannel i32* %1, align 4, !tbaa !5, !noalias !2 <-> store i32 42, i32* %cond, noalias_sidechannel i32* undef, align 4, !tbaa !5, !noalias !2 + +; Function Attrs: nounwind +define dso_local void @test_phi_rp_rp_rp_01(i32* nocapture %_pA, i32* nocapture %_pB, i32* nocapture %_pC, i32 %c) local_unnamed_addr #1 { +entry: + %0 = tail call i8* @llvm.noalias.decl.p0i8.p0p0i32.i32(i32** null, i32 0, metadata !23) + %1 = tail call i8* @llvm.noalias.decl.p0i8.p0p0i32.i32(i32** null, i32 0, metadata !26) + %2 = tail call i8* @llvm.noalias.decl.p0i8.p0p0i32.i32(i32** null, i32 0, metadata !28) + %tobool = icmp ne i32 %c, 0 + %3 = tail call i32* @llvm.side.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32* %_pA, i8* %0, i32** null, i32** undef, i32 0, metadata !23) + %4 = tail call i32* @llvm.side.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32* %_pB, i8* %1, i32** null, i32** undef, i32 0, metadata !26) + br i1 %tobool, label %cond.false, label %cond.true + +cond.true: ; preds = %entry + br label %cond.end + +cond.false: ; preds = %entry + br label %cond.end + +cond.end: ; preds = %cond.false, %cond.true + %cond = phi i32* [ %_pA, %cond.true ], [ %_pB, %cond.false ] + %side.cond = phi i32* [ %3, %cond.true ], [ %4, %cond.false ] + store i32 42, i32* %cond, noalias_sidechannel i32* %side.cond, align 4, !tbaa !2, !noalias !30 + %5 = tail call i32* @llvm.side.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32* %_pC, i8* %2, i32** null, i32** undef, i32 0, metadata !28), !tbaa !21, !noalias !30 + store i32 99, i32* %_pC, noalias_sidechannel i32* %5, align 4, !tbaa !2, !noalias !30 + ret void +} + +; CHECK-LABEL: Function: test_phi_rp_rp_rp_01: +; CHECK: NoAlias: store i32 99, i32* %_pC, noalias_sidechannel i32* %5, align 4, !tbaa !9, !noalias !13 <-> store i32 42, i32* %cond, noalias_sidechannel i32* %side.cond, align 4, !tbaa !9, !noalias !13 + +; Function Attrs: nounwind +define dso_local void @test_phi_rp_rp_rp_02(i32* nocapture %_pA, i32* nocapture readnone %_pB, i32* nocapture %_pC, i32 %c) local_unnamed_addr #1 { +entry: + %0 = tail call i8* @llvm.noalias.decl.p0i8.p0p0i32.i32(i32** null, i32 0, metadata !31) + %1 = tail call i8* @llvm.noalias.decl.p0i8.p0p0i32.i32(i32** null, i32 0, metadata !34) + %tobool = icmp ne i32 %c, 0 + %2 = tail call i32* @llvm.side.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32* %_pA, i8* %0, i32** null, i32** undef, i32 0, metadata !31) + %3 = tail call i32* @llvm.side.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32* %_pC, i8* %1, i32** null, i32** undef, i32 0, metadata !34) + br i1 %tobool, label %cond.false, label %cond.true + +cond.true: ; preds = %entry + br label %cond.end + +cond.false: ; preds = %entry + br label %cond.end + +cond.end: ; preds = %cond.false, %cond.true + %cond = phi i32* [ %_pA, %cond.true ], [ %_pC, %cond.false ] + %side.cond = phi i32* [ %2, %cond.true ], [ %3, %cond.false ] + store i32 42, i32* %cond, noalias_sidechannel i32* %side.cond, align 4, !tbaa !2, !noalias !36 + store i32 99, i32* %_pC, noalias_sidechannel i32* %3, align 4, !tbaa !2, !noalias !36 + ret void +} +; CHECK-LABEL: Function: test_phi_rp_rp_rp_02: +; CHECK: MayAlias: store i32 99, i32* %_pC, noalias_sidechannel i32* %3, align 4, !tbaa !7, !noalias !11 <-> store i32 42, i32* %cond, noalias_sidechannel i32* %side.cond, align 4, !tbaa !7, !noalias !11 + +; Function Attrs: nounwind readnone speculatable +declare i32* @llvm.side.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32*, i8*, i32**, i32**, i32, metadata) #3 + +attributes #0 = { nofree norecurse nounwind writeonly "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #2 = { argmemonly nounwind } +attributes #3 = { nounwind readnone speculatable } + +!llvm.module.flags = !{!0} +!llvm.ident = !{!1} + +!0 = !{i32 1, !"wchar_size", i32 4} +!1 = !{!"clang"} +!2 = !{!3, !3, i64 0, i64 4} +!3 = !{!4, i64 4, !"int"} +!4 = !{!5, i64 1, !"omnipotent char"} +!5 = !{!"Simple C/C++ TBAA"} +!6 = !{!7} +!7 = distinct !{!7, !8, !"test_phi_rp_p_p: pA"} +!8 = distinct !{!8, !"test_phi_rp_p_p"} +!9 = !{!10} +!10 = distinct !{!10, !11, !"test_phi_p_rp_p: pB"} +!11 = distinct !{!11, !"test_phi_p_rp_p"} +!12 = !{!13} +!13 = distinct !{!13, !14, !"test_phi_rp_rp_p: pA"} +!14 = distinct !{!14, !"test_phi_rp_rp_p"} +!15 = !{!16} +!16 = distinct !{!16, !14, !"test_phi_rp_rp_p: pB"} +!17 = !{!13, !16} +!18 = !{!19} +!19 = distinct !{!19, !20, !"test_phi_p_p_rp: pC"} +!20 = distinct !{!20, !"test_phi_p_p_rp"} +!21 = !{!22, !22, i64 0, i64 4} +!22 = !{!4, i64 4, !"any pointer"} +!23 = !{!24} +!24 = distinct !{!24, !25, !"test_phi_rp_rp_rp_01: pA"} +!25 = distinct !{!25, !"test_phi_rp_rp_rp_01"} +!26 = !{!27} +!27 = distinct !{!27, !25, !"test_phi_rp_rp_rp_01: pB"} +!28 = !{!29} +!29 = distinct !{!29, !25, !"test_phi_rp_rp_rp_01: pC"} +!30 = !{!24, !27, !29} +!31 = !{!32} +!32 = distinct !{!32, !33, !"test_phi_rp_rp_rp_02: pA"} +!33 = distinct !{!33, !"test_phi_rp_rp_rp_02"} +!34 = !{!35} +!35 = distinct !{!35, !33, !"test_phi_rp_rp_rp_02: pC"} +!36 = !{!32, !37, !35} +!37 = distinct !{!37, !33, !"test_phi_rp_rp_rp_02: pB"} Index: llvm/test/Analysis/ScopedNoAliasAA/noalias_phi_in_loop.ll =================================================================== --- /dev/null +++ llvm/test/Analysis/ScopedNoAliasAA/noalias_phi_in_loop.ll @@ -0,0 +1,154 @@ +; RUN: opt < %s -basicaa -scoped-noalias -aa-eval -evaluate-aa-metadata -print-all-alias-modref-info -disable-output 2>&1 | FileCheck %s +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +; Function Attrs: nounwind +define dso_local void @test_complex_phi_01(i32* nocapture %_pA, i32** nocapture readonly %_pB, i32 %n) local_unnamed_addr #0 { +entry: + %0 = tail call i8* @llvm.noalias.decl.p0i8.p0p0i32.i32(i32** null, i32 0, metadata !2) + %1 = tail call i32* @llvm.side.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32* %_pA, i8* %0, i32** null, i32** undef, i32 0, metadata !2), !tbaa !5, !noalias !2 + %2 = load i32*, i32** %_pB, noalias_sidechannel i32** undef, align 4, !tbaa !5, !noalias !2 + %arrayidx1 = getelementptr inbounds i32*, i32** %_pB, i32 1 + %3 = load i32*, i32** %arrayidx1, noalias_sidechannel i32** undef, align 4, !tbaa !5, !noalias !2 + %arrayidx2 = getelementptr inbounds i32*, i32** %_pB, i32 2 + %4 = load i32*, i32** %arrayidx2, noalias_sidechannel i32** undef, align 4, !tbaa !5, !noalias !2 + %arrayidx3 = getelementptr inbounds i32*, i32** %_pB, i32 3 + %5 = load i32*, i32** %arrayidx3, noalias_sidechannel i32** undef, align 4, !tbaa !5, !noalias !2 + %arrayidx4 = getelementptr inbounds i32*, i32** %_pB, i32 4 + %6 = load i32*, i32** %arrayidx4, noalias_sidechannel i32** undef, align 4, !tbaa !5, !noalias !2 + %arrayidx5 = getelementptr inbounds i32*, i32** %_pB, i32 5 + %7 = load i32*, i32** %arrayidx5, noalias_sidechannel i32** undef, align 4, !tbaa !5, !noalias !2 + %arrayidx6 = getelementptr inbounds i32*, i32** %_pB, i32 6 + %8 = load i32*, i32** %arrayidx6, noalias_sidechannel i32** undef, align 4, !tbaa !5, !noalias !2 + %arrayidx7 = getelementptr inbounds i32*, i32** %_pB, i32 7 + %9 = load i32*, i32** %arrayidx7, noalias_sidechannel i32** undef, align 4, !tbaa !5, !noalias !2 + %arrayidx8 = getelementptr inbounds i32*, i32** %_pB, i32 8 + %10 = load i32*, i32** %arrayidx8, noalias_sidechannel i32** undef, align 4, !tbaa !5, !noalias !2 + %arrayidx9 = getelementptr inbounds i32*, i32** %_pB, i32 9 + %11 = load i32*, i32** %arrayidx9, noalias_sidechannel i32** undef, align 4, !tbaa !5, !noalias !2 + br label %for.cond + +for.cond: ; preds = %for.cond, %entry + %side.pTmp00.0 = phi i32* [ %2, %entry ], [ %side.pTmp01.0, %for.cond ] + %pTmp00.0 = phi i32* [ %2, %entry ], [ %pTmp01.0, %for.cond ] + %side.pTmp01.0 = phi i32* [ %3, %entry ], [ %side.pTmp02.0, %for.cond ] + %pTmp01.0 = phi i32* [ %3, %entry ], [ %pTmp02.0, %for.cond ] + %side.pTmp02.0 = phi i32* [ %4, %entry ], [ %side.pTmp03.0, %for.cond ] + %pTmp02.0 = phi i32* [ %4, %entry ], [ %pTmp03.0, %for.cond ] + %side.pTmp03.0 = phi i32* [ %5, %entry ], [ %side.pTmp04.0, %for.cond ] + %pTmp03.0 = phi i32* [ %5, %entry ], [ %pTmp04.0, %for.cond ] + %side.pTmp04.0 = phi i32* [ %6, %entry ], [ %side.pTmp05.0, %for.cond ] + %pTmp04.0 = phi i32* [ %6, %entry ], [ %pTmp05.0, %for.cond ] + %side.pTmp05.0 = phi i32* [ %7, %entry ], [ %side.pTmp06.0, %for.cond ] + %pTmp05.0 = phi i32* [ %7, %entry ], [ %pTmp06.0, %for.cond ] + %side.pTmp06.0 = phi i32* [ %8, %entry ], [ %side.pTmp07.0, %for.cond ] + %pTmp06.0 = phi i32* [ %8, %entry ], [ %pTmp07.0, %for.cond ] + %side.pTmp07.0 = phi i32* [ %9, %entry ], [ %side.pTmp08.0, %for.cond ] + %pTmp07.0 = phi i32* [ %9, %entry ], [ %pTmp08.0, %for.cond ] + %side.pTmp08.0 = phi i32* [ %10, %entry ], [ %side.pTmp09.0, %for.cond ] + %pTmp08.0 = phi i32* [ %10, %entry ], [ %pTmp09.0, %for.cond ] + %side.pTmp09.0 = phi i32* [ %11, %entry ], [ %1, %for.cond ] + %pTmp09.0 = phi i32* [ %11, %entry ], [ %_pA, %for.cond ] + %i.0 = phi i32 [ 0, %entry ], [ %inc, %for.cond ] + %cmp = icmp slt i32 %i.0, %n + %inc = add nuw nsw i32 %i.0, 1 + br i1 %cmp, label %for.cond, label %for.cond.cleanup + +for.cond.cleanup: ; preds = %for.cond + store i32 99, i32* %_pA, noalias_sidechannel i32* %1, align 4, !tbaa !9, !noalias !2 + store i32 42, i32* %pTmp00.0, noalias_sidechannel i32* %side.pTmp00.0, align 4, !tbaa !9, !noalias !2 + ret void +} + +; CHECK-LABEL: Function: test_complex_phi_01: +; CHECK: MayAlias: store i32 42, i32* %pTmp00.0, noalias_sidechannel i32* %side.pTmp00.0, align 4, !tbaa !9, !noalias !2 <-> store i32 99, i32* %_pA, noalias_sidechannel i32* %1, align 4, !tbaa !9, !noalias !2 + + +; Adapted version where the sidechannel chains don't collapse +; Function Attrs: nounwind +define dso_local void @test_complex_phi_02(i32* nocapture %_pA, i32** nocapture readonly %_pB, i32 %n) local_unnamed_addr #0 { +entry: + %0 = tail call i8* @llvm.noalias.decl.p0i8.p0p0i32.i32(i32** null, i32 0, metadata !2) + %decl2 = tail call i8* @llvm.noalias.decl.p0i8.p0p0i32.i32(i32** null, i32 1, metadata !2) + %1 = tail call i32* @llvm.side.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32* %_pA, i8* %0, i32** null, i32** undef, i32 0, metadata !2), !tbaa !5, !noalias !2 + %extra_side = tail call i32* @llvm.side.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32* %_pA, i8* %decl2, i32** null, i32** undef, i32 1, metadata !2), !tbaa !5, !noalias !2 + %2 = load i32*, i32** %_pB, noalias_sidechannel i32** undef, align 4, !tbaa !5, !noalias !2 + %arrayidx1 = getelementptr inbounds i32*, i32** %_pB, i32 1 + %3 = load i32*, i32** %arrayidx1, noalias_sidechannel i32** undef, align 4, !tbaa !5, !noalias !2 + %arrayidx2 = getelementptr inbounds i32*, i32** %_pB, i32 2 + %4 = load i32*, i32** %arrayidx2, noalias_sidechannel i32** undef, align 4, !tbaa !5, !noalias !2 + %arrayidx3 = getelementptr inbounds i32*, i32** %_pB, i32 3 + %5 = load i32*, i32** %arrayidx3, noalias_sidechannel i32** undef, align 4, !tbaa !5, !noalias !2 + %arrayidx4 = getelementptr inbounds i32*, i32** %_pB, i32 4 + %6 = load i32*, i32** %arrayidx4, noalias_sidechannel i32** undef, align 4, !tbaa !5, !noalias !2 + %arrayidx5 = getelementptr inbounds i32*, i32** %_pB, i32 5 + %7 = load i32*, i32** %arrayidx5, noalias_sidechannel i32** undef, align 4, !tbaa !5, !noalias !2 + %arrayidx6 = getelementptr inbounds i32*, i32** %_pB, i32 6 + %8 = load i32*, i32** %arrayidx6, noalias_sidechannel i32** undef, align 4, !tbaa !5, !noalias !2 + %arrayidx7 = getelementptr inbounds i32*, i32** %_pB, i32 7 + %9 = load i32*, i32** %arrayidx7, noalias_sidechannel i32** undef, align 4, !tbaa !5, !noalias !2 + %arrayidx8 = getelementptr inbounds i32*, i32** %_pB, i32 8 + %10 = load i32*, i32** %arrayidx8, noalias_sidechannel i32** undef, align 4, !tbaa !5, !noalias !2 + %arrayidx9 = getelementptr inbounds i32*, i32** %_pB, i32 9 + %11 = load i32*, i32** %arrayidx9, noalias_sidechannel i32** undef, align 4, !tbaa !5, !noalias !2 + br label %for.cond + +for.cond: ; preds = %for.cond, %entry + %side.pTmp00.0 = phi i32* [ %2, %entry ], [ %side.pTmp01.0, %for.cond ] + %pTmp00.0 = phi i32* [ %2, %entry ], [ %pTmp01.0, %for.cond ] + %side.pTmp01.0 = phi i32* [ %3, %entry ], [ %side.pTmp02.0, %for.cond ] + %pTmp01.0 = phi i32* [ %3, %entry ], [ %pTmp02.0, %for.cond ] + %side.pTmp02.0 = phi i32* [ %4, %entry ], [ %side.pTmp03.0, %for.cond ] + %pTmp02.0 = phi i32* [ %4, %entry ], [ %pTmp03.0, %for.cond ] + %side.pTmp03.0 = phi i32* [ %5, %entry ], [ %side.pTmp04.0, %for.cond ] + %pTmp03.0 = phi i32* [ %5, %entry ], [ %pTmp04.0, %for.cond ] + %side.pTmp04.0 = phi i32* [ %6, %entry ], [ %side.pTmp05.0, %for.cond ] + %pTmp04.0 = phi i32* [ %6, %entry ], [ %pTmp05.0, %for.cond ] + %side.pTmp05.0 = phi i32* [ %7, %entry ], [ %side.pTmp06.0, %for.cond ] + %pTmp05.0 = phi i32* [ %7, %entry ], [ %pTmp06.0, %for.cond ] + %side.pTmp06.0 = phi i32* [ %8, %entry ], [ %side.pTmp07.0, %for.cond ] + %pTmp06.0 = phi i32* [ %8, %entry ], [ %pTmp07.0, %for.cond ] + %side.pTmp07.0 = phi i32* [ %9, %entry ], [ %side.pTmp08.0, %for.cond ] + %pTmp07.0 = phi i32* [ %9, %entry ], [ %pTmp08.0, %for.cond ] + %side.pTmp08.0 = phi i32* [ %10, %entry ], [ %side.pTmp09.0, %for.cond ] + %pTmp08.0 = phi i32* [ %10, %entry ], [ %pTmp09.0, %for.cond ] + %side.pTmp09.0 = phi i32* [ %11, %entry ], [ %extra_side, %for.cond ] + %pTmp09.0 = phi i32* [ %11, %entry ], [ %_pA, %for.cond ] + %i.0 = phi i32 [ 0, %entry ], [ %inc, %for.cond ] + %cmp = icmp slt i32 %i.0, %n + %inc = add nuw nsw i32 %i.0, 1 + br i1 %cmp, label %for.cond, label %for.cond.cleanup + +for.cond.cleanup: ; preds = %for.cond + store i32 99, i32* %_pA, noalias_sidechannel i32* %1, align 4, !tbaa !9, !noalias !2 + store i32 42, i32* %pTmp00.0, noalias_sidechannel i32* %side.pTmp00.0, align 4, !tbaa !9, !noalias !2 + ret void +} + +; CHECK-LABEL: Function: test_complex_phi_02: +; CHECK: NoAlias: store i32 42, i32* %pTmp00.0, noalias_sidechannel i32* %side.pTmp00.0, align 4, !tbaa !9, !noalias !2 <-> store i32 99, i32* %_pA, noalias_sidechannel i32* %1, align 4, !tbaa !9, !noalias !2 + +; Function Attrs: argmemonly nounwind +declare i8* @llvm.noalias.decl.p0i8.p0p0i32.i32(i32**, i32, metadata) #1 + +; Function Attrs: nounwind readnone speculatable +declare i32* @llvm.side.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32*, i8*, i32**, i32**, i32, metadata) #2 + +attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { argmemonly nounwind } +attributes #2 = { nounwind readnone speculatable } + +!llvm.module.flags = !{!0} +!llvm.ident = !{!1} + +!0 = !{i32 1, !"wchar_size", i32 4} +!1 = !{!"clang"} +!2 = !{!3} +!3 = distinct !{!3, !4, !"test_complex_phi: rpTmp"} +!4 = distinct !{!4, !"test_complex_phi"} +!5 = !{!6, !6, i64 0, i64 4} +!6 = !{!7, i64 4, !"any pointer"} +!7 = !{!8, i64 1, !"omnipotent char"} +!8 = !{!"Simple C/C++ TBAA"} +!9 = !{!10, !10, i64 0, i64 4} +!10 = !{!7, i64 4, !"int"} Index: llvm/test/Analysis/ScopedNoAliasAA/noalias_recursive.ll =================================================================== --- /dev/null +++ llvm/test/Analysis/ScopedNoAliasAA/noalias_recursive.ll @@ -0,0 +1,127 @@ +; RUN: opt < %s -basicaa -scoped-noalias -aa-eval -evaluate-aa-metadata -print-all-alias-modref-info -disable-output 2>&1 | FileCheck %s +; RUN: opt < %s -aa-pipeline=basic-aa,scoped-noalias-aa -passes=aa-eval -evaluate-aa-metadata -print-all-alias-modref-info -disable-output 2>&1 | FileCheck %s +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +; Function Attrs: nounwind +define dso_local void @test_prp_prp(i32** nocapture readonly %_pA, i32** nocapture readonly %_pB) local_unnamed_addr #0 { +entry: + %0 = tail call i8* @llvm.noalias.decl.p0i8.p0p0p0i32.i64(i32*** null, i64 0, metadata !2) + %1 = tail call i8* @llvm.noalias.decl.p0i8.p0p0p0i32.i64(i32*** null, i64 0, metadata !5) + %2 = tail call i32** @llvm.side.noalias.p0p0i32.p0i8.p0p0p0i32.p0p0p0i32.i64(i32** %_pA, i8* %0, i32*** null, i32*** undef, i64 0, metadata !2), !tbaa !7, !noalias !11 + %3 = load i32*, i32** %_pA, noalias_sidechannel i32** %2, align 4, !tbaa !7, !noalias !11 + store i32 42, i32* %3, noalias_sidechannel i32* undef, align 4, !tbaa !12, !noalias !11 + %4 = tail call i32** @llvm.side.noalias.p0p0i32.p0i8.p0p0p0i32.p0p0p0i32.i64(i32** %_pB, i8* %1, i32*** null, i32*** undef, i64 0, metadata !5), !tbaa !7, !noalias !11 + %5 = load i32*, i32** %_pB, noalias_sidechannel i32** %4, align 4, !tbaa !7, !noalias !11 + store i32 99, i32* %5, noalias_sidechannel i32* undef, align 4, !tbaa !12, !noalias !11 + ret void +} +; CHECK-LABEL: Function: test_prp_prp: +; CHECK: MayAlias: store i32 99, i32* %5, noalias_sidechannel i32* undef, align 4, !tbaa !12, !noalias !11 <-> store i32 42, i32* %3, noalias_sidechannel i32* undef, align 4, !tbaa !12, !noalias !11 + +; Function Attrs: argmemonly nounwind +declare i8* @llvm.noalias.decl.p0i8.p0p0p0i32.i64(i32***, i64, metadata) #1 + +; Function Attrs: nofree nounwind +define dso_local void @test_rpp_rpp(i32** nocapture %_pA, i32** nocapture %_pB) local_unnamed_addr #2 !noalias !14 { +entry: + %0 = load i32*, i32** %_pA, noalias_sidechannel i32** undef, align 4, !tbaa !7, !noalias !14 + %1 = tail call i32* @llvm.side.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i64(i32* %0, i8* null, i32** %_pA, i32** undef, i64 0, metadata !14), !tbaa !7, !noalias !14 + store i32 42, i32* %0, noalias_sidechannel i32* %1, align 4, !tbaa !12, !noalias !14 + %2 = load i32*, i32** %_pB, noalias_sidechannel i32** undef, align 4, !tbaa !7, !noalias !14 + %3 = tail call i32* @llvm.side.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i64(i32* %2, i8* null, i32** %_pB, i32** undef, i64 0, metadata !14), !tbaa !7, !noalias !14 + store i32 99, i32* %2, noalias_sidechannel i32* %3, align 4, !tbaa !12, !noalias !14 + ret void +} +; CHECK-LABEL: Function: test_rpp_rpp: +; CHECK: MayAlias: store i32 99, i32* %2, noalias_sidechannel i32* %3, align 4, !tbaa !9, !noalias !2 <-> store i32 42, i32* %0, noalias_sidechannel i32* %1, align 4, !tbaa !9, !noalias !2 + +; Function Attrs: nounwind +define dso_local void @test_rprp_rprp(i32** nocapture %_pA, i32** nocapture %_pB) local_unnamed_addr #0 !noalias !17 { +entry: + %0 = tail call i8* @llvm.noalias.decl.p0i8.p0p0p0i32.i64(i32*** null, i64 0, metadata !20) + %1 = tail call i8* @llvm.noalias.decl.p0i8.p0p0p0i32.i64(i32*** null, i64 0, metadata !22) + %2 = tail call i32** @llvm.side.noalias.p0p0i32.p0i8.p0p0p0i32.p0p0p0i32.i64(i32** %_pA, i8* %0, i32*** null, i32*** undef, i64 0, metadata !20), !tbaa !7, !noalias !24 + %3 = load i32*, i32** %_pA, noalias_sidechannel i32** %2, align 4, !tbaa !7, !noalias !24 + %4 = tail call i32* @llvm.side.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i64(i32* %3, i8* null, i32** %_pA, i32** %2, i64 0, metadata !17), !tbaa !7, !noalias !24 + store i32 42, i32* %3, noalias_sidechannel i32* %4, align 4, !tbaa !12, !noalias !24 + %5 = tail call i32** @llvm.side.noalias.p0p0i32.p0i8.p0p0p0i32.p0p0p0i32.i64(i32** %_pB, i8* %1, i32*** null, i32*** undef, i64 0, metadata !22), !tbaa !7, !noalias !24 + %6 = load i32*, i32** %_pB, noalias_sidechannel i32** %5, align 4, !tbaa !7, !noalias !24 + %7 = tail call i32* @llvm.side.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i64(i32* %6, i8* null, i32** %_pB, i32** %5, i64 0, metadata !17), !tbaa !7, !noalias !24 + store i32 99, i32* %6, noalias_sidechannel i32* %7, align 4, !tbaa !12, !noalias !24 + ret void +} + +; CHECK-LABEL: Function: test_rprp_rprp: +; CHECK: NoAlias: store i32 99, i32* %6, noalias_sidechannel i32* %7, align 4, !tbaa !14, !noalias !13 <-> store i32 42, i32* %3, noalias_sidechannel i32* %4, align 4, !tbaa !14, !noalias !13 + +; Function Attrs: nounwind +define dso_local void @test_prp_01(i32** nocapture %pA) local_unnamed_addr #0 !noalias !17 { +entry: + %0 = load i32*, i32** %pA, noalias_sidechannel i32** undef, align 8, !tbaa !7, !noalias !17 + %1 = call i32* @llvm.side.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i64(i32* %0, i8* null, i32** %pA, i32** undef, i64 0, metadata !17), !tbaa !7, !noalias !17 + store i32 42, i32* %0, noalias_sidechannel i32* %1, align 4, !tbaa !12, !noalias !17 + %arrayidx1 = getelementptr inbounds i32*, i32** %pA, i64 0 + %2 = load i32*, i32** %arrayidx1, noalias_sidechannel i32** undef, align 8, !tbaa !7, !noalias !17 + %3 = call i32* @llvm.side.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i64(i32* %2, i8* null, i32** %arrayidx1, i32** undef, i64 0, metadata !17), !tbaa !7, !noalias !17 + store i32 43, i32* %2, noalias_sidechannel i32* %3, align 4, !tbaa !12, !noalias !17 + ret void +} + +; CHECK-LABEL: Function: test_prp_01: +; CHECK: MayAlias: store i32 43, i32* %2, noalias_sidechannel i32* %3, align 4, !tbaa !9, !noalias !2 <-> store i32 42, i32* %0, noalias_sidechannel i32* %1, align 4, !tbaa !9, !noalias !2 +; Function Attrs: nounwind +define dso_local void @test_prp_02(i32** nocapture %pA) local_unnamed_addr #0 !noalias !17 { +entry: + %0 = load i32*, i32** %pA, noalias_sidechannel i32** undef, align 8, !tbaa !7, !noalias !17 + %1 = call i32* @llvm.side.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i64(i32* %0, i8* null, i32** %pA, i32** undef, i64 0, metadata !17), !tbaa !7, !noalias !17 + store i32 42, i32* %0, noalias_sidechannel i32* %1, align 4, !tbaa !12, !noalias !17 + %arrayidx1 = getelementptr inbounds i32*, i32** %pA, i64 1 + %2 = load i32*, i32** %arrayidx1, noalias_sidechannel i32** undef, align 8, !tbaa !7, !noalias !17 + %3 = call i32* @llvm.side.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i64(i32* %2, i8* null, i32** %arrayidx1, i32** undef, i64 0, metadata !17), !tbaa !7, !noalias !17 + store i32 43, i32* %2, noalias_sidechannel i32* %3, align 4, !tbaa !12, !noalias !17 + ret void +} + +; CHECK-LABEL: Function: test_prp_02: +; CHECK: NoAlias: store i32 43, i32* %2, noalias_sidechannel i32* %3, align 4, !tbaa !9, !noalias !2 <-> store i32 42, i32* %0, noalias_sidechannel i32* %1, align 4, !tbaa !9, !noalias !2 + +; Function Attrs: nounwind readnone speculatable +declare i32** @llvm.side.noalias.p0p0i32.p0i8.p0p0p0i32.p0p0p0i32.i64(i32**, i8*, i32***, i32***, i64, metadata) #3 + +; Function Attrs: nounwind readnone speculatable +declare i32* @llvm.side.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i64(i32*, i8*, i32**, i32**, i64, metadata) #3 + +attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { argmemonly nounwind } +attributes #2 = { nofree nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #3 = { nounwind readnone speculatable } + +!llvm.module.flags = !{!0} +!llvm.ident = !{!1} + +!0 = !{i32 1, !"wchar_size", i32 4} +!1 = !{!"clang"} +!2 = !{!3} +!3 = distinct !{!3, !4, !"test_prp_prp: pA"} +!4 = distinct !{!4, !"test_prp_prp"} +!5 = !{!6} +!6 = distinct !{!6, !4, !"test_prp_prp: pB"} +!7 = !{!8, !8, i64 0, i64 4} +!8 = !{!9, i64 4, !"any pointer"} +!9 = !{!10, i64 1, !"omnipotent char"} +!10 = !{!"Simple C/C++ TBAA"} +!11 = !{!3, !6} +!12 = !{!13, !13, i64 0, i64 4} +!13 = !{!9, i64 4, !"int"} +!14 = !{!15} +!15 = distinct !{!15, !16, !"test_rpp_rpp: unknown scope"} +!16 = distinct !{!16, !"test_rpp_rpp"} +!17 = !{!18} +!18 = distinct !{!18, !19, !"test_rprp_rprp: unknown scope"} +!19 = distinct !{!19, !"test_rprp_rprp"} +!20 = !{!21} +!21 = distinct !{!21, !19, !"test_rprp_rprp: pA"} +!22 = !{!23} +!23 = distinct !{!23, !19, !"test_rprp_rprp: pB"} +!24 = !{!21, !23, !18} Index: llvm/test/Analysis/ScopedNoAliasAA/noalias_select.ll =================================================================== --- /dev/null +++ llvm/test/Analysis/ScopedNoAliasAA/noalias_select.ll @@ -0,0 +1,167 @@ +; RUN: opt < %s -basicaa -scoped-noalias -aa-eval -evaluate-aa-metadata -print-all-alias-modref-info -disable-output 2>&1 | FileCheck %s +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +; Function Attrs: nofree norecurse nounwind writeonly +define dso_local void @test_select_p_p_p(i32* nocapture %_pA, i32* nocapture %_pB, i32* nocapture %_pC, i32 %c) local_unnamed_addr #0 { +entry: + %tobool = icmp eq i32 %c, 0 + %cond = select i1 %tobool, i32* %_pB, i32* %_pA + store i32 42, i32* %cond, noalias_sidechannel i32* undef, align 4, !tbaa !2 + store i32 99, i32* %_pC, noalias_sidechannel i32* undef, align 4, !tbaa !2 + ret void +} +; CHECK-LABEL: Function: test_select_p_p_p: +; CHECK: MayAlias: store i32 99, i32* %_pC, noalias_sidechannel i32* undef, align 4, !tbaa !2 <-> store i32 42, i32* %cond, noalias_sidechannel i32* undef, align 4, !tbaa !2 + +; Function Attrs: nounwind +define dso_local void @test_select_rp_p_p(i32* nocapture %_pA, i32* nocapture %_pB, i32* nocapture %_pC, i32 %c) local_unnamed_addr #1 { +entry: + %0 = tail call i8* @llvm.noalias.decl.p0i8.p0p0i32.i32(i32** null, i32 0, metadata !6) + %tobool = icmp ne i32 %c, 0 + %1 = tail call i32* @llvm.side.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32* %_pA, i8* %0, i32** null, i32** undef, i32 0, metadata !6) + %side.cond = select i1 %tobool, i32* %1, i32* %_pB + %cond = select i1 %tobool, i32* %_pA, i32* %_pB + store i32 42, i32* %cond, noalias_sidechannel i32* %side.cond, align 4, !tbaa !2, !noalias !6 + store i32 99, i32* %_pC, noalias_sidechannel i32* undef, align 4, !tbaa !2, !noalias !6 + ret void +} +; CHECK-LABEL: Function: test_select_rp_p_p: +; CHECK: MayAlias: store i32 99, i32* %_pC, noalias_sidechannel i32* undef, align 4, !tbaa !5, !noalias !2 <-> store i32 42, i32* %cond, noalias_sidechannel i32* %side.cond, align 4, !tbaa !5, !noalias !2 + + +; Function Attrs: argmemonly nounwind +declare i8* @llvm.noalias.decl.p0i8.p0p0i32.i32(i32**, i32, metadata) #2 + +; Function Attrs: nounwind +define dso_local void @test_select_p_rp_p(i32* nocapture %_pA, i32* nocapture %_pB, i32* nocapture %_pC, i32 %c) local_unnamed_addr #1 { +entry: + %0 = tail call i8* @llvm.noalias.decl.p0i8.p0p0i32.i32(i32** null, i32 0, metadata !9) + %tobool = icmp ne i32 %c, 0 + %1 = tail call i32* @llvm.side.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32* %_pB, i8* %0, i32** null, i32** undef, i32 0, metadata !9) + %side.cond = select i1 %tobool, i32* %_pA, i32* %1 + %cond = select i1 %tobool, i32* %_pA, i32* %_pB + store i32 42, i32* %cond, noalias_sidechannel i32* %side.cond, align 4, !tbaa !2, !noalias !9 + store i32 99, i32* %_pC, noalias_sidechannel i32* undef, align 4, !tbaa !2, !noalias !9 + ret void +} +; CHECK-LABEL: Function: test_select_p_rp_p: +; CHECK: MayAlias: store i32 99, i32* %_pC, noalias_sidechannel i32* undef, align 4, !tbaa !5, !noalias !2 <-> store i32 42, i32* %cond, noalias_sidechannel i32* %side.cond, align 4, !tbaa !5, !noalias !2 + +; Function Attrs: nounwind +define dso_local void @test_select_rp_rp_p(i32* nocapture %_pA, i32* nocapture %_pB, i32* nocapture %_pC, i32 %c) local_unnamed_addr #1 { +entry: + %0 = tail call i8* @llvm.noalias.decl.p0i8.p0p0i32.i32(i32** null, i32 0, metadata !12) + %1 = tail call i8* @llvm.noalias.decl.p0i8.p0p0i32.i32(i32** null, i32 0, metadata !15) + %tobool = icmp ne i32 %c, 0 + %2 = tail call i32* @llvm.side.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32* %_pA, i8* %0, i32** null, i32** undef, i32 0, metadata !12) + %3 = tail call i32* @llvm.side.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32* %_pB, i8* %1, i32** null, i32** undef, i32 0, metadata !15) + %side.cond = select i1 %tobool, i32* %2, i32* %3 + %cond = select i1 %tobool, i32* %_pA, i32* %_pB + store i32 42, i32* %cond, noalias_sidechannel i32* %side.cond, align 4, !tbaa !2, !noalias !17 + store i32 99, i32* %_pC, noalias_sidechannel i32* undef, align 4, !tbaa !2, !noalias !17 + ret void +} +; CHECK-LABEL: Function: test_select_rp_rp_p: +; CHECK: NoAlias: store i32 99, i32* %_pC, noalias_sidechannel i32* undef, align 4, !tbaa !7, !noalias !11 <-> store i32 42, i32* %cond, noalias_sidechannel i32* %side.cond, align 4, !tbaa !7, !noalias !11 + +; Function Attrs: nounwind +define dso_local void @test_select_p_p_rp(i32* nocapture %_pA, i32* nocapture %_pB, i32* nocapture %_pC, i32 %c) local_unnamed_addr #1 { +entry: + %0 = tail call i8* @llvm.noalias.decl.p0i8.p0p0i32.i32(i32** null, i32 0, metadata !18) + %tobool = icmp eq i32 %c, 0 + %cond = select i1 %tobool, i32* %_pB, i32* %_pA + store i32 42, i32* %cond, noalias_sidechannel i32* undef, align 4, !tbaa !2, !noalias !18 + %1 = tail call i32* @llvm.side.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32* %_pC, i8* %0, i32** null, i32** undef, i32 0, metadata !18), !tbaa !21, !noalias !18 + store i32 99, i32* %_pC, noalias_sidechannel i32* %1, align 4, !tbaa !2, !noalias !18 + ret void +} +; CHECK-LABEL: Function: test_select_p_p_rp: +; CHECK: NoAlias: store i32 99, i32* %_pC, noalias_sidechannel i32* %1, align 4, !tbaa !5, !noalias !2 <-> store i32 42, i32* %cond, noalias_sidechannel i32* undef, align 4, !tbaa !5, !noalias !2 + +; Function Attrs: nounwind +define dso_local void @test_select_rp_rp_rp_01(i32* nocapture %_pA, i32* nocapture %_pB, i32* nocapture %_pC, i32 %c) local_unnamed_addr #1 { +entry: + %0 = tail call i8* @llvm.noalias.decl.p0i8.p0p0i32.i32(i32** null, i32 0, metadata !23) + %1 = tail call i8* @llvm.noalias.decl.p0i8.p0p0i32.i32(i32** null, i32 0, metadata !26) + %2 = tail call i8* @llvm.noalias.decl.p0i8.p0p0i32.i32(i32** null, i32 0, metadata !28) + %tobool = icmp ne i32 %c, 0 + %3 = tail call i32* @llvm.side.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32* %_pA, i8* %0, i32** null, i32** undef, i32 0, metadata !23) + %4 = tail call i32* @llvm.side.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32* %_pB, i8* %1, i32** null, i32** undef, i32 0, metadata !26) + %side.cond = select i1 %tobool, i32* %3, i32* %4 + %cond = select i1 %tobool, i32* %_pA, i32* %_pB + store i32 42, i32* %cond, noalias_sidechannel i32* %side.cond, align 4, !tbaa !2, !noalias !30 + %5 = tail call i32* @llvm.side.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32* %_pC, i8* %2, i32** null, i32** undef, i32 0, metadata !28), !tbaa !21, !noalias !30 + store i32 99, i32* %_pC, noalias_sidechannel i32* %5, align 4, !tbaa !2, !noalias !30 + ret void +} + +; CHECK-LABEL: Function: test_select_rp_rp_rp_01: +; CHECK: NoAlias: store i32 99, i32* %_pC, noalias_sidechannel i32* %5, align 4, !tbaa !9, !noalias !13 <-> store i32 42, i32* %cond, noalias_sidechannel i32* %side.cond, align 4, !tbaa !9, !noalias !13 + +; Function Attrs: nounwind +define dso_local void @test_select_rp_rp_rp_02(i32* nocapture %_pA, i32* nocapture readnone %_pB, i32* nocapture %_pC, i32 %c) local_unnamed_addr #1 { +entry: + %0 = tail call i8* @llvm.noalias.decl.p0i8.p0p0i32.i32(i32** null, i32 0, metadata !31) + %1 = tail call i8* @llvm.noalias.decl.p0i8.p0p0i32.i32(i32** null, i32 0, metadata !34) + %tobool = icmp ne i32 %c, 0 + %2 = tail call i32* @llvm.side.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32* %_pA, i8* %0, i32** null, i32** undef, i32 0, metadata !31) + %3 = tail call i32* @llvm.side.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32* %_pC, i8* %1, i32** null, i32** undef, i32 0, metadata !34) + %side.cond = select i1 %tobool, i32* %2, i32* %3 + %cond = select i1 %tobool, i32* %_pA, i32* %_pC + store i32 42, i32* %cond, noalias_sidechannel i32* %side.cond, align 4, !tbaa !2, !noalias !36 + store i32 99, i32* %_pC, noalias_sidechannel i32* %3, align 4, !tbaa !2, !noalias !36 + ret void +} +; CHECK-LABEL: Function: test_select_rp_rp_rp_02: +; CHECK: MayAlias: store i32 99, i32* %_pC, noalias_sidechannel i32* %3, align 4, !tbaa !7, !noalias !11 <-> store i32 42, i32* %cond, noalias_sidechannel i32* %side.cond, align 4, !tbaa !7, !noalias !11 + +; Function Attrs: nounwind readnone speculatable +declare i32* @llvm.side.noalias.p0i32.p0i8.p0p0i32.p0p0i32.i32(i32*, i8*, i32**, i32**, i32, metadata) #3 + +attributes #0 = { nofree norecurse nounwind writeonly "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #2 = { argmemonly nounwind } +attributes #3 = { nounwind readnone speculatable } + +!llvm.module.flags = !{!0} +!llvm.ident = !{!1} + +!0 = !{i32 1, !"wchar_size", i32 4} +!1 = !{!"clang"} +!2 = !{!3, !3, i64 0, i64 4} +!3 = !{!4, i64 4, !"int"} +!4 = !{!5, i64 1, !"omnipotent char"} +!5 = !{!"Simple C/C++ TBAA"} +!6 = !{!7} +!7 = distinct !{!7, !8, !"test_select_rp_p_p: pA"} +!8 = distinct !{!8, !"test_select_rp_p_p"} +!9 = !{!10} +!10 = distinct !{!10, !11, !"test_select_p_rp_p: pB"} +!11 = distinct !{!11, !"test_select_p_rp_p"} +!12 = !{!13} +!13 = distinct !{!13, !14, !"test_select_rp_rp_p: pA"} +!14 = distinct !{!14, !"test_select_rp_rp_p"} +!15 = !{!16} +!16 = distinct !{!16, !14, !"test_select_rp_rp_p: pB"} +!17 = !{!13, !16} +!18 = !{!19} +!19 = distinct !{!19, !20, !"test_select_p_p_rp: pC"} +!20 = distinct !{!20, !"test_select_p_p_rp"} +!21 = !{!22, !22, i64 0, i64 4} +!22 = !{!4, i64 4, !"any pointer"} +!23 = !{!24} +!24 = distinct !{!24, !25, !"test_select_rp_rp_rp_01: pA"} +!25 = distinct !{!25, !"test_select_rp_rp_rp_01"} +!26 = !{!27} +!27 = distinct !{!27, !25, !"test_select_rp_rp_rp_01: pB"} +!28 = !{!29} +!29 = distinct !{!29, !25, !"test_select_rp_rp_rp_01: pC"} +!30 = !{!24, !27, !29} +!31 = !{!32} +!32 = distinct !{!32, !33, !"test_select_rp_rp_rp_02: pA"} +!33 = distinct !{!33, !"test_select_rp_rp_rp_02"} +!34 = !{!35} +!35 = distinct !{!35, !33, !"test_select_rp_rp_rp_02: pC"} +!36 = !{!32, !37, !35} +!37 = distinct !{!37, !33, !"test_select_rp_rp_rp_02: pB"}