diff --git a/llvm/include/llvm/Transforms/IPO/Attributor.h b/llvm/include/llvm/Transforms/IPO/Attributor.h --- a/llvm/include/llvm/Transforms/IPO/Attributor.h +++ b/llvm/include/llvm/Transforms/IPO/Attributor.h @@ -250,6 +250,22 @@ return OAS.Offset + OAS.Size > Offset && OAS.Offset < Offset + Size; } + OffsetAndSize &operator&=(const OffsetAndSize &R) { + if (Offset == Unassigned) + Offset = R.Offset; + else if (R.Offset != Unassigned && R.Offset != Offset) + Offset = Unknown; + + if (Size == Unassigned) + Size = R.Size; + else if (Size == Unknown || R.Size == Unknown) + Size = Unknown; + else if (R.Size != Unassigned) + Size = std::max(Size, R.Size); + + return *this; + } + /// Constants used to represent special offsets or sizes. /// - This assumes that Offset and Size are non-negative. /// - The constants should not clash with DenseMapInfo, such as EmptyKey @@ -4992,33 +5008,47 @@ /// An access description. struct Access { - Access(Instruction *I, Optional Content, AccessKind Kind, Type *Ty) - : LocalI(I), RemoteI(I), Content(Content), Kind(Kind), Ty(Ty) { + Access(Instruction *I, int64_t Offset, int64_t Size, + Optional Content, AccessKind Kind, Type *Ty) + : LocalI(I), RemoteI(I), Content(Content), OAS(Offset, Size), + Kind(Kind), Ty(Ty) { verify(); } - Access(Instruction *LocalI, Instruction *RemoteI, Optional Content, - AccessKind Kind, Type *Ty) - : LocalI(LocalI), RemoteI(RemoteI), Content(Content), Kind(Kind), - Ty(Ty) { + Access(Instruction *LocalI, Instruction *RemoteI, int64_t Offset, + int64_t Size, Optional Content, AccessKind Kind, Type *Ty) + : LocalI(LocalI), RemoteI(RemoteI), Content(Content), OAS(Offset, Size), + Kind(Kind), Ty(Ty) { verify(); } Access(const Access &Other) = default; Access(const Access &&Other) : LocalI(Other.LocalI), RemoteI(Other.RemoteI), Content(Other.Content), - Kind(Other.Kind), Ty(Other.Ty) {} + OAS(Other.OAS), Kind(Other.Kind), Ty(Other.Ty) {} Access &operator=(const Access &Other) = default; bool operator==(const Access &R) const { - return LocalI == R.LocalI && RemoteI == R.RemoteI && + return LocalI == R.LocalI && RemoteI == R.RemoteI && OAS == R.OAS && Content == R.Content && Kind == R.Kind; } bool operator!=(const Access &R) const { return !(*this == R); } Access &operator&=(const Access &R) { assert(RemoteI == R.RemoteI && "Expected same instruction!"); - Content = - AA::combineOptionalValuesInAAValueLatice(Content, R.Content, Ty); + assert(LocalI == R.LocalI && "Expected same instruction!"); Kind = AccessKind(Kind | R.Kind); + auto Before = OAS; + OAS &= R.OAS; + if (Before.isUnassigned() || Before == OAS) { + Content = + AA::combineOptionalValuesInAAValueLatice(Content, R.Content, Ty); + } else { + // Since the OAS information changed, set a conservative state -- drop + // the contents, and assume MayAccess rather than MustAccess. + Content.reset(); + Kind = AccessKind(Kind | AK_MAY); + Kind = AccessKind(Kind & ~AK_MUST); + } + verify(); return *this; } @@ -5066,6 +5096,12 @@ /// determined. Optional getContent() const { return Content; } + /// Return the offset for this access. + int64_t getOffset() const { return OAS.Offset; } + + /// Return the size for this access. + int64_t getSize() const { return OAS.Size; } + private: /// The instruction responsible for the access with respect to the local /// scope of the associated attribute. @@ -5078,6 +5114,9 @@ /// cannot be determined. Optional Content; + /// The object accessed, in terms of an offset and size in bytes. + AA::OffsetAndSize OAS; + /// The access kind, e.g., READ, as bitset (could be more than one). AccessKind Kind; @@ -5113,7 +5152,7 @@ virtual bool forallInterferingAccesses( Attributor &A, const AbstractAttribute &QueryingAA, Instruction &I, function_ref CB, bool &HasBeenWrittenTo, - AA::OffsetAndSize *OASPtr = nullptr) const = 0; + AA::OffsetAndSize &OAS) const = 0; /// This function should return true if the type of the \p AA is AAPointerInfo static bool classof(const AbstractAttribute *AA) { diff --git a/llvm/lib/Transforms/IPO/Attributor.cpp b/llvm/lib/Transforms/IPO/Attributor.cpp --- a/llvm/lib/Transforms/IPO/Attributor.cpp +++ b/llvm/lib/Transforms/IPO/Attributor.cpp @@ -456,7 +456,7 @@ auto &PI = A.getAAFor(QueryingAA, IRPosition::value(*Obj), DepClassTy::NONE); if (!PI.forallInterferingAccesses(A, QueryingAA, I, CheckAccess, - HasBeenWrittenTo, &OAS)) { + HasBeenWrittenTo, OAS)) { LLVM_DEBUG( dbgs() << "Failed to verify all interfering accesses for underlying object: " diff --git a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp --- a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp +++ b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp @@ -757,13 +757,6 @@ /// A type to track pointer/struct usage and accesses for AAPointerInfo. struct AA::PointerInfo::State : public AbstractState { - - ~State() { - // We do not delete the Accesses objects but need to destroy them still. - for (auto &It : AccessBins) - It.second->~Accesses(); - } - /// Return the best possible representable state. static State getBestState(const State &SIS) { return State(); } @@ -775,9 +768,7 @@ } State() = default; - State(State &&SIS) : AccessBins(std::move(SIS.AccessBins)) { - SIS.AccessBins.clear(); - } + State(State &&SIS) = default; const State &getAssumed() const { return *this; } @@ -803,7 +794,9 @@ if (this == &R) return *this; BS = R.BS; - AccessBins = R.AccessBins; + AccessList = R.AccessList; + OffsetBins = R.OffsetBins; + RemoteIMap = R.RemoteIMap; return *this; } @@ -811,99 +804,52 @@ if (this == &R) return *this; std::swap(BS, R.BS); - std::swap(AccessBins, R.AccessBins); + std::swap(AccessList, R.AccessList); + std::swap(OffsetBins, R.OffsetBins); + std::swap(RemoteIMap, R.RemoteIMap); return *this; } - bool operator==(const State &R) const { - if (BS != R.BS) - return false; - if (AccessBins.size() != R.AccessBins.size()) - return false; - auto It = begin(), RIt = R.begin(), E = end(); - while (It != E) { - if (It->getFirst() != RIt->getFirst()) - return false; - auto &Accs = It->getSecond(); - auto &RAccs = RIt->getSecond(); - if (Accs->size() != RAccs->size()) - return false; - for (const auto &ZipIt : llvm::zip(*Accs, *RAccs)) - if (std::get<0>(ZipIt) != std::get<1>(ZipIt)) - return false; - ++It; - ++RIt; - } - return true; - } - bool operator!=(const State &R) const { return !(*this == R); } - - /// We store accesses in a set with the instruction as key. - struct Accesses { - SmallVector Accesses; - DenseMap Map; - - unsigned size() const { return Accesses.size(); } - - using vec_iterator = decltype(Accesses)::iterator; - vec_iterator begin() { return Accesses.begin(); } - vec_iterator end() { return Accesses.end(); } - - using iterator = decltype(Map)::const_iterator; - iterator find(AAPointerInfo::Access &Acc) { - return Map.find(Acc.getRemoteInst()); - } - iterator find_end() { return Map.end(); } - - AAPointerInfo::Access &get(iterator &It) { - return Accesses[It->getSecond()]; - } - - void insert(AAPointerInfo::Access &Acc) { - Map[Acc.getRemoteInst()] = Accesses.size(); - Accesses.push_back(Acc); - } - }; - - /// We store all accesses in bins denoted by their offset and size. - using AccessBinsTy = DenseMap; - - AccessBinsTy::const_iterator begin() const { return AccessBins.begin(); } - AccessBinsTy::const_iterator end() const { return AccessBins.end(); } - -protected: - /// The bins with all the accesses for the associated pointer. - AccessBinsTy AccessBins; - - /// Add a new access to the state at offset \p Offset and with size \p Size. + /// Add a new Access to the state at offset \p Offset and with size \p Size. /// The access is associated with \p I, writes \p Content (if anything), and - /// is of kind \p Kind. + /// is of kind \p Kind. If an Access already exists for the same \p I and same + /// \p RemoteI, the two are combined, potentially losing information about + /// offset and size. The resulting access must now be moved from its original + /// OffsetBin to the bin for its new offset. + /// /// \Returns CHANGED, if the state changed, UNCHANGED otherwise. ChangeStatus addAccess(Attributor &A, int64_t Offset, int64_t Size, Instruction &I, Optional Content, AAPointerInfo::AccessKind Kind, Type *Ty, - Instruction *RemoteI = nullptr, - Accesses *BinPtr = nullptr) { - AA::OffsetAndSize Key{Offset, Size}; - Accesses *&Bin = BinPtr ? BinPtr : AccessBins[Key]; - if (!Bin) - Bin = new (A.Allocator) Accesses; - AAPointerInfo::Access Acc(&I, RemoteI ? RemoteI : &I, Content, Kind, Ty); - // Check if we have an access for this instruction in this bin, if not, - // simply add it. - auto It = Bin->find(Acc); - if (It == Bin->find_end()) { - Bin->insert(Acc); - return ChangeStatus::CHANGED; - } - // If the existing access is the same as then new one, nothing changed. - AAPointerInfo::Access &Current = Bin->get(It); - AAPointerInfo::Access Before = Current; - // The new one will be combined with the existing one. - Current &= Acc; - return Current == Before ? ChangeStatus::UNCHANGED : ChangeStatus::CHANGED; + Instruction *RemoteI = nullptr); + + using OffsetBinsTy = DenseMap>; + + using const_bin_iterator = OffsetBinsTy::const_iterator; + const_bin_iterator begin() const { return OffsetBins.begin(); } + const_bin_iterator end() const { return OffsetBins.end(); } + + const AAPointerInfo::Access &getAccess(unsigned Index) const { + return AccessList[Index]; } +protected: + // Every memory instruction results in an Access object. We maintain a list of + // all Access objects that we own, along with the following maps: + // + // - OffsetBins: OffsetAndSize -> { Access } + // - RemoteIMap: RemoteI x LocalI -> Access + // + // A RemoteI is any instruction that accesses memory. RemoteI is different + // from LocalI if and only if LocalI is a call; then RemoteI is some + // instruction in the callgraph starting from LocalI. Multiple paths in the + // callgraph from LocalI to RemoteI may produce multiple accesses, but these + // are all combined into a single Access object. This may result in loss of + // information in OffsetAndSize in the Access object. + SmallVector AccessList; + OffsetBinsTy OffsetBins; + DenseMap> RemoteIMap; + /// See AAPointerInfo::forallInterferingAccesses. bool forallInterferingAccesses( AA::OffsetAndSize OAS, @@ -911,14 +857,16 @@ if (!isValidState()) return false; - for (const auto &It : AccessBins) { + for (const auto &It : OffsetBins) { AA::OffsetAndSize ItOAS = It.getFirst(); if (!OAS.mayOverlap(ItOAS)) continue; bool IsExact = OAS == ItOAS && !OAS.offsetOrSizeAreUnknown(); - for (auto &Access : *It.getSecond()) + for (auto Index : It.getSecond()) { + auto &Access = AccessList[Index]; if (!CB(Access, IsExact)) return false; + } } return true; } @@ -927,33 +875,23 @@ bool forallInterferingAccesses( Instruction &I, function_ref CB, - AA::OffsetAndSize *OASPtr) const { + AA::OffsetAndSize &OAS) const { if (!isValidState()) return false; - // First find the offset and size of I. - AA::OffsetAndSize OAS; - for (const auto &It : AccessBins) { - for (auto &Access : *It.getSecond()) { - if (Access.getRemoteInst() == &I) { - OAS = It.getFirst(); - break; - } - } - if (OAS.Size != AA::OffsetAndSize::Unassigned) - break; + auto LocalList = RemoteIMap.find(&I); + if (LocalList == RemoteIMap.end()) { + return true; } - if (OASPtr) - *OASPtr = OAS; - - // No access for I was found, we are done. - if (OAS.Size == AA::OffsetAndSize::Unassigned) - return true; + bool Changed = false; + for (auto LI : LocalList->getSecond()) { + auto &Access = AccessList[LI]; + OAS &= {Access.getOffset(), Access.getSize()}; + Changed |= forallInterferingAccesses(OAS, CB); + } - // Now that we have an offset and size, find all overlapping ones and use - // the callback on the accesses. - return forallInterferingAccesses(OAS, CB); + return Changed; } private: @@ -961,6 +899,59 @@ BooleanState BS; }; +ChangeStatus AA::PointerInfo::State::addAccess(Attributor &A, int64_t Offset, + int64_t Size, Instruction &I, + Optional Content, + AAPointerInfo::AccessKind Kind, + Type *Ty, Instruction *RemoteI) { + RemoteI = RemoteI ? RemoteI : &I; + AAPointerInfo::Access Acc(&I, RemoteI, Offset, Size, Content, Kind, Ty); + + // Check if we have an access for this instruction, if not, simply add it. + auto &LocalList = RemoteIMap[RemoteI]; + bool AccExists = false; + unsigned AccIndex = AccessList.size(); + for (auto Index : LocalList) { + auto &A = AccessList[Index]; + if (A.getLocalInst() == &I) { + AccExists = true; + AccIndex = Index; + break; + } + } + if (!AccExists) { + AccessList.push_back(Acc); + LocalList.push_back(AccIndex); + } else { + // The new one will be combined with the existing one. + auto &Current = AccessList[AccIndex]; + auto Before = Current; + Current &= Acc; + if (Current == Before) + return ChangeStatus::UNCHANGED; + + LLVM_DEBUG(dbgs() << "Access changed from " << Before << " to " << Current + << "\n"); + Acc = Current; + AA::OffsetAndSize Key{Before.getOffset(), Before.getSize()}; + assert(OffsetBins.count(Key) && "Existing Access must be in some bin."); + auto &Bin = OffsetBins[Key]; + assert(Bin.count(AccIndex) && + "Expected bin to actually contain the Access."); + LLVM_DEBUG(dbgs() << "[AAPointerInfo] Removing Access " + << AccessList[AccIndex] << " with key " << '{' + << Key.Offset << ',' << Key.Size << '}' << "\n"); + Bin.erase(AccIndex); + } + + AA::OffsetAndSize Key{Acc.getOffset(), Acc.getSize()}; + LLVM_DEBUG(dbgs() << "[AAPointerInfo] Inserting Access " << Acc + << " with key " << '{' << Key.Offset << ',' << Key.Size + << '}' << "\n"); + OffsetBins[Key].insert(AccIndex); + return ChangeStatus::CHANGED; +} + namespace { struct AAPointerInfoImpl : public StateWrapper { @@ -971,7 +962,7 @@ const std::string getAsStr() const override { return std::string("PointerInfo ") + (isValidState() ? (std::string("#") + - std::to_string(AccessBins.size()) + " bins") + std::to_string(OffsetBins.size()) + " bins") : ""); } @@ -990,7 +981,7 @@ bool forallInterferingAccesses( Attributor &A, const AbstractAttribute &QueryingAA, Instruction &I, function_ref UserCB, bool &HasBeenWrittenTo, - AA::OffsetAndSize *OASPtr = nullptr) const override { + AA::OffsetAndSize &OAS) const override { HasBeenWrittenTo = false; SmallPtrSet DominatingWrites; @@ -1105,7 +1096,7 @@ InterferingAccesses.push_back({&Acc, Exact}); return true; }; - if (!State::forallInterferingAccesses(I, AccessCB, OASPtr)) + if (!State::forallInterferingAccesses(I, AccessCB, OAS)) return false; if (HasBeenWrittenTo) { @@ -1172,12 +1163,13 @@ // Combine the accesses bin by bin. ChangeStatus Changed = ChangeStatus::UNCHANGED; - for (const auto &It : OtherAAImpl.getState()) { + const auto &State = OtherAAImpl.getState(); + for (const auto &It : State) { AA::OffsetAndSize OAS = AA::OffsetAndSize::getUnknown(); if (Offset != AA::OffsetAndSize::Unknown) OAS = AA::OffsetAndSize(It.first.Offset + Offset, It.first.Size); - Accesses *Bin = AccessBins.lookup(OAS); - for (const AAPointerInfo::Access &RAcc : *It.second) { + for (auto Index : It.getSecond()) { + const auto &RAcc = State.getAccess(Index); if (IsByval && !RAcc.isRead()) continue; bool UsedAssumedInformation = false; @@ -1190,9 +1182,8 @@ AccessKind(AK & (IsByval ? AccessKind::AK_R : AccessKind::AK_RW)); AK = AccessKind(AK | (RAcc.isMayAccess() ? AK_MAY : AK_MUST)); } - Changed = - Changed | addAccess(A, OAS.Offset, OAS.Size, CB, Content, AK, - RAcc.getType(), RAcc.getRemoteInst(), Bin); + Changed = Changed | addAccess(A, OAS.Offset, OAS.Size, CB, Content, AK, + RAcc.getType(), RAcc.getRemoteInst()); } } return Changed; @@ -1204,10 +1195,11 @@ /// Dump the state into \p O. void dumpState(raw_ostream &O) { - for (auto &It : AccessBins) { + for (auto &It : OffsetBins) { O << "[" << It.first.Offset << "-" << It.first.Offset + It.first.Size - << "] : " << It.getSecond()->size() << "\n"; - for (auto &Acc : *It.getSecond()) { + << "] : " << It.getSecond().size() << "\n"; + for (auto AccIndex : It.getSecond()) { + auto &Acc = AccessList[AccIndex]; O << " - " << Acc.getKind() << " - " << *Acc.getLocalInst() << "\n"; if (Acc.getLocalInst() != Acc.getRemoteInst()) O << " --> " << *Acc.getRemoteInst() diff --git a/llvm/test/Transforms/Attributor/value-simplify-pointer-info.ll b/llvm/test/Transforms/Attributor/value-simplify-pointer-info.ll --- a/llvm/test/Transforms/Attributor/value-simplify-pointer-info.ll +++ b/llvm/test/Transforms/Attributor/value-simplify-pointer-info.ll @@ -141,7 +141,7 @@ ; CGSCC-NEXT: entry: ; CGSCC-NEXT: [[S:%.*]] = alloca [[STRUCT_S]], align 4 ; CGSCC-NEXT: [[I:%.*]] = bitcast %struct.S* [[S]] to i8* -; CGSCC-NEXT: call void @llvm.lifetime.start.p0i8(i64 noundef 24, i8* nocapture nofree noundef nonnull align 4 dereferenceable(24) [[I]]) #[[ATTR18:[0-9]+]] +; CGSCC-NEXT: call void @llvm.lifetime.start.p0i8(i64 noundef 24, i8* nocapture nofree noundef nonnull align 4 dereferenceable(24) [[I]]) #[[ATTR20:[0-9]+]] ; CGSCC-NEXT: [[F1:%.*]] = getelementptr inbounds [[STRUCT_S]], %struct.S* [[S]], i64 0, i32 3 ; CGSCC-NEXT: store float 0x3FF19999A0000000, float* [[F1]], align 4, !tbaa [[TBAA7:![0-9]+]] ; CGSCC-NEXT: [[F2:%.*]] = getelementptr inbounds [[STRUCT_S]], %struct.S* [[S]], i64 0, i32 4 @@ -149,11 +149,11 @@ ; CGSCC-NEXT: [[F3:%.*]] = getelementptr inbounds [[STRUCT_S]], %struct.S* [[S]], i64 0, i32 5 ; CGSCC-NEXT: store float 0x400A666660000000, float* [[F3]], align 4, !tbaa [[TBAA11:![0-9]+]] ; CGSCC-NEXT: [[I1:%.*]] = getelementptr inbounds [[STRUCT_S]], %struct.S* [[S]], i64 0, i32 0 -; CGSCC-NEXT: call void @write_arg(i32* nocapture nofree noundef nonnull writeonly align 4 dereferenceable(24) [[I1]], i32 noundef 1) #[[ATTR19:[0-9]+]] +; CGSCC-NEXT: call void @write_arg(i32* nocapture nofree noundef nonnull writeonly align 4 dereferenceable(24) [[I1]], i32 noundef 1) #[[ATTR21:[0-9]+]] ; CGSCC-NEXT: [[I2:%.*]] = getelementptr inbounds [[STRUCT_S]], %struct.S* [[S]], i64 0, i32 1 -; CGSCC-NEXT: call void @write_arg(i32* nocapture nofree noundef nonnull writeonly align 4 dereferenceable(20) [[I2]], i32 noundef 2) #[[ATTR19]] +; CGSCC-NEXT: call void @write_arg(i32* nocapture nofree noundef nonnull writeonly align 4 dereferenceable(20) [[I2]], i32 noundef 2) #[[ATTR21]] ; CGSCC-NEXT: [[I3:%.*]] = getelementptr inbounds [[STRUCT_S]], %struct.S* [[S]], i64 0, i32 2 -; CGSCC-NEXT: call void @write_arg(i32* nocapture nofree noundef nonnull writeonly align 4 dereferenceable(16) [[I3]], i32 noundef 3) #[[ATTR19]] +; CGSCC-NEXT: call void @write_arg(i32* nocapture nofree noundef nonnull writeonly align 4 dereferenceable(16) [[I3]], i32 noundef 3) #[[ATTR21]] ; CGSCC-NEXT: [[F11:%.*]] = getelementptr inbounds [[STRUCT_S]], %struct.S* [[S]], i64 0, i32 3 ; CGSCC-NEXT: [[I4:%.*]] = load float, float* [[F11]], align 4, !tbaa [[TBAA7]] ; CGSCC-NEXT: [[F12:%.*]] = getelementptr inbounds [[STRUCT_S]], %struct.S* [[AGG_RESULT]], i64 0, i32 3 @@ -187,7 +187,7 @@ ; CGSCC-NEXT: [[I316:%.*]] = getelementptr inbounds [[STRUCT_S]], %struct.S* [[AGG_RESULT]], i64 0, i32 2 ; CGSCC-NEXT: store i32 [[ADD15]], i32* [[I316]], align 4, !tbaa [[TBAA14]] ; CGSCC-NEXT: [[I12:%.*]] = bitcast %struct.S* [[S]] to i8* -; CGSCC-NEXT: call void @llvm.lifetime.end.p0i8(i64 noundef 24, i8* nocapture nofree noundef nonnull align 4 dereferenceable(24) [[I12]]) #[[ATTR18]] +; CGSCC-NEXT: call void @llvm.lifetime.end.p0i8(i64 noundef 24, i8* nocapture nofree noundef nonnull align 4 dereferenceable(24) [[I12]]) #[[ATTR20]] ; CGSCC-NEXT: ret void ; entry: @@ -348,7 +348,7 @@ ; CGSCC-NEXT: entry: ; CGSCC-NEXT: [[BYTES:%.*]] = alloca [1024 x i8], align 16 ; CGSCC-NEXT: [[I:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 0 -; CGSCC-NEXT: call void @llvm.lifetime.start.p0i8(i64 noundef 1024, i8* nocapture nofree noundef nonnull align 16 dereferenceable(1024) [[I]]) #[[ATTR18]] +; CGSCC-NEXT: call void @llvm.lifetime.start.p0i8(i64 noundef 1024, i8* nocapture nofree noundef nonnull align 16 dereferenceable(1024) [[I]]) #[[ATTR20]] ; CGSCC-NEXT: br label [[FOR_COND:%.*]] ; CGSCC: for.cond: ; CGSCC-NEXT: [[INDVARS_IV:%.*]] = phi i64 [ [[INDVARS_IV_NEXT:%.*]], [[FOR_INC:%.*]] ], [ 0, [[ENTRY:%.*]] ] @@ -405,7 +405,7 @@ ; CGSCC-NEXT: store i8 0, i8* [[ARRAYIDX25]], align 1, !tbaa [[TBAA15]] ; CGSCC-NEXT: [[ARRAYIDX26:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 500 ; CGSCC-NEXT: [[I22:%.*]] = bitcast i8* [[ARRAYIDX26]] to i32* -; CGSCC-NEXT: call void @write_arg(i32* nocapture nofree noundef nonnull writeonly align 4 dereferenceable(524) [[I22]], i32 noundef 0) #[[ATTR19]] +; CGSCC-NEXT: call void @write_arg(i32* nocapture nofree noundef nonnull writeonly align 4 dereferenceable(524) [[I22]], i32 noundef 0) #[[ATTR21]] ; CGSCC-NEXT: br label [[FOR_COND28:%.*]] ; CGSCC: for.cond28: ; CGSCC-NEXT: [[INDVARS_IV12:%.*]] = phi i64 [ [[INDVARS_IV_NEXT13:%.*]], [[FOR_INC36:%.*]] ], [ 0, [[FOR_END24]] ] @@ -424,7 +424,7 @@ ; CGSCC-NEXT: br label [[FOR_COND28]], !llvm.loop [[LOOP23:![0-9]+]] ; CGSCC: for.end38: ; CGSCC-NEXT: [[I24:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 0 -; CGSCC-NEXT: call void @llvm.lifetime.end.p0i8(i64 noundef 1024, i8* nocapture nofree noundef nonnull align 16 dereferenceable(1024) [[I24]]) #[[ATTR18]] +; CGSCC-NEXT: call void @llvm.lifetime.end.p0i8(i64 noundef 1024, i8* nocapture nofree noundef nonnull align 16 dereferenceable(1024) [[I24]]) #[[ATTR20]] ; CGSCC-NEXT: ret void ; entry: @@ -573,6 +573,67 @@ ret i32 %l } +define internal i8 @read_arg(i8* %p, i64 %index) { +; CGSCC: Function Attrs: argmemonly nofree norecurse nosync nounwind readonly willreturn +; CGSCC-LABEL: define {{[^@]+}}@read_arg +; CGSCC-SAME: (i8* nocapture nofree noundef nonnull readonly dereferenceable(1) [[P:%.*]]) #[[ATTR5:[0-9]+]] { +; CGSCC-NEXT: entry: +; CGSCC-NEXT: [[L:%.*]] = load i8, i8* [[P]], align 1 +; CGSCC-NEXT: ret i8 [[L]] +; +entry: + %g = getelementptr inbounds i8, i8* %p, i64 %index + %l = load i8, i8* %p + ret i8 %l +} + +define internal i8 @sum_two_same_loads(i8* %p) { +; CGSCC: Function Attrs: argmemonly nofree nosync nounwind readonly willreturn +; CGSCC-LABEL: define {{[^@]+}}@sum_two_same_loads +; CGSCC-SAME: (i8* nocapture nofree noundef nonnull readonly align 16 dereferenceable(1024) [[P:%.*]]) #[[ATTR6:[0-9]+]] { +; CGSCC-NEXT: [[X:%.*]] = call i8 @read_arg(i8* nocapture nofree noundef nonnull readonly align 16 dereferenceable(1024) [[P]]) #[[ATTR22:[0-9]+]] +; CGSCC-NEXT: [[Y:%.*]] = call i8 @read_arg(i8* nocapture nofree noundef nonnull readonly align 16 dereferenceable(1024) [[P]]) #[[ATTR22]] +; CGSCC-NEXT: [[Z:%.*]] = add nsw i8 [[X]], [[Y]] +; CGSCC-NEXT: ret i8 [[Z]] +; + %x = call i8 @read_arg(i8* %p, i64 1) + %y = call i8 @read_arg(i8* %p, i64 1) + %z = add nsw i8 %x, %y + ret i8 %z +} + +define i8 @local_alloca_simplifiable_5() { +; TUNIT: Function Attrs: nofree norecurse nosync nounwind readnone willreturn +; TUNIT-LABEL: define {{[^@]+}}@local_alloca_simplifiable_5 +; TUNIT-SAME: () #[[ATTR4]] { +; TUNIT-NEXT: entry: +; TUNIT-NEXT: [[BYTES:%.*]] = alloca [1024 x i8], align 16 +; TUNIT-NEXT: [[I0:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 0 +; TUNIT-NEXT: [[I1:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 1 +; TUNIT-NEXT: ret i8 2 +; +; CGSCC: Function Attrs: nofree nosync nounwind readnone willreturn +; CGSCC-LABEL: define {{[^@]+}}@local_alloca_simplifiable_5 +; CGSCC-SAME: () #[[ATTR7:[0-9]+]] { +; CGSCC-NEXT: entry: +; CGSCC-NEXT: [[BYTES:%.*]] = alloca [1024 x i8], align 16 +; CGSCC-NEXT: [[I0:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 0 +; CGSCC-NEXT: store i8 1, i8* [[I0]], align 16 +; CGSCC-NEXT: [[I1:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 1 +; CGSCC-NEXT: store i8 1, i8* [[I1]], align 1 +; CGSCC-NEXT: [[R:%.*]] = call i8 @sum_two_same_loads(i8* nocapture nofree noundef nonnull readonly align 16 dereferenceable(1024) [[I0]]) #[[ATTR22]] +; CGSCC-NEXT: ret i8 [[R]] +; +entry: + %Bytes = alloca [1024 x i8], align 16 + %i0 = getelementptr inbounds [1024 x i8], [1024 x i8]* %Bytes, i64 0, i64 0 + store i8 1, i8* %i0 + %i1 = getelementptr inbounds [1024 x i8], [1024 x i8]* %Bytes, i64 0, i64 1 + store i8 1, i8* %i1 + %r = call i8 @sum_two_same_loads(i8* %i0) + ret i8 %r +} + ; static int GI1 __attribute__((loader_uninitialized)); ; int multi_obj_simplifiable_1(int cnd) { ; int L = GI1 = 5; @@ -600,11 +661,11 @@ ; ; CGSCC: Function Attrs: nofree norecurse nosync nounwind willreturn ; CGSCC-LABEL: define {{[^@]+}}@multi_obj_simplifiable_1 -; CGSCC-SAME: (i32 [[CND:%.*]]) #[[ATTR5:[0-9]+]] { +; CGSCC-SAME: (i32 [[CND:%.*]]) #[[ATTR8:[0-9]+]] { ; CGSCC-NEXT: entry: ; CGSCC-NEXT: [[L:%.*]] = alloca i32, align 4 ; CGSCC-NEXT: [[I:%.*]] = bitcast i32* [[L]] to i8* -; CGSCC-NEXT: call void @llvm.lifetime.start.p0i8(i64 noundef 4, i8* nocapture nofree noundef nonnull align 4 dereferenceable(4) [[I]]) #[[ATTR18]] +; CGSCC-NEXT: call void @llvm.lifetime.start.p0i8(i64 noundef 4, i8* nocapture nofree noundef nonnull align 4 dereferenceable(4) [[I]]) #[[ATTR20]] ; CGSCC-NEXT: [[TOBOOL_NOT:%.*]] = icmp eq i32 [[CND]], 0 ; CGSCC-NEXT: br i1 [[TOBOOL_NOT]], label [[COND_FALSE:%.*]], label [[COND_TRUE:%.*]] ; CGSCC: cond.true: @@ -613,7 +674,7 @@ ; CGSCC-NEXT: br label [[COND_END]] ; CGSCC: cond.end: ; CGSCC-NEXT: [[I2:%.*]] = bitcast i32* [[L]] to i8* -; CGSCC-NEXT: call void @llvm.lifetime.end.p0i8(i64 noundef 4, i8* nocapture nofree noundef nonnull align 4 dereferenceable(4) [[I2]]) #[[ATTR18]] +; CGSCC-NEXT: call void @llvm.lifetime.end.p0i8(i64 noundef 4, i8* nocapture nofree noundef nonnull align 4 dereferenceable(4) [[I2]]) #[[ATTR20]] ; CGSCC-NEXT: ret i32 5 ; entry: @@ -668,11 +729,11 @@ ; ; CGSCC: Function Attrs: nofree norecurse nosync nounwind willreturn ; CGSCC-LABEL: define {{[^@]+}}@multi_obj_simplifiable_2 -; CGSCC-SAME: (i32 [[CND:%.*]]) #[[ATTR5]] { +; CGSCC-SAME: (i32 [[CND:%.*]]) #[[ATTR8]] { ; CGSCC-NEXT: entry: ; CGSCC-NEXT: [[L:%.*]] = alloca i32, align 4 ; CGSCC-NEXT: [[I:%.*]] = bitcast i32* [[L]] to i8* -; CGSCC-NEXT: call void @llvm.lifetime.start.p0i8(i64 noundef 4, i8* nocapture nofree noundef nonnull align 4 dereferenceable(4) [[I]]) #[[ATTR18]] +; CGSCC-NEXT: call void @llvm.lifetime.start.p0i8(i64 noundef 4, i8* nocapture nofree noundef nonnull align 4 dereferenceable(4) [[I]]) #[[ATTR20]] ; CGSCC-NEXT: [[TOBOOL_NOT:%.*]] = icmp eq i32 [[CND]], 0 ; CGSCC-NEXT: br i1 [[TOBOOL_NOT]], label [[COND_FALSE:%.*]], label [[COND_TRUE:%.*]] ; CGSCC: cond.true: @@ -681,7 +742,7 @@ ; CGSCC-NEXT: br label [[COND_END]] ; CGSCC: cond.end: ; CGSCC-NEXT: [[I1:%.*]] = bitcast i32* [[L]] to i8* -; CGSCC-NEXT: call void @llvm.lifetime.end.p0i8(i64 noundef 4, i8* nocapture nofree noundef nonnull align 4 dereferenceable(4) [[I1]]) #[[ATTR18]] +; CGSCC-NEXT: call void @llvm.lifetime.end.p0i8(i64 noundef 4, i8* nocapture nofree noundef nonnull align 4 dereferenceable(4) [[I1]]) #[[ATTR20]] ; CGSCC-NEXT: ret i32 5 ; entry: @@ -753,9 +814,9 @@ ; CGSCC-NEXT: store float 0x3FF19999A0000000, float* getelementptr inbounds ([[STRUCT_S]], %struct.S* @Gs1, i64 0, i32 3), align 4, !tbaa [[TBAA7]] ; CGSCC-NEXT: store float 0x40019999A0000000, float* getelementptr inbounds ([[STRUCT_S]], %struct.S* @Gs1, i64 0, i32 4), align 4, !tbaa [[TBAA10]] ; CGSCC-NEXT: store float 0x400A666660000000, float* getelementptr inbounds ([[STRUCT_S]], %struct.S* @Gs1, i64 0, i32 5), align 4, !tbaa [[TBAA11]] -; CGSCC-NEXT: call void @write_arg(i32* nocapture nofree noundef nonnull writeonly align 4 dereferenceable(24) getelementptr inbounds ([[STRUCT_S]], %struct.S* @Gs1, i32 0, i32 0), i32 noundef 1) #[[ATTR19]] -; CGSCC-NEXT: call void @write_arg(i32* nocapture nofree noundef nonnull writeonly align 4 dereferenceable(20) getelementptr inbounds ([[STRUCT_S]], %struct.S* @Gs1, i64 0, i32 1), i32 noundef 2) #[[ATTR19]] -; CGSCC-NEXT: call void @write_arg(i32* nocapture nofree noundef nonnull writeonly align 4 dereferenceable(16) getelementptr inbounds ([[STRUCT_S]], %struct.S* @Gs1, i64 0, i32 2), i32 noundef 3) #[[ATTR19]] +; CGSCC-NEXT: call void @write_arg(i32* nocapture nofree noundef nonnull writeonly align 4 dereferenceable(24) getelementptr inbounds ([[STRUCT_S]], %struct.S* @Gs1, i32 0, i32 0), i32 noundef 1) #[[ATTR21]] +; CGSCC-NEXT: call void @write_arg(i32* nocapture nofree noundef nonnull writeonly align 4 dereferenceable(20) getelementptr inbounds ([[STRUCT_S]], %struct.S* @Gs1, i64 0, i32 1), i32 noundef 2) #[[ATTR21]] +; CGSCC-NEXT: call void @write_arg(i32* nocapture nofree noundef nonnull writeonly align 4 dereferenceable(16) getelementptr inbounds ([[STRUCT_S]], %struct.S* @Gs1, i64 0, i32 2), i32 noundef 3) #[[ATTR21]] ; CGSCC-NEXT: [[I:%.*]] = load float, float* getelementptr inbounds ([[STRUCT_S]], %struct.S* @Gs1, i64 0, i32 3), align 4, !tbaa [[TBAA7]] ; CGSCC-NEXT: [[F1:%.*]] = getelementptr inbounds [[STRUCT_S]], %struct.S* [[AGG_RESULT]], i64 0, i32 3 ; CGSCC-NEXT: store float [[I]], float* [[F1]], align 4, !tbaa [[TBAA7]] @@ -956,7 +1017,7 @@ ; CGSCC-NEXT: br label [[FOR_COND13]], !llvm.loop [[LOOP26:![0-9]+]] ; CGSCC: for.end23: ; CGSCC-NEXT: store i8 0, i8* getelementptr inbounds ([1024 x i8], [1024 x i8]* @GBytes, i64 0, i64 1023), align 1, !tbaa [[TBAA15]] -; CGSCC-NEXT: call void @write_arg(i32* nocapture nofree noundef nonnull writeonly align 4 dereferenceable(524) bitcast (i8* getelementptr inbounds ([1024 x i8], [1024 x i8]* @GBytes, i64 0, i64 500) to i32*), i32 noundef 0) #[[ATTR19]] +; CGSCC-NEXT: call void @write_arg(i32* nocapture nofree noundef nonnull writeonly align 4 dereferenceable(524) bitcast (i8* getelementptr inbounds ([1024 x i8], [1024 x i8]* @GBytes, i64 0, i64 500) to i32*), i32 noundef 0) #[[ATTR21]] ; CGSCC-NEXT: br label [[FOR_COND25:%.*]] ; CGSCC: for.cond25: ; CGSCC-NEXT: [[INDVARS_IV12:%.*]] = phi i64 [ [[INDVARS_IV_NEXT13:%.*]], [[FOR_INC33:%.*]] ], [ 0, [[FOR_END23]] ] @@ -1083,7 +1144,7 @@ ; ; CGSCC: Function Attrs: nofree norecurse nosync nounwind willreturn writeonly ; CGSCC-LABEL: define {{[^@]+}}@static_global_simplifiable_3 -; CGSCC-SAME: () #[[ATTR6:[0-9]+]] { +; CGSCC-SAME: () #[[ATTR9:[0-9]+]] { ; CGSCC-NEXT: store i32 1, i32* @Flag3, align 4, !tbaa [[TBAA3]] ; CGSCC-NEXT: ret i32 1 ; @@ -1171,11 +1232,11 @@ ; CGSCC-NEXT: [[F3:%.*]] = getelementptr inbounds [[STRUCT_S]], %struct.S* [[S]], i64 0, i32 5 ; CGSCC-NEXT: store float 0x400A666660000000, float* [[F3]], align 4, !tbaa [[TBAA11]] ; CGSCC-NEXT: [[I1:%.*]] = getelementptr inbounds [[STRUCT_S]], %struct.S* [[S]], i64 0, i32 0 -; CGSCC-NEXT: call void @write_arg(i32* nocapture nofree noundef nonnull writeonly align 8 dereferenceable(24) [[I1]], i32 noundef 1) #[[ATTR19]] +; CGSCC-NEXT: call void @write_arg(i32* nocapture nofree noundef nonnull writeonly align 8 dereferenceable(24) [[I1]], i32 noundef 1) #[[ATTR21]] ; CGSCC-NEXT: [[I2:%.*]] = getelementptr inbounds [[STRUCT_S]], %struct.S* [[S]], i64 0, i32 1 -; CGSCC-NEXT: call void @write_arg(i32* nocapture nofree noundef nonnull writeonly align 4 dereferenceable(20) [[I2]], i32 noundef 2) #[[ATTR19]] +; CGSCC-NEXT: call void @write_arg(i32* nocapture nofree noundef nonnull writeonly align 4 dereferenceable(20) [[I2]], i32 noundef 2) #[[ATTR21]] ; CGSCC-NEXT: [[I3:%.*]] = getelementptr inbounds [[STRUCT_S]], %struct.S* [[S]], i64 0, i32 2 -; CGSCC-NEXT: call void @write_arg(i32* nocapture nofree noundef nonnull writeonly align 8 dereferenceable(16) [[I3]], i32 noundef 3) #[[ATTR19]] +; CGSCC-NEXT: call void @write_arg(i32* nocapture nofree noundef nonnull writeonly align 8 dereferenceable(16) [[I3]], i32 noundef 3) #[[ATTR21]] ; CGSCC-NEXT: [[F11:%.*]] = getelementptr inbounds [[STRUCT_S]], %struct.S* [[S]], i64 0, i32 3 ; CGSCC-NEXT: [[I:%.*]] = load float, float* [[F11]], align 4, !tbaa [[TBAA7]] ; CGSCC-NEXT: [[F12:%.*]] = getelementptr inbounds [[STRUCT_S]], %struct.S* [[AGG_RESULT]], i64 0, i32 3 @@ -1413,7 +1474,7 @@ ; CGSCC-NEXT: store i8 0, i8* [[ARRAYIDX24]], align 1, !tbaa [[TBAA15]] ; CGSCC-NEXT: [[ARRAYIDX25:%.*]] = getelementptr inbounds i8, i8* [[BYTES]], i64 500 ; CGSCC-NEXT: [[I21:%.*]] = bitcast i8* [[ARRAYIDX25]] to i32* -; CGSCC-NEXT: call void @write_arg(i32* nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) [[I21]], i32 noundef 0) #[[ATTR19]] +; CGSCC-NEXT: call void @write_arg(i32* nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) [[I21]], i32 noundef 0) #[[ATTR21]] ; CGSCC-NEXT: br label [[FOR_COND27:%.*]] ; CGSCC: for.cond27: ; CGSCC-NEXT: [[INDVARS_IV12:%.*]] = phi i64 [ [[INDVARS_IV_NEXT13:%.*]], [[FOR_INC35:%.*]] ], [ 0, [[FOR_END23]] ] @@ -1571,9 +1632,9 @@ ; CGSCC-NEXT: [[X:%.*]] = alloca i32, align 4 ; CGSCC-NEXT: [[Y:%.*]] = alloca i32, align 4 ; CGSCC-NEXT: [[I:%.*]] = bitcast i32* [[X]] to i8* -; CGSCC-NEXT: call void @llvm.lifetime.start.p0i8(i64 noundef 4, i8* nocapture nofree noundef nonnull align 4 dereferenceable(4) [[I]]) #[[ATTR18]] +; CGSCC-NEXT: call void @llvm.lifetime.start.p0i8(i64 noundef 4, i8* nocapture nofree noundef nonnull align 4 dereferenceable(4) [[I]]) #[[ATTR20]] ; CGSCC-NEXT: [[I1:%.*]] = bitcast i32* [[Y]] to i8* -; CGSCC-NEXT: call void @llvm.lifetime.start.p0i8(i64 noundef 4, i8* nocapture nofree noundef nonnull align 4 dereferenceable(4) [[I1]]) #[[ATTR18]] +; CGSCC-NEXT: call void @llvm.lifetime.start.p0i8(i64 noundef 4, i8* nocapture nofree noundef nonnull align 4 dereferenceable(4) [[I1]]) #[[ATTR20]] ; CGSCC-NEXT: store i32 1, i32* [[Y]], align 4, !tbaa [[TBAA3]] ; CGSCC-NEXT: store i32 1, i32* [[X]], align 4, !tbaa [[TBAA3]] ; CGSCC-NEXT: [[I2:%.*]] = bitcast i32* [[X]] to i8* @@ -1639,7 +1700,7 @@ ; ; CGSCC: Function Attrs: nofree norecurse nosync nounwind willreturn ; CGSCC-LABEL: define {{[^@]+}}@local_alloca_not_simplifiable_2 -; CGSCC-SAME: (i64 [[INDEX1:%.*]], i64 [[INDEX2:%.*]], i1 [[CND:%.*]]) #[[ATTR5]] { +; CGSCC-SAME: (i64 [[INDEX1:%.*]], i64 [[INDEX2:%.*]], i1 [[CND:%.*]]) #[[ATTR8]] { ; CGSCC-NEXT: entry: ; CGSCC-NEXT: [[BYTES:%.*]] = alloca [1024 x i8], align 16 ; CGSCC-NEXT: [[GEP0:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 0 @@ -1681,6 +1742,53 @@ ret i8 %i } +define internal i8 @sum_two_different_loads(i8* %p) { +; CGSCC: Function Attrs: argmemonly nofree nosync nounwind readonly willreturn +; CGSCC-LABEL: define {{[^@]+}}@sum_two_different_loads +; CGSCC-SAME: (i8* nocapture nofree noundef nonnull readonly align 16 dereferenceable(1024) [[P:%.*]]) #[[ATTR6]] { +; CGSCC-NEXT: [[X:%.*]] = call i8 @read_arg(i8* nocapture nofree noundef nonnull readonly align 16 dereferenceable(1024) [[P]]) #[[ATTR22]] +; CGSCC-NEXT: [[Y:%.*]] = call i8 @read_arg(i8* nocapture nofree noundef nonnull readonly align 16 dereferenceable(1024) [[P]]) #[[ATTR22]] +; CGSCC-NEXT: [[Z:%.*]] = add nsw i8 [[X]], [[Y]] +; CGSCC-NEXT: ret i8 [[Z]] +; + %x = call i8 @read_arg(i8* %p, i64 0) + %y = call i8 @read_arg(i8* %p, i64 1) + %z = add nsw i8 %x, %y + ret i8 %z +} + +define i8 @local_alloca_not_simplifiable_3() { +; TUNIT: Function Attrs: nofree norecurse nosync nounwind readnone willreturn +; TUNIT-LABEL: define {{[^@]+}}@local_alloca_not_simplifiable_3 +; TUNIT-SAME: () #[[ATTR4]] { +; TUNIT-NEXT: entry: +; TUNIT-NEXT: [[BYTES:%.*]] = alloca [1024 x i8], align 16 +; TUNIT-NEXT: [[I0:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 0 +; TUNIT-NEXT: [[I1:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 1 +; TUNIT-NEXT: ret i8 2 +; +; CGSCC: Function Attrs: nofree nosync nounwind readnone willreturn +; CGSCC-LABEL: define {{[^@]+}}@local_alloca_not_simplifiable_3 +; CGSCC-SAME: () #[[ATTR7]] { +; CGSCC-NEXT: entry: +; CGSCC-NEXT: [[BYTES:%.*]] = alloca [1024 x i8], align 16 +; CGSCC-NEXT: [[I0:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 0 +; CGSCC-NEXT: store i8 1, i8* [[I0]], align 16 +; CGSCC-NEXT: [[I1:%.*]] = getelementptr inbounds [1024 x i8], [1024 x i8]* [[BYTES]], i64 0, i64 1 +; CGSCC-NEXT: store i8 1, i8* [[I1]], align 1 +; CGSCC-NEXT: [[R:%.*]] = call i8 @sum_two_different_loads(i8* nocapture nofree noundef nonnull readonly align 16 dereferenceable(1024) [[I0]]) #[[ATTR22]] +; CGSCC-NEXT: ret i8 [[R]] +; +entry: + %Bytes = alloca [1024 x i8], align 16 + %i0 = getelementptr inbounds [1024 x i8], [1024 x i8]* %Bytes, i64 0, i64 0 + store i8 1, i8* %i0 + %i1 = getelementptr inbounds [1024 x i8], [1024 x i8]* %Bytes, i64 0, i64 1 + store i8 1, i8* %i1 + %r = call i8 @sum_two_different_loads(i8* %i0) + ret i8 %r +} + ; We could simplify these if we separate accessed bins wrt. alignment (here mod 4). define i32 @unknown_access_mixed_simplifiable(i32 %arg1, i32 %arg2) { ; CHECK: Function Attrs: nofree norecurse nosync nounwind readnone willreturn @@ -1786,7 +1894,7 @@ ; ; CGSCC: Function Attrs: nofree norecurse nosync nounwind readonly willreturn ; CGSCC-LABEL: define {{[^@]+}}@global_not_simplifiable_1 -; CGSCC-SAME: (i32 [[CND:%.*]]) #[[ATTR7:[0-9]+]] { +; CGSCC-SAME: (i32 [[CND:%.*]]) #[[ATTR10:[0-9]+]] { ; CGSCC-NEXT: entry: ; CGSCC-NEXT: [[I:%.*]] = load i32, i32* @Flag0, align 4, !tbaa [[TBAA3]] ; CGSCC-NEXT: ret i32 [[I]] @@ -1878,7 +1986,7 @@ ; CGSCC-SAME: (i32 [[CND:%.*]]) { ; CGSCC-NEXT: entry: ; CGSCC-NEXT: store i32 1, i32* @Flag4, align 4, !tbaa [[TBAA3]] -; CGSCC-NEXT: call void @sync() #[[ATTR20:[0-9]+]] +; CGSCC-NEXT: call void @sync() #[[ATTR23:[0-9]+]] ; CGSCC-NEXT: [[I:%.*]] = load i32, i32* @Flag4, align 4, !tbaa [[TBAA3]] ; CGSCC-NEXT: store i32 2, i32* @Flag4, align 4, !tbaa [[TBAA3]] ; CGSCC-NEXT: ret i32 [[I]] @@ -1899,7 +2007,7 @@ ; ; CGSCC: Function Attrs: nofree norecurse nosync nounwind willreturn writeonly ; CGSCC-LABEL: define {{[^@]+}}@static_global_not_simplifiable_2_helper -; CGSCC-SAME: () #[[ATTR6]] { +; CGSCC-SAME: () #[[ATTR9]] { ; CGSCC-NEXT: store i32 2, i32* @Flag4, align 4, !tbaa [[TBAA3]] ; CGSCC-NEXT: ret void ; @@ -1919,7 +2027,7 @@ ; ; CGSCC: Function Attrs: nofree norecurse nosync nounwind willreturn ; CGSCC-LABEL: define {{[^@]+}}@static_global_not_simplifiable_3 -; CGSCC-SAME: (i1 [[C:%.*]], i32* nocapture nofree writeonly [[P:%.*]]) #[[ATTR5]] { +; CGSCC-SAME: (i1 [[C:%.*]], i32* nocapture nofree writeonly [[P:%.*]]) #[[ATTR8]] { ; CGSCC-NEXT: [[SEL:%.*]] = select i1 [[C]], i32* @Flag3, i32* [[P]] ; CGSCC-NEXT: store i32 1, i32* [[SEL]], align 4, !tbaa [[TBAA3]] ; CGSCC-NEXT: [[I:%.*]] = load i32, i32* @Flag3, align 4, !tbaa [[TBAA3]] @@ -1954,7 +2062,7 @@ ; ; CGSCC: Function Attrs: nofree norecurse nosync nounwind willreturn ; CGSCC-LABEL: define {{[^@]+}}@write_read_global -; CGSCC-SAME: () #[[ATTR5]] { +; CGSCC-SAME: () #[[ATTR8]] { ; CGSCC-NEXT: store i32 7, i32* @Gint1, align 4 ; CGSCC-NEXT: [[L:%.*]] = load i32, i32* @Gint1, align 4 ; CGSCC-NEXT: ret i32 [[L]] @@ -1972,7 +2080,7 @@ ; ; CGSCC: Function Attrs: nofree norecurse nosync nounwind willreturn writeonly ; CGSCC-LABEL: define {{[^@]+}}@write_global -; CGSCC-SAME: () #[[ATTR6]] { +; CGSCC-SAME: () #[[ATTR9]] { ; CGSCC-NEXT: store i32 7, i32* @Gint2, align 4 ; CGSCC-NEXT: ret void ; @@ -1988,7 +2096,7 @@ ; ; CGSCC: Function Attrs: nofree norecurse nosync nounwind readonly willreturn ; CGSCC-LABEL: define {{[^@]+}}@read_global -; CGSCC-SAME: () #[[ATTR7]] { +; CGSCC-SAME: () #[[ATTR10]] { ; CGSCC-NEXT: [[L:%.*]] = load i32, i32* @Gint2, align 4 ; CGSCC-NEXT: ret i32 [[L]] ; @@ -2003,7 +2111,7 @@ ; ; CGSCC: Function Attrs: nofree norecurse nosync nounwind willreturn writeonly ; CGSCC-LABEL: define {{[^@]+}}@write_read_static_global -; CGSCC-SAME: () #[[ATTR6]] { +; CGSCC-SAME: () #[[ATTR9]] { ; CGSCC-NEXT: ret i32 7 ; store i32 7, i32* @Gstatic_int1 @@ -2019,7 +2127,7 @@ ; ; CGSCC: Function Attrs: nofree norecurse nosync nounwind willreturn writeonly ; CGSCC-LABEL: define {{[^@]+}}@write_static_global -; CGSCC-SAME: () #[[ATTR6]] { +; CGSCC-SAME: () #[[ATTR9]] { ; CGSCC-NEXT: store i32 7, i32* @Gstatic_int2, align 4 ; CGSCC-NEXT: ret void ; @@ -2035,7 +2143,7 @@ ; ; CGSCC: Function Attrs: nofree norecurse nosync nounwind readonly willreturn ; CGSCC-LABEL: define {{[^@]+}}@read_static_global -; CGSCC-SAME: () #[[ATTR7]] { +; CGSCC-SAME: () #[[ATTR10]] { ; CGSCC-NEXT: [[L:%.*]] = load i32, i32* @Gstatic_int2, align 4 ; CGSCC-NEXT: ret i32 [[L]] ; @@ -2050,7 +2158,7 @@ ; ; CGSCC: Function Attrs: nofree norecurse nosync nounwind willreturn writeonly ; CGSCC-LABEL: define {{[^@]+}}@write_read_static_undef_global -; CGSCC-SAME: () #[[ATTR6]] { +; CGSCC-SAME: () #[[ATTR9]] { ; CGSCC-NEXT: ret i32 7 ; store i32 7, i32* @Gstatic_undef_int1 @@ -2065,7 +2173,7 @@ ; ; CGSCC: Function Attrs: nofree norecurse nosync nounwind willreturn writeonly ; CGSCC-LABEL: define {{[^@]+}}@write_static_undef_global -; CGSCC-SAME: () #[[ATTR6]] { +; CGSCC-SAME: () #[[ATTR9]] { ; CGSCC-NEXT: store i32 7, i32* @Gstatic_undef_int2, align 4 ; CGSCC-NEXT: ret void ; @@ -2115,7 +2223,7 @@ ; ; CGSCC: Function Attrs: nofree norecurse nosync nounwind willreturn ; CGSCC-LABEL: define {{[^@]+}}@phi_store -; CGSCC-SAME: () #[[ATTR5]] { +; CGSCC-SAME: () #[[ATTR8]] { ; CGSCC-NEXT: entry: ; CGSCC-NEXT: [[A:%.*]] = alloca i16, align 2 ; CGSCC-NEXT: [[B:%.*]] = bitcast i16* [[A]] to i8* @@ -2175,7 +2283,7 @@ ; ; CGSCC: Function Attrs: nofree norecurse nosync nounwind willreturn ; CGSCC-LABEL: define {{[^@]+}}@phi_no_store_1 -; CGSCC-SAME: () #[[ATTR5]] { +; CGSCC-SAME: () #[[ATTR8]] { ; CGSCC-NEXT: entry: ; CGSCC-NEXT: br label [[LOOP:%.*]] ; CGSCC: loop: @@ -2223,6 +2331,7 @@ ; TUNIT: loop: ; TUNIT-NEXT: [[P:%.*]] = phi i8* [ bitcast (i32* @a2 to i8*), [[ENTRY:%.*]] ], [ [[G:%.*]], [[LOOP]] ] ; TUNIT-NEXT: [[I:%.*]] = phi i8 [ 0, [[ENTRY]] ], [ [[O:%.*]], [[LOOP]] ] +; TUNIT-NEXT: store i8 1, i8* [[P]], align 2 ; TUNIT-NEXT: [[G]] = getelementptr i8, i8* bitcast (i32* @a2 to i8*), i64 2 ; TUNIT-NEXT: [[O]] = add nsw i8 [[I]], 1 ; TUNIT-NEXT: [[C:%.*]] = icmp eq i8 [[O]], 7 @@ -2235,12 +2344,13 @@ ; ; CGSCC: Function Attrs: nofree norecurse nosync nounwind willreturn ; CGSCC-LABEL: define {{[^@]+}}@phi_no_store_2 -; CGSCC-SAME: () #[[ATTR5]] { +; CGSCC-SAME: () #[[ATTR8]] { ; CGSCC-NEXT: entry: ; CGSCC-NEXT: br label [[LOOP:%.*]] ; CGSCC: loop: ; CGSCC-NEXT: [[P:%.*]] = phi i8* [ bitcast (i32* @a2 to i8*), [[ENTRY:%.*]] ], [ [[G:%.*]], [[LOOP]] ] ; CGSCC-NEXT: [[I:%.*]] = phi i8 [ 0, [[ENTRY]] ], [ [[O:%.*]], [[LOOP]] ] +; CGSCC-NEXT: store i8 1, i8* [[P]], align 2 ; CGSCC-NEXT: [[G]] = getelementptr i8, i8* bitcast (i32* @a2 to i8*), i64 2 ; CGSCC-NEXT: [[O]] = add nsw i8 [[I]], 1 ; CGSCC-NEXT: [[C:%.*]] = icmp eq i8 [[O]], 7 @@ -2281,6 +2391,7 @@ ; TUNIT: loop: ; TUNIT-NEXT: [[P:%.*]] = phi i8* [ bitcast (i32* @a3 to i8*), [[ENTRY:%.*]] ], [ [[G:%.*]], [[LOOP]] ] ; TUNIT-NEXT: [[I:%.*]] = phi i8 [ 0, [[ENTRY]] ], [ [[O:%.*]], [[LOOP]] ] +; TUNIT-NEXT: store i8 1, i8* [[P]], align 2 ; TUNIT-NEXT: [[G]] = getelementptr i8, i8* bitcast (i32* @a3 to i8*), i64 2 ; TUNIT-NEXT: [[O]] = add nsw i8 [[I]], 1 ; TUNIT-NEXT: [[C:%.*]] = icmp eq i8 [[O]], 7 @@ -2295,13 +2406,14 @@ ; ; CGSCC: Function Attrs: nofree norecurse nosync nounwind willreturn ; CGSCC-LABEL: define {{[^@]+}}@phi_no_store_3 -; CGSCC-SAME: () #[[ATTR5]] { +; CGSCC-SAME: () #[[ATTR8]] { ; CGSCC-NEXT: entry: ; CGSCC-NEXT: store i8 0, i8* getelementptr (i8, i8* bitcast (i32* @a3 to i8*), i64 3), align 1 ; CGSCC-NEXT: br label [[LOOP:%.*]] ; CGSCC: loop: ; CGSCC-NEXT: [[P:%.*]] = phi i8* [ bitcast (i32* @a3 to i8*), [[ENTRY:%.*]] ], [ [[G:%.*]], [[LOOP]] ] ; CGSCC-NEXT: [[I:%.*]] = phi i8 [ 0, [[ENTRY]] ], [ [[O:%.*]], [[LOOP]] ] +; CGSCC-NEXT: store i8 1, i8* [[P]], align 2 ; CGSCC-NEXT: [[G]] = getelementptr i8, i8* bitcast (i32* @a3 to i8*), i64 2 ; CGSCC-NEXT: [[O]] = add nsw i8 [[I]], 1 ; CGSCC-NEXT: [[C:%.*]] = icmp eq i8 [[O]], 7 @@ -2349,7 +2461,7 @@ ; ; CGSCC: Function Attrs: nofree norecurse nosync nounwind willreturn ; CGSCC-LABEL: define {{[^@]+}}@cast_and_load_1 -; CGSCC-SAME: () #[[ATTR5]] { +; CGSCC-SAME: () #[[ATTR8]] { ; CGSCC-NEXT: store i32 42, i32* @bytes1, align 4 ; CGSCC-NEXT: [[L:%.*]] = load i8, i8* bitcast (i32* @bytes1 to i8*), align 4 ; CGSCC-NEXT: ret i8 [[L]] @@ -2370,7 +2482,7 @@ ; ; CGSCC: Function Attrs: nofree norecurse nosync nounwind willreturn ; CGSCC-LABEL: define {{[^@]+}}@cast_and_load_2 -; CGSCC-SAME: () #[[ATTR5]] { +; CGSCC-SAME: () #[[ATTR8]] { ; CGSCC-NEXT: store i32 42, i32* @bytes2, align 4 ; CGSCC-NEXT: [[L:%.*]] = load i64, i64* bitcast (i32* @bytes2 to i64*), align 4 ; CGSCC-NEXT: ret i64 [[L]] @@ -2400,7 +2512,7 @@ ; ; CGSCC: Function Attrs: nofree norecurse nosync nounwind writeonly ; CGSCC-LABEL: define {{[^@]+}}@recursive_load_store -; CGSCC-SAME: (i64 [[N:%.*]], i32 [[V:%.*]]) #[[ATTR8:[0-9]+]] { +; CGSCC-SAME: (i64 [[N:%.*]], i32 [[V:%.*]]) #[[ATTR11:[0-9]+]] { ; CGSCC-NEXT: entry: ; CGSCC-NEXT: br label [[FOR_COND:%.*]] ; CGSCC: for.cond: @@ -2610,7 +2722,7 @@ ; CGSCC-SAME: (i32 [[S:%.*]]) { ; CGSCC-NEXT: entry: ; CGSCC-NEXT: [[CONV:%.*]] = sext i32 [[S]] to i64 -; CGSCC-NEXT: [[CALL:%.*]] = call noalias i8* @malloc(i64 [[CONV]]) #[[ATTR21:[0-9]+]] +; CGSCC-NEXT: [[CALL:%.*]] = call noalias i8* @malloc(i64 [[CONV]]) #[[ATTR24:[0-9]+]] ; CGSCC-NEXT: [[TMP0:%.*]] = bitcast i8* [[CALL]] to i32* ; CGSCC-NEXT: ret i32* [[TMP0]] ; @@ -2635,11 +2747,11 @@ ; CGSCC-LABEL: define {{[^@]+}}@round_trip_malloc_like ; CGSCC-SAME: (i32 [[X:%.*]]) { ; CGSCC-NEXT: entry: -; CGSCC-NEXT: [[CALL:%.*]] = call i32* @malloc_like(i32 noundef 4) #[[ATTR21]] +; CGSCC-NEXT: [[CALL:%.*]] = call i32* @malloc_like(i32 noundef 4) #[[ATTR24]] ; CGSCC-NEXT: store i32 [[X]], i32* [[CALL]], align 4 ; CGSCC-NEXT: [[TMP0:%.*]] = load i32, i32* [[CALL]], align 4 ; CGSCC-NEXT: [[TMP1:%.*]] = bitcast i32* [[CALL]] to i8* -; CGSCC-NEXT: call void @free(i8* noundef nonnull [[TMP1]]) #[[ATTR21]] +; CGSCC-NEXT: call void @free(i8* noundef nonnull [[TMP1]]) #[[ATTR24]] ; CGSCC-NEXT: ret i32 [[TMP0]] ; entry: @@ -2665,11 +2777,11 @@ ; CGSCC-LABEL: define {{[^@]+}}@round_trip_unknown_alloc ; CGSCC-SAME: (i32 [[X:%.*]]) { ; CGSCC-NEXT: entry: -; CGSCC-NEXT: [[CALL:%.*]] = call i32* @unknown_alloc(i32 noundef 4) #[[ATTR21]] +; CGSCC-NEXT: [[CALL:%.*]] = call i32* @unknown_alloc(i32 noundef 4) #[[ATTR24]] ; CGSCC-NEXT: store i32 [[X]], i32* [[CALL]], align 4 ; CGSCC-NEXT: [[TMP0:%.*]] = load i32, i32* [[CALL]], align 4 ; CGSCC-NEXT: [[TMP1:%.*]] = bitcast i32* [[CALL]] to i8* -; CGSCC-NEXT: call void @free(i8* noundef nonnull [[TMP1]]) #[[ATTR21]] +; CGSCC-NEXT: call void @free(i8* noundef nonnull [[TMP1]]) #[[ATTR24]] ; CGSCC-NEXT: ret i32 [[TMP0]] ; entry: @@ -2702,7 +2814,7 @@ ; CGSCC-LABEL: define {{[^@]+}}@conditional_unknown_alloc ; CGSCC-SAME: (i32 [[X:%.*]]) { ; CGSCC-NEXT: entry: -; CGSCC-NEXT: [[CALL:%.*]] = call noalias i32* @unknown_alloc(i32 noundef 4) #[[ATTR21]] +; CGSCC-NEXT: [[CALL:%.*]] = call noalias i32* @unknown_alloc(i32 noundef 4) #[[ATTR24]] ; CGSCC-NEXT: [[TOBOOL:%.*]] = icmp ne i32 [[X]], 0 ; CGSCC-NEXT: br i1 [[TOBOOL]], label [[IF_END:%.*]], label [[IF_THEN:%.*]] ; CGSCC: if.then: @@ -2711,7 +2823,7 @@ ; CGSCC: if.end: ; CGSCC-NEXT: [[TMP0:%.*]] = load i32, i32* [[CALL]], align 4 ; CGSCC-NEXT: [[TMP1:%.*]] = bitcast i32* [[CALL]] to i8* -; CGSCC-NEXT: call void @free(i8* nonnull [[TMP1]]) #[[ATTR21]] +; CGSCC-NEXT: call void @free(i8* nonnull [[TMP1]]) #[[ATTR24]] ; CGSCC-NEXT: ret i32 [[TMP0]] ; entry: @@ -2771,7 +2883,7 @@ ; CGSCC-NEXT: [[TMP1:%.*]] = bitcast i8* [[SRC2]] to double** ; CGSCC-NEXT: store double* [[SRC]], double** [[TMP1]], align 8 ; CGSCC-NEXT: store i8* [[CALL]], i8** bitcast (%struct.STy** getelementptr inbounds ([[STRUCT_STY]], %struct.STy* @global, i64 0, i32 2) to i8**), align 8 -; CGSCC-NEXT: call fastcc void @nested_memory_callee(float* nofree nonnull align 4294967296 undef, double* nofree nonnull align 4294967296 undef, %struct.STy* nofree noundef nonnull align 8 dereferenceable(24) @global) #[[ATTR22:[0-9]+]] +; CGSCC-NEXT: call fastcc void @nested_memory_callee(float* nofree nonnull align 4294967296 undef, double* nofree nonnull align 4294967296 undef, %struct.STy* nofree noundef nonnull align 8 dereferenceable(24) @global) #[[ATTR25:[0-9]+]] ; CGSCC-NEXT: ret void ; entry: @@ -2817,7 +2929,7 @@ ; ; CGSCC: Function Attrs: nofree norecurse nosync nounwind willreturn uwtable ; CGSCC-LABEL: define {{[^@]+}}@nested_memory_callee -; CGSCC-SAME: (float* [[TMP0:%.*]], double* [[TMP1:%.*]], %struct.STy* [[TMP2:%.*]]) #[[ATTR12:[0-9]+]] { +; CGSCC-SAME: (float* [[TMP0:%.*]], double* [[TMP1:%.*]], %struct.STy* [[TMP2:%.*]]) #[[ATTR15:[0-9]+]] { ; CGSCC-NEXT: entry: ; CGSCC-NEXT: [[S_PRIV:%.*]] = alloca [[STRUCT_STY:%.*]], align 8 ; CGSCC-NEXT: [[S_PRIV_CAST:%.*]] = bitcast %struct.STy* [[S_PRIV]] to float** @@ -2902,11 +3014,11 @@ ; ; CGSCC: Function Attrs: argmemonly nofree norecurse nosync nounwind willreturn ; CGSCC-LABEL: define {{[^@]+}}@no_propagation_of_unknown_index_access -; CGSCC-SAME: (i32* nocapture nofree readonly [[IN:%.*]], i32* nocapture nofree writeonly [[OUT:%.*]], i32 [[IDX:%.*]]) #[[ATTR13:[0-9]+]] { +; CGSCC-SAME: (i32* nocapture nofree readonly [[IN:%.*]], i32* nocapture nofree writeonly [[OUT:%.*]], i32 [[IDX:%.*]]) #[[ATTR16:[0-9]+]] { ; CGSCC-NEXT: entry: ; CGSCC-NEXT: [[BUF:%.*]] = alloca [128 x i32], align 16 ; CGSCC-NEXT: [[TMP0:%.*]] = bitcast [128 x i32]* [[BUF]] to i8* -; CGSCC-NEXT: call void @llvm.lifetime.start.p0i8(i64 noundef 512, i8* nocapture nofree noundef nonnull align 16 dereferenceable(512) [[TMP0]]) #[[ATTR18]] +; CGSCC-NEXT: call void @llvm.lifetime.start.p0i8(i64 noundef 512, i8* nocapture nofree noundef nonnull align 16 dereferenceable(512) [[TMP0]]) #[[ATTR20]] ; CGSCC-NEXT: br label [[FOR_COND:%.*]] ; CGSCC: for.cond: ; CGSCC-NEXT: [[I_0:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[FOR_BODY:%.*]] ] @@ -2927,7 +3039,7 @@ ; CGSCC-NEXT: [[CMP5:%.*]] = icmp slt i32 [[I3_0]], 128 ; CGSCC-NEXT: br i1 [[CMP5]], label [[FOR_BODY7]], label [[FOR_COND_CLEANUP6:%.*]] ; CGSCC: for.cond.cleanup6: -; CGSCC-NEXT: call void @llvm.lifetime.end.p0i8(i64 noundef 512, i8* nocapture nofree noundef nonnull align 16 dereferenceable(512) [[TMP0]]) #[[ATTR18]] +; CGSCC-NEXT: call void @llvm.lifetime.end.p0i8(i64 noundef 512, i8* nocapture nofree noundef nonnull align 16 dereferenceable(512) [[TMP0]]) #[[ATTR20]] ; CGSCC-NEXT: ret void ; CGSCC: for.body7: ; CGSCC-NEXT: [[IDXPROM8:%.*]] = sext i32 [[I3_0]] to i64 @@ -3008,12 +3120,12 @@ ; ; CGSCC: Function Attrs: argmemonly nofree nosync nounwind ; CGSCC-LABEL: define {{[^@]+}}@alloca_non_unique -; CGSCC-SAME: (i32* nocapture nofree nonnull readonly align 4 [[P:%.*]], i32 [[IN:%.*]], i1 [[C:%.*]]) #[[ATTR14:[0-9]+]] { +; CGSCC-SAME: (i32* nocapture nofree nonnull readonly align 4 [[P:%.*]], i32 [[IN:%.*]], i1 [[C:%.*]]) #[[ATTR17:[0-9]+]] { ; CGSCC-NEXT: [[A:%.*]] = alloca i32, align 4 ; CGSCC-NEXT: store i32 [[IN]], i32* [[A]], align 4 ; CGSCC-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]] ; CGSCC: t: -; CGSCC-NEXT: [[R:%.*]] = call i1 @alloca_non_unique(i32* noalias nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[A]], i32 noundef 42, i1 noundef false) #[[ATTR23:[0-9]+]] +; CGSCC-NEXT: [[R:%.*]] = call i1 @alloca_non_unique(i32* noalias nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[A]], i32 noundef 42, i1 noundef false) #[[ATTR26:[0-9]+]] ; CGSCC-NEXT: ret i1 [[R]] ; CGSCC: f: ; CGSCC-NEXT: [[L:%.*]] = load i32, i32* [[P]], align 4 @@ -3042,8 +3154,8 @@ ; ; CGSCC: Function Attrs: nofree nosync nounwind readnone ; CGSCC-LABEL: define {{[^@]+}}@alloca_non_unique_caller -; CGSCC-SAME: (i32 [[IN:%.*]], i1 [[C:%.*]]) #[[ATTR15:[0-9]+]] { -; CGSCC-NEXT: [[R:%.*]] = call i1 @alloca_non_unique(i32* undef, i32 [[IN]], i1 [[C]]) #[[ATTR22]] +; CGSCC-SAME: (i32 [[IN:%.*]], i1 [[C:%.*]]) #[[ATTR18:[0-9]+]] { +; CGSCC-NEXT: [[R:%.*]] = call i1 @alloca_non_unique(i32* undef, i32 [[IN]], i1 [[C]]) #[[ATTR25]] ; CGSCC-NEXT: ret i1 [[R]] ; %r = call i1 @alloca_non_unique(i32* undef, i32 %in, i1 %c) @@ -3064,10 +3176,10 @@ ; ; CGSCC: Function Attrs: nofree nosync nounwind readnone willreturn ; CGSCC-LABEL: define {{[^@]+}}@scope_value_traversal -; CGSCC-SAME: (i32 [[BAD:%.*]], i1 [[C:%.*]], i1 [[C2:%.*]]) #[[ATTR16:[0-9]+]] { +; CGSCC-SAME: (i32 [[BAD:%.*]], i1 [[C:%.*]], i1 [[C2:%.*]]) #[[ATTR7]] { ; CGSCC-NEXT: [[A:%.*]] = alloca i32, align 4 ; CGSCC-NEXT: store i32 [[BAD]], i32* [[A]], align 4 -; CGSCC-NEXT: call void @scope_value_traversal_helper(i32* noalias nocapture nofree noundef nonnull align 4 dereferenceable(4) [[A]], i1 [[C2]]) #[[ATTR24:[0-9]+]] +; CGSCC-NEXT: call void @scope_value_traversal_helper(i32* noalias nocapture nofree noundef nonnull align 4 dereferenceable(4) [[A]], i1 [[C2]]) #[[ATTR27:[0-9]+]] ; CGSCC-NEXT: [[L:%.*]] = load i32, i32* [[A]], align 4 ; CGSCC-NEXT: [[SEL:%.*]] = select i1 [[C]], i32 [[BAD]], i32 [[L]] ; CGSCC-NEXT: ret i32 [[SEL]] @@ -3091,7 +3203,7 @@ ; ; CGSCC: Function Attrs: argmemonly nofree norecurse nosync nounwind willreturn ; CGSCC-LABEL: define {{[^@]+}}@scope_value_traversal_helper -; CGSCC-SAME: (i32* nocapture nofree noundef nonnull align 4 dereferenceable(4) [[A:%.*]], i1 [[C:%.*]]) #[[ATTR13]] { +; CGSCC-SAME: (i32* nocapture nofree noundef nonnull align 4 dereferenceable(4) [[A:%.*]], i1 [[C:%.*]]) #[[ATTR16]] { ; CGSCC-NEXT: [[L:%.*]] = load i32, i32* [[A]], align 4 ; CGSCC-NEXT: [[SEL:%.*]] = select i1 [[C]], i32 [[L]], i32 42 ; CGSCC-NEXT: store i32 [[SEL]], i32* [[A]], align 4 @@ -3167,26 +3279,29 @@ ; CGSCC: attributes #[[ATTR2:[0-9]+]] = { argmemonly nocallback nofree nosync nounwind willreturn } ; CGSCC: attributes #[[ATTR3]] = { nofree nosync nounwind willreturn } ; CGSCC: attributes #[[ATTR4]] = { nofree norecurse nosync nounwind readnone willreturn } -; CGSCC: attributes #[[ATTR5]] = { nofree norecurse nosync nounwind willreturn } -; CGSCC: attributes #[[ATTR6]] = { nofree norecurse nosync nounwind willreturn writeonly } -; CGSCC: attributes #[[ATTR7]] = { nofree norecurse nosync nounwind readonly willreturn } -; CGSCC: attributes #[[ATTR8]] = { nofree norecurse nosync nounwind writeonly } -; CGSCC: attributes #[[ATTR9:[0-9]+]] = { allockind("alloc,uninitialized") allocsize(0) "alloc-family"="malloc" } -; CGSCC: attributes #[[ATTR10:[0-9]+]] = { allockind("free") "alloc-family"="malloc" } -; CGSCC: attributes #[[ATTR11:[0-9]+]] = { allockind("alloc,zeroed") allocsize(0,1) "alloc-family"="malloc" } -; CGSCC: attributes #[[ATTR12]] = { nofree norecurse nosync nounwind willreturn uwtable } -; CGSCC: attributes #[[ATTR13]] = { argmemonly nofree norecurse nosync nounwind willreturn } -; CGSCC: attributes #[[ATTR14]] = { argmemonly nofree nosync nounwind } -; CGSCC: attributes #[[ATTR15]] = { nofree nosync nounwind readnone } -; CGSCC: attributes #[[ATTR16]] = { nofree nosync nounwind readnone willreturn } -; CGSCC: attributes #[[ATTR17:[0-9]+]] = { argmemonly nocallback nofree nounwind willreturn writeonly } -; CGSCC: attributes #[[ATTR18]] = { willreturn } -; CGSCC: attributes #[[ATTR19]] = { nounwind willreturn writeonly } -; CGSCC: attributes #[[ATTR20]] = { nocallback } -; CGSCC: attributes #[[ATTR21]] = { norecurse } -; CGSCC: attributes #[[ATTR22]] = { nounwind } -; CGSCC: attributes #[[ATTR23]] = { nofree nosync nounwind } -; CGSCC: attributes #[[ATTR24]] = { nounwind willreturn } +; CGSCC: attributes #[[ATTR5]] = { argmemonly nofree norecurse nosync nounwind readonly willreturn } +; CGSCC: attributes #[[ATTR6]] = { argmemonly nofree nosync nounwind readonly willreturn } +; CGSCC: attributes #[[ATTR7]] = { nofree nosync nounwind readnone willreturn } +; CGSCC: attributes #[[ATTR8]] = { nofree norecurse nosync nounwind willreturn } +; CGSCC: attributes #[[ATTR9]] = { nofree norecurse nosync nounwind willreturn writeonly } +; CGSCC: attributes #[[ATTR10]] = { nofree norecurse nosync nounwind readonly willreturn } +; CGSCC: attributes #[[ATTR11]] = { nofree norecurse nosync nounwind writeonly } +; CGSCC: attributes #[[ATTR12:[0-9]+]] = { allockind("alloc,uninitialized") allocsize(0) "alloc-family"="malloc" } +; CGSCC: attributes #[[ATTR13:[0-9]+]] = { allockind("free") "alloc-family"="malloc" } +; CGSCC: attributes #[[ATTR14:[0-9]+]] = { allockind("alloc,zeroed") allocsize(0,1) "alloc-family"="malloc" } +; CGSCC: attributes #[[ATTR15]] = { nofree norecurse nosync nounwind willreturn uwtable } +; CGSCC: attributes #[[ATTR16]] = { argmemonly nofree norecurse nosync nounwind willreturn } +; CGSCC: attributes #[[ATTR17]] = { argmemonly nofree nosync nounwind } +; CGSCC: attributes #[[ATTR18]] = { nofree nosync nounwind readnone } +; CGSCC: attributes #[[ATTR19:[0-9]+]] = { argmemonly nocallback nofree nounwind willreturn writeonly } +; CGSCC: attributes #[[ATTR20]] = { willreturn } +; CGSCC: attributes #[[ATTR21]] = { nounwind willreturn writeonly } +; CGSCC: attributes #[[ATTR22]] = { readonly willreturn } +; CGSCC: attributes #[[ATTR23]] = { nocallback } +; CGSCC: attributes #[[ATTR24]] = { norecurse } +; CGSCC: attributes #[[ATTR25]] = { nounwind } +; CGSCC: attributes #[[ATTR26]] = { nofree nosync nounwind } +; CGSCC: attributes #[[ATTR27]] = { nounwind willreturn } ;. ; TUNIT: [[META0:![0-9]+]] = !{i32 1, !"wchar_size", i32 4} ; TUNIT: [[META1:![0-9]+]] = !{i32 7, !"uwtable", i32 1}