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 @@ -5973,6 +5973,40 @@ AA::ValueScope Scope = AA::Interprocedural) const = 0; }; +/// An abstract interface for address space information. +struct AAAddressSpaceInfo + : public StateWrapper { + AAAddressSpaceInfo(const IRPosition &IRP, Attributor &A) + : StateWrapper(IRP) {} + + /// Return the address space of the associated value. \p NoAddressSpace is + /// returned if the associated value is dead. This functions is not supposed + /// to be called if the AA is invalid. + virtual int64_t getAddressSpace() const = 0; + + /// Create an abstract attribute view for the position \p IRP. + static AAAddressSpaceInfo &createForPosition(const IRPosition &IRP, + Attributor &A); + + /// See AbstractAttribute::getName() + const std::string getName() const override { return "AAAddressSpaceInfo"; } + + /// See AbstractAttribute::getIdAddr() + const char *getIdAddr() const override { return &ID; } + + /// This function should return true if the type of the \p AA is + /// AAAssumptionInfo + static bool classof(const AbstractAttribute *AA) { + return (AA->getIdAddr() == &ID); + } + + // No address space which indicates the associated value is dead. + static const int64_t NoAddressSpace = -1; + + /// Unique ID (due to the unique address) + static const char ID; +}; + raw_ostream &operator<<(raw_ostream &, const AAPointerInfo::Access &); /// Run options, used by the pass manager. 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 @@ -3502,18 +3502,21 @@ assert(Success && "Expected the check call to be successful!"); auto LoadStorePred = [&](Instruction &I) -> bool { - if (isa(I)) { - getOrCreateAAFor( - IRPosition::value(*cast(I).getPointerOperand())); + if (auto *LI = dyn_cast(&I)) { + getOrCreateAAFor(IRPosition::value(*LI->getPointerOperand())); if (SimplifyAllLoads) getAssumedSimplified(IRPosition::value(I), nullptr, UsedAssumedInformation, AA::Intraprocedural); + getOrCreateAAFor( + IRPosition::value(*LI->getPointerOperand())); } else { auto &SI = cast(I); getOrCreateAAFor(IRPosition::inst(I)); getAssumedSimplified(IRPosition::value(*SI.getValueOperand()), nullptr, UsedAssumedInformation, AA::Intraprocedural); getOrCreateAAFor(IRPosition::value(*SI.getPointerOperand())); + getOrCreateAAFor( + IRPosition::value(*SI.getPointerOperand())); } return true; }; 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 @@ -187,6 +187,7 @@ PIPE_OPERATOR(AAPointerInfo) PIPE_OPERATOR(AAAssumptionInfo) PIPE_OPERATOR(AAUnderlyingObjects) +PIPE_OPERATOR(AAAddressSpaceInfo) #undef PIPE_OPERATOR @@ -11856,6 +11857,159 @@ }; } +/// ------------------------ Address Space Propagation ------------------------- +namespace { +struct AAAddressSpaceInfoImpl : public AAAddressSpaceInfo { + AAAddressSpaceInfoImpl(const IRPosition &IRP, Attributor &A) + : AAAddressSpaceInfo(IRP, A) {} + + int64_t getAddressSpace() const override { + assert(isValidState() && "the AA is invalid"); + return AssumedAddressSpace; + } + + /// See AbstractAttribute::initialize(...). + void initialize(Attributor &A) override { + assert(getAssociatedType()->isPointerTy() && + "Associated value is not a pointer"); + A.getAAFor(*this, getIRPosition(), DepClassTy::OPTIONAL); + } + + ChangeStatus updateImpl(Attributor &A) override { + auto *AUO = A.getOrCreateAAFor(getIRPosition(), this, + DepClassTy::OPTIONAL); + if (!AUO->getState().isValidState()) + return takeAddressSpace(getAssociatedType()->getPointerAddressSpace()) + ? ChangeStatus::CHANGED + : ChangeStatus::UNCHANGED; + + int64_t OldAddressSpace = AssumedAddressSpace; + + auto Pred = [&](Value &Obj) { + if (isa(&Obj)) + return true; + uint32_t AS = Obj.getType()->getPointerAddressSpace(); + if (AssumedAddressSpace == NoAddressSpace) { + (void)takeAddressSpace(AS); + return true; + } + assert(AssumedAddressSpace >= 0 && + "AssumedAddressSpace should not be negative"); + return AS == static_cast(AssumedAddressSpace); + }; + + if (!AUO->forallUnderlyingObjects(Pred)) + return indicatePessimisticFixpoint(); + + return OldAddressSpace == AssumedAddressSpace ? ChangeStatus::UNCHANGED + : ChangeStatus::CHANGED; + } + + /// See AbstractAttribute::manifest(...). + ChangeStatus manifest(Attributor &A) override { + Value *AssociatedValue = &getAssociatedValue(); + if (getAddressSpace() == NoAddressSpace || + static_cast(getAddressSpace()) == + getAssociatedType()->getPointerAddressSpace()) + return ChangeStatus::UNCHANGED; + + Type *NewPtrTy = PointerType::getWithSamePointeeType( + cast(getAssociatedType()), + static_cast(getAddressSpace())); + + bool Changed = false; + + auto Pred = [&](const Use &U, bool &) { + if (U.get() != AssociatedValue) + return true; + User *Usr = U.getUser(); + if (isa(Usr) || isa(Usr)) { + Instruction *CastInst = new AddrSpaceCastInst(AssociatedValue, NewPtrTy); + CastInst->insertBefore(cast(Usr)); + A.changeUseAfterManifest(const_cast(U), *CastInst); + Changed = true; + } + return true; + }; + + // It doesn't matter if we can't check all uses as we can simply + // conservatively ignore those that can not be visited. + (void)A.checkForAllUses(Pred, *this, getAssociatedValue(), + /* CheckBBLivenessOnly */ true); + + return Changed ? ChangeStatus::CHANGED : ChangeStatus::UNCHANGED; + } + + /// See AbstractAttribute::getAsStr(). + const std::string getAsStr() const override { + return "addrspace(" + + (AssumedAddressSpace == NoAddressSpace + ? "none" + : std::to_string(AssumedAddressSpace)) + + ")"; + } + +private: + // We use an int64_t to make sure the cast from uint32_t does not overflow. + int64_t AssumedAddressSpace = NoAddressSpace; + + bool takeAddressSpace(uint32_t AS) { + int64_t OldAddressSpace = AssumedAddressSpace; + AssumedAddressSpace = static_cast(AS); + return OldAddressSpace != AssumedAddressSpace; + } +}; + +struct AAAddressSpaceInfoFloating final : AAAddressSpaceInfoImpl { + AAAddressSpaceInfoFloating(const IRPosition &IRP, Attributor &A) + : AAAddressSpaceInfoImpl(IRP, A) {} + + void trackStatistics() const override { + STATS_DECLTRACK_FLOATING_ATTR(addrspace); + } +}; + +struct AAAddressSpaceInfoReturned final : AAAddressSpaceInfoImpl { + AAAddressSpaceInfoReturned(const IRPosition &IRP, Attributor &A) + : AAAddressSpaceInfoImpl(IRP, A) {} + + void trackStatistics() const override { + STATS_DECLTRACK_FNRET_ATTR(addrspace); + } +}; + +struct AAAddressSpaceInfoCallSiteReturned final : AAAddressSpaceInfoImpl { + AAAddressSpaceInfoCallSiteReturned(const IRPosition &IRP, Attributor &A) + : AAAddressSpaceInfoImpl(IRP, A) {} + + void trackStatistics() const override { + STATS_DECLTRACK_CSRET_ATTR(addrspace); + } +}; + +struct AAAddressSpaceInfoArgument final : AAAddressSpaceInfoImpl { + AAAddressSpaceInfoArgument(const IRPosition &IRP, Attributor &A) + : AAAddressSpaceInfoImpl(IRP, A) {} + + void trackStatistics() const override { STATS_DECLTRACK_ARG_ATTR(addrspace); } +}; + +struct AAAddressSpaceInfoCallSiteArgument final : AAAddressSpaceInfoImpl { + AAAddressSpaceInfoCallSiteArgument(const IRPosition &IRP, Attributor &A) + : AAAddressSpaceInfoImpl(IRP, A) {} + + // We don't rewrite call site argument for now because it will need to rewrite + // the function signature of the callee. + ChangeStatus updateImpl(Attributor &A) override { + return ChangeStatus::UNCHANGED; + }; + + void trackStatistics() const override { + STATS_DECLTRACK_CSARG_ATTR(addrspace); + } +}; +} // namespace + const char AAReturnedValues::ID = 0; const char AANoUnwind::ID = 0; const char AANoSync::ID = 0; @@ -11889,6 +12043,7 @@ const char AAPointerInfo::ID = 0; const char AAAssumptionInfo::ID = 0; const char AAUnderlyingObjects::ID = 0; +const char AAAddressSpaceInfo::ID = 0; // Macro magic to create the static generator function for attributes that // follow the naming scheme. @@ -12007,6 +12162,7 @@ CREATE_VALUE_ABSTRACT_ATTRIBUTE_FOR_POSITION(AANoUndef) CREATE_VALUE_ABSTRACT_ATTRIBUTE_FOR_POSITION(AANoFPClass) CREATE_VALUE_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAPointerInfo) +CREATE_VALUE_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAAddressSpaceInfo) CREATE_ALL_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAValueSimplify) CREATE_ALL_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAIsDead) diff --git a/llvm/test/Transforms/Attributor/IPConstantProp/PR26044.ll b/llvm/test/Transforms/Attributor/IPConstantProp/PR26044.ll --- a/llvm/test/Transforms/Attributor/IPConstantProp/PR26044.ll +++ b/llvm/test/Transforms/Attributor/IPConstantProp/PR26044.ll @@ -77,11 +77,10 @@ ; TUNIT: for.cond1: ; TUNIT-NEXT: br i1 [[C]], label [[IF_END]], label [[EXIT:%.*]] ; TUNIT: if.end: -; TUNIT-NEXT: [[E_2:%.*]] = phi ptr [ undef, [[ENTRY:%.*]] ], [ null, [[FOR_COND1:%.*]] ] ; TUNIT-NEXT: [[TMP0:%.*]] = load i32, ptr null, align 4294967296 ; TUNIT-NEXT: [[CALL:%.*]] = call i32 @fn0(i32 [[TMP0]]) #[[ATTR3]] ; TUNIT-NEXT: store i32 [[CALL]], ptr [[P]], align 4 -; TUNIT-NEXT: br label [[FOR_COND1]] +; TUNIT-NEXT: br label [[FOR_COND1:%.*]] ; TUNIT: exit: ; TUNIT-NEXT: ret void ; @@ -93,11 +92,10 @@ ; CGSCC: for.cond1: ; CGSCC-NEXT: br i1 [[C]], label [[IF_END]], label [[EXIT:%.*]] ; CGSCC: if.end: -; CGSCC-NEXT: [[E_2:%.*]] = phi ptr [ undef, [[ENTRY:%.*]] ], [ null, [[FOR_COND1:%.*]] ] ; CGSCC-NEXT: [[TMP0:%.*]] = load i32, ptr null, align 4294967296 ; CGSCC-NEXT: [[CALL:%.*]] = call i32 @fn0(i32 [[TMP0]]) #[[ATTR3]] ; CGSCC-NEXT: store i32 [[CALL]], ptr [[P]], align 4 -; CGSCC-NEXT: br label [[FOR_COND1]] +; CGSCC-NEXT: br label [[FOR_COND1:%.*]] ; CGSCC: exit: ; CGSCC-NEXT: ret void ; diff --git a/llvm/test/Transforms/Attributor/address_space_info.ll b/llvm/test/Transforms/Attributor/address_space_info.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Transforms/Attributor/address_space_info.ll @@ -0,0 +1,159 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes --check-globals --prefix-filecheck-ir-name true +; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK + +@dst = dso_local addrspace(1) externally_initialized global i32 0, align 4 +@g1 = dso_local addrspace(1) externally_initialized global i32 0, align 4 +@g2 = dso_local addrspace(1) externally_initialized global i32 0, align 4 +@s1 = dso_local addrspace(3) global i32 undef, align 4 +@s2 = dso_local addrspace(3) global i32 undef, align 4 +@llvm.compiler.used = appending global [3 x ptr] [ptr addrspacecast (ptr addrspace(1) @dst to ptr), ptr addrspacecast (ptr addrspace(1) @g1 to ptr), ptr addrspacecast (ptr addrspace(1) @g2 to ptr)], section "llvm.metadata" + +; Function Attrs: convergent mustprogress noinline nounwind +;. +; CHECK: @[[DST:[a-zA-Z0-9_$"\\.-]+]] = dso_local addrspace(1) externally_initialized global i32 0, align 4 +; CHECK: @[[G1:[a-zA-Z0-9_$"\\.-]+]] = dso_local addrspace(1) externally_initialized global i32 0, align 4 +; CHECK: @[[G2:[a-zA-Z0-9_$"\\.-]+]] = dso_local addrspace(1) externally_initialized global i32 0, align 4 +; CHECK: @[[S1:[a-zA-Z0-9_$"\\.-]+]] = dso_local addrspace(3) global i32 undef, align 4 +; CHECK: @[[S2:[a-zA-Z0-9_$"\\.-]+]] = dso_local addrspace(3) global i32 undef, align 4 +; CHECK: @[[LLVM_COMPILER_USED:[a-zA-Z0-9_$"\\.-]+]] = appending global [3 x ptr] [ptr addrspacecast (ptr addrspace(1) @dst to ptr), ptr addrspacecast (ptr addrspace(1) @g1 to ptr), ptr addrspacecast (ptr addrspace(1) @g2 to ptr)], section "llvm.metadata" +;. +define internal void @_Z12global_writePi(ptr noundef %p) #0 { +; CHECK: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(write) +; CHECK-LABEL: define {{[^@]+}}@_Z12global_writePi +; CHECK-SAME: (ptr nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) [[P:%.*]]) #[[ATTR0:[0-9]+]] { +; CHECK-NEXT: entry: +; CHECK-NEXT: [[TMP0:%.*]] = addrspacecast ptr [[P]] to ptr addrspace(1) +; CHECK-NEXT: store i32 1, ptr addrspace(1) [[TMP0]], align 4 +; CHECK-NEXT: ret void +; +entry: + store i32 1, ptr %p, align 4 + ret void +} + +; Function Attrs: convergent mustprogress noinline nounwind +define internal void @_Z13unknown_writePi(ptr noundef %p) #0 { +; CHECK: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(write) +; CHECK-LABEL: define {{[^@]+}}@_Z13unknown_writePi +; CHECK-SAME: (ptr nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) [[P:%.*]]) #[[ATTR0]] { +; CHECK-NEXT: entry: +; CHECK-NEXT: store i32 2, ptr [[P]], align 4 +; CHECK-NEXT: ret void +; +entry: + store i32 2, ptr %p, align 4 + ret void +} + +; Function Attrs: convergent mustprogress noinline nounwind +define internal void @_Z12shared_writePi(ptr noundef %p) #0 { +; CHECK: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(write) +; CHECK-LABEL: define {{[^@]+}}@_Z12shared_writePi +; CHECK-SAME: (ptr nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) [[P:%.*]]) #[[ATTR0]] { +; CHECK-NEXT: entry: +; CHECK-NEXT: [[TMP0:%.*]] = addrspacecast ptr [[P]] to ptr addrspace(3) +; CHECK-NEXT: store i32 3, ptr addrspace(3) [[TMP0]], align 4 +; CHECK-NEXT: ret void +; +entry: + store i32 3, ptr %p, align 4 + ret void +} + +; Function Attrs: convergent mustprogress noinline nounwind +define internal void @_Z11global_readPi(ptr noundef %p) #0 { +; CHECK: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn +; CHECK-LABEL: define {{[^@]+}}@_Z11global_readPi +; CHECK-SAME: (ptr nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[P:%.*]]) #[[ATTR1:[0-9]+]] { +; CHECK-NEXT: entry: +; CHECK-NEXT: [[TMP0:%.*]] = addrspacecast ptr [[P]] to ptr addrspace(1) +; CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr addrspace(1) [[TMP0]], align 4 +; CHECK-NEXT: [[TMP2:%.*]] = addrspacecast ptr addrspacecast (ptr addrspace(1) @dst to ptr) to ptr addrspace(1) +; CHECK-NEXT: store i32 [[TMP1]], ptr addrspace(1) [[TMP2]], align 4 +; CHECK-NEXT: ret void +; +entry: + %0 = load i32, ptr %p, align 4 + store i32 %0, ptr addrspacecast (ptr addrspace(1) @dst to ptr), align 4 + ret void +} + +; Function Attrs: convergent mustprogress noinline nounwind +define internal void @_Z12unknown_readPi(ptr noundef %p) #0 { +; CHECK: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn +; CHECK-LABEL: define {{[^@]+}}@_Z12unknown_readPi +; CHECK-SAME: (ptr nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[P:%.*]]) #[[ATTR1]] { +; CHECK-NEXT: entry: +; CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[P]], align 4 +; CHECK-NEXT: [[TMP1:%.*]] = addrspacecast ptr addrspacecast (ptr addrspace(1) @dst to ptr) to ptr addrspace(1) +; CHECK-NEXT: store i32 [[TMP0]], ptr addrspace(1) [[TMP1]], align 4 +; CHECK-NEXT: ret void +; +entry: + %0 = load i32, ptr %p, align 4 + store i32 %0, ptr addrspacecast (ptr addrspace(1) @dst to ptr), align 4 + ret void +} + +; Function Attrs: convergent mustprogress noinline nounwind +define internal void @_Z11shared_readPi(ptr noundef %p) #0 { +; CHECK: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn +; CHECK-LABEL: define {{[^@]+}}@_Z11shared_readPi +; CHECK-SAME: (ptr nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[P:%.*]]) #[[ATTR1]] { +; CHECK-NEXT: entry: +; CHECK-NEXT: [[TMP0:%.*]] = addrspacecast ptr [[P]] to ptr addrspace(3) +; CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr addrspace(3) [[TMP0]], align 4 +; CHECK-NEXT: [[TMP2:%.*]] = addrspacecast ptr addrspacecast (ptr addrspace(1) @dst to ptr) to ptr addrspace(1) +; CHECK-NEXT: store i32 [[TMP1]], ptr addrspace(1) [[TMP2]], align 4 +; CHECK-NEXT: ret void +; +entry: + %0 = load i32, ptr %p, align 4 + store i32 %0, ptr addrspacecast (ptr addrspace(1) @dst to ptr), align 4 + ret void +} + +; Function Attrs: convergent mustprogress noinline nounwind +define dso_local void @_Z3bazv() #0 { +; CHECK: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn +; CHECK-LABEL: define {{[^@]+}}@_Z3bazv +; CHECK-SAME: () #[[ATTR1]] { +; CHECK-NEXT: entry: +; CHECK-NEXT: call void @_Z12global_writePi(ptr nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) addrspacecast (ptr addrspace(1) @g1 to ptr)) #[[ATTR2:[0-9]+]] +; CHECK-NEXT: call void @_Z12global_writePi(ptr nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) addrspacecast (ptr addrspace(1) @g2 to ptr)) #[[ATTR2]] +; CHECK-NEXT: call void @_Z13unknown_writePi(ptr nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) addrspacecast (ptr addrspace(1) @g1 to ptr)) #[[ATTR2]] +; CHECK-NEXT: call void @_Z13unknown_writePi(ptr nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) addrspacecast (ptr addrspace(3) @s1 to ptr)) #[[ATTR2]] +; CHECK-NEXT: call void @_Z12shared_writePi(ptr nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) addrspacecast (ptr addrspace(3) @s1 to ptr)) #[[ATTR2]] +; CHECK-NEXT: call void @_Z12shared_writePi(ptr nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) addrspacecast (ptr addrspace(3) @s2 to ptr)) #[[ATTR2]] +; CHECK-NEXT: call void @_Z11global_readPi(ptr nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) addrspacecast (ptr addrspace(1) @g1 to ptr)) #[[ATTR3:[0-9]+]] +; CHECK-NEXT: call void @_Z11global_readPi(ptr nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) addrspacecast (ptr addrspace(1) @g2 to ptr)) #[[ATTR3]] +; CHECK-NEXT: call void @_Z12unknown_readPi(ptr nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) addrspacecast (ptr addrspace(1) @g1 to ptr)) #[[ATTR3]] +; CHECK-NEXT: call void @_Z12unknown_readPi(ptr nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) addrspacecast (ptr addrspace(3) @s1 to ptr)) #[[ATTR3]] +; CHECK-NEXT: call void @_Z11shared_readPi(ptr nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) addrspacecast (ptr addrspace(3) @s1 to ptr)) #[[ATTR3]] +; CHECK-NEXT: call void @_Z11shared_readPi(ptr nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) addrspacecast (ptr addrspace(3) @s2 to ptr)) #[[ATTR3]] +; CHECK-NEXT: ret void +; +entry: + call void @_Z12global_writePi(ptr noundef addrspacecast (ptr addrspace(1) @g1 to ptr)) #1 + call void @_Z12global_writePi(ptr noundef addrspacecast (ptr addrspace(1) @g2 to ptr)) #1 + call void @_Z13unknown_writePi(ptr noundef addrspacecast (ptr addrspace(1) @g1 to ptr)) #1 + call void @_Z13unknown_writePi(ptr noundef addrspacecast (ptr addrspace(3) @s1 to ptr)) #1 + call void @_Z12shared_writePi(ptr noundef addrspacecast (ptr addrspace(3) @s1 to ptr)) #1 + call void @_Z12shared_writePi(ptr noundef addrspacecast (ptr addrspace(3) @s2 to ptr)) #1 + call void @_Z11global_readPi(ptr noundef addrspacecast (ptr addrspace(1) @g1 to ptr)) #1 + call void @_Z11global_readPi(ptr noundef addrspacecast (ptr addrspace(1) @g2 to ptr)) #1 + call void @_Z12unknown_readPi(ptr noundef addrspacecast (ptr addrspace(1) @g1 to ptr)) #1 + call void @_Z12unknown_readPi(ptr noundef addrspacecast (ptr addrspace(3) @s1 to ptr)) #1 + call void @_Z11shared_readPi(ptr noundef addrspacecast (ptr addrspace(3) @s1 to ptr)) #1 + call void @_Z11shared_readPi(ptr noundef addrspacecast (ptr addrspace(3) @s2 to ptr)) #1 + ret void +} + +attributes #0 = { convergent mustprogress noinline nounwind } +attributes #1 = { convergent nounwind } +;. +; CHECK: attributes #[[ATTR0]] = { mustprogress nofree noinline norecurse nosync nounwind willreturn memory(write) } +; CHECK: attributes #[[ATTR1]] = { mustprogress nofree noinline norecurse nosync nounwind willreturn } +; CHECK: attributes #[[ATTR2]] = { convergent nofree nosync nounwind willreturn memory(write) } +; CHECK: attributes #[[ATTR3]] = { convergent nofree nosync nounwind willreturn } +;. diff --git a/llvm/test/Transforms/Attributor/depgraph.ll b/llvm/test/Transforms/Attributor/depgraph.ll --- a/llvm/test/Transforms/Attributor/depgraph.ll +++ b/llvm/test/Transforms/Attributor/depgraph.ll @@ -239,6 +239,8 @@ ; GRAPH-EMPTY: ; GRAPH-NEXT: [AANoFree] for CtxI ' %6 = call ptr @checkAndAdvance(ptr %5)' at position {cs_arg: [@0]} with state nofree ; GRAPH-EMPTY: +; GRAPH-NEXT: [AAAddressSpaceInfo] for CtxI ' %2 = load i32, ptr %0, align 4' at position {arg: [@0]} with state addrspace(0) +; GRAPH-EMPTY: ; GRAPH-NEXT: [AADereferenceable] for CtxI ' %5 = getelementptr inbounds i32, ptr %0, i64 4' at position {flt: [@-1]} with state unknown-dereferenceable ; GRAPH-NOT: update @@ -320,6 +322,7 @@ ; DOT-DAG: Node[[Node71:0x[a-z0-9]+]] [shape=record,label="{[AANoAlias] ; DOT-DAG: Node[[Node72:0x[a-z0-9]+]] [shape=record,label="{[AANoAlias] ; DOT-DAG: Node[[Node73:0x[a-z0-9]+]] [shape=record,label="{[AANoFree] +; DOT-DAG: Node[[Node75:0x[a-z0-9]+]] [shape=record,label="{[AAAddressSpaceInfo] ; DOT-DAG: Node[[Node74:0x[a-z0-9]+]] [shape=record,label="{[AADereferenceable] ; DOT-DAG: Node[[Node20]] -> Node[[Node19]]; diff --git a/llvm/test/Transforms/Attributor/memory_locations_gpu.ll b/llvm/test/Transforms/Attributor/memory_locations_gpu.ll --- a/llvm/test/Transforms/Attributor/memory_locations_gpu.ll +++ b/llvm/test/Transforms/Attributor/memory_locations_gpu.ll @@ -42,7 +42,8 @@ ; CHECK-SAME: () #[[ATTR2:[0-9]+]] { ; CHECK-NEXT: [[P1:%.*]] = call ptr addrspace(4) @ptr_to_const() ; CHECK-NEXT: [[C1:%.*]] = addrspacecast ptr addrspace(4) [[P1]] to ptr -; CHECK-NEXT: [[L1:%.*]] = load i32, ptr [[C1]], align 4 +; CHECK-NEXT: [[TMP1:%.*]] = addrspacecast ptr [[C1]] to ptr addrspace(4) +; CHECK-NEXT: [[L1:%.*]] = load i32, ptr addrspace(4) [[TMP1]], align 4 ; CHECK-NEXT: ret i32 [[L1]] ; %p1 = call ptr addrspace(4) @ptr_to_const() @@ -57,7 +58,8 @@ ; CHECK-SAME: () #[[ATTR3:[0-9]+]] { ; CHECK-NEXT: [[P2:%.*]] = call ptr @ptr() ; CHECK-NEXT: [[C2:%.*]] = addrspacecast ptr [[P2]] to ptr addrspace(4) -; CHECK-NEXT: [[L2:%.*]] = load i32, ptr addrspace(4) [[C2]], align 4 +; CHECK-NEXT: [[TMP1:%.*]] = addrspacecast ptr addrspace(4) [[C2]] to ptr +; CHECK-NEXT: [[L2:%.*]] = load i32, ptr [[TMP1]], align 4 ; CHECK-NEXT: ret i32 [[L2]] ; %p2 = call ptr @ptr() @@ -73,7 +75,8 @@ ; CHECK-SAME: () #[[ATTR2]] { ; CHECK-NEXT: [[P1:%.*]] = call ptr addrspace(3) @ptr_to_shared() ; CHECK-NEXT: [[C1:%.*]] = addrspacecast ptr addrspace(3) [[P1]] to ptr -; CHECK-NEXT: [[L1:%.*]] = load i32, ptr [[C1]], align 4 +; CHECK-NEXT: [[TMP1:%.*]] = addrspacecast ptr [[C1]] to ptr addrspace(3) +; CHECK-NEXT: [[L1:%.*]] = load i32, ptr addrspace(3) [[TMP1]], align 4 ; CHECK-NEXT: ret i32 [[L1]] ; %p1 = call ptr addrspace(3) @ptr_to_shared() @@ -88,7 +91,8 @@ ; CHECK-SAME: () #[[ATTR2]] { ; CHECK-NEXT: [[P2:%.*]] = call ptr @ptr() ; CHECK-NEXT: [[C2:%.*]] = addrspacecast ptr [[P2]] to ptr addrspace(3) -; CHECK-NEXT: [[L2:%.*]] = load i32, ptr addrspace(3) [[C2]], align 4 +; CHECK-NEXT: [[TMP1:%.*]] = addrspacecast ptr addrspace(3) [[C2]] to ptr +; CHECK-NEXT: [[L2:%.*]] = load i32, ptr [[TMP1]], align 4 ; CHECK-NEXT: ret i32 [[L2]] ; %p2 = call ptr @ptr() diff --git a/llvm/test/Transforms/Attributor/undefined_behavior.ll b/llvm/test/Transforms/Attributor/undefined_behavior.ll --- a/llvm/test/Transforms/Attributor/undefined_behavior.ll +++ b/llvm/test/Transforms/Attributor/undefined_behavior.ll @@ -75,7 +75,7 @@ ; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) ; TUNIT-LABEL: define {{[^@]+}}@load_null_propagated ; TUNIT-SAME: () #[[ATTR0]] { -; TUNIT-NEXT: unreachable +; TUNIT-NEXT: ret void ; ; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none) ; CGSCC-LABEL: define {{[^@]+}}@load_null_propagated @@ -158,7 +158,7 @@ ; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) ; TUNIT-LABEL: define {{[^@]+}}@store_null_propagated ; TUNIT-SAME: () #[[ATTR0]] { -; TUNIT-NEXT: unreachable +; TUNIT-NEXT: ret void ; ; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(write) ; CGSCC-LABEL: define {{[^@]+}}@store_null_propagated @@ -239,7 +239,8 @@ ; TUNIT: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(none) ; TUNIT-LABEL: define {{[^@]+}}@atomicrmw_null_propagated ; TUNIT-SAME: () #[[ATTR2]] { -; TUNIT-NEXT: unreachable +; TUNIT-NEXT: [[A:%.*]] = atomicrmw add ptr null, i32 1 acquire, align 4 +; TUNIT-NEXT: ret void ; ; CGSCC: Function Attrs: mustprogress nofree nounwind willreturn ; CGSCC-LABEL: define {{[^@]+}}@atomicrmw_null_propagated @@ -321,7 +322,8 @@ ; TUNIT: Function Attrs: mustprogress nofree norecurse nounwind willreturn memory(none) ; TUNIT-LABEL: define {{[^@]+}}@atomiccmpxchg_null_propagated ; TUNIT-SAME: () #[[ATTR2]] { -; TUNIT-NEXT: unreachable +; TUNIT-NEXT: [[A:%.*]] = cmpxchg ptr null, i32 2, i32 3 acq_rel monotonic, align 4 +; TUNIT-NEXT: ret void ; ; CGSCC: Function Attrs: mustprogress nofree nounwind willreturn ; CGSCC-LABEL: define {{[^@]+}}@atomiccmpxchg_null_propagated diff --git a/llvm/test/Transforms/Attributor/value-simplify-local-remote.ll b/llvm/test/Transforms/Attributor/value-simplify-local-remote.ll --- a/llvm/test/Transforms/Attributor/value-simplify-local-remote.ll +++ b/llvm/test/Transforms/Attributor/value-simplify-local-remote.ll @@ -342,14 +342,6 @@ ; CHECK-NEXT: entry: ; CHECK-NEXT: [[RETVAL:%.*]] = alloca [[S_2:%.*]], align 8 ; CHECK-NEXT: call void @ext1(ptr noundef nonnull align 8 dereferenceable(24) [[RETVAL]]) -; CHECK-NEXT: [[DOTFCA_0_LOAD:%.*]] = load ptr, ptr [[RETVAL]], align 8 -; CHECK-NEXT: [[DOTFCA_0_INSERT:%.*]] = insertvalue [[S_2]] poison, ptr [[DOTFCA_0_LOAD]], 0 -; CHECK-NEXT: [[DOTFCA_1_GEP:%.*]] = getelementptr inbounds [[S_2]], ptr [[RETVAL]], i32 0, i32 1 -; CHECK-NEXT: [[DOTFCA_1_LOAD:%.*]] = load i64, ptr [[DOTFCA_1_GEP]], align 8 -; CHECK-NEXT: [[DOTFCA_1_INSERT:%.*]] = insertvalue [[S_2]] [[DOTFCA_0_INSERT]], i64 [[DOTFCA_1_LOAD]], 1 -; CHECK-NEXT: [[DOTFCA_2_GEP:%.*]] = getelementptr inbounds [[S_2]], ptr [[RETVAL]], i32 0, i32 2 -; CHECK-NEXT: [[DOTFCA_2_LOAD:%.*]] = load i64, ptr [[DOTFCA_2_GEP]], align 8 -; CHECK-NEXT: [[DOTFCA_2_INSERT:%.*]] = insertvalue [[S_2]] [[DOTFCA_1_INSERT]], i64 [[DOTFCA_2_LOAD]], 2 ; CHECK-NEXT: ret [[S_2]] zeroinitializer ; entry: