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 @@ -6017,6 +6017,46 @@ AA::ValueScope Scope = AA::Interprocedural) const = 0; }; +/// An abstract interface for address space information. +struct AAAddressSpace : public StateWrapper { + AAAddressSpace(const IRPosition &IRP, Attributor &A) + : StateWrapper(IRP) {} + + /// See AbstractAttribute::isValidIRPositionForInit + static bool isValidIRPositionForInit(Attributor &A, const IRPosition &IRP) { + if (!IRP.getAssociatedType()->isPtrOrPtrVectorTy()) + return false; + return AbstractAttribute::isValidIRPositionForInit(A, 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 int32_t getAddressSpace() const = 0; + + /// Create an abstract attribute view for the position \p IRP. + static AAAddressSpace &createForPosition(const IRPosition &IRP, + Attributor &A); + + /// See AbstractAttribute::getName() + const std::string getName() const override { return "AAAddressSpace"; } + + /// 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 int32_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 @@ -3501,18 +3501,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 @@ -188,6 +188,7 @@ PIPE_OPERATOR(AAPointerInfo) PIPE_OPERATOR(AAAssumptionInfo) PIPE_OPERATOR(AAUnderlyingObjects) +PIPE_OPERATOR(AAAddressSpace) #undef PIPE_OPERATOR @@ -12022,6 +12023,182 @@ }; } // namespace +/// ------------------------ Address Space ------------------------------------ +namespace { +struct AAAddressSpaceImpl : public AAAddressSpace { + AAAddressSpaceImpl(const IRPosition &IRP, Attributor &A) + : AAAddressSpace(IRP, A) {} + + int32_t getAddressSpace() const override { + assert(isValidState() && "the AA is invalid"); + return AssumedAddressSpace; + } + + /// See AbstractAttribute::initialize(...). + void initialize(Attributor &A) override { + assert(getAssociatedType()->isPtrOrPtrVectorTy() && + "Associated value is not a pointer"); + } + + ChangeStatus updateImpl(Attributor &A) override { + int32_t OldAddressSpace = AssumedAddressSpace; + auto *AUO = A.getOrCreateAAFor(getIRPosition(), this, + DepClassTy::REQUIRED); + auto Pred = [&](Value &Obj) { + if (isa(&Obj)) + return true; + return takeAddressSpace(Obj.getType()->getPointerAddressSpace()); + }; + + if (!AUO->forallUnderlyingObjects(Pred)) + return indicatePessimisticFixpoint(); + + return OldAddressSpace == AssumedAddressSpace ? ChangeStatus::UNCHANGED + : ChangeStatus::CHANGED; + } + + /// See AbstractAttribute::manifest(...). + ChangeStatus manifest(Attributor &A) override { + Value *AssociatedValue = &getAssociatedValue(); + Value *OriginalValue = peelAddrspacecast(AssociatedValue); + if (getAddressSpace() == NoAddressSpace || + static_cast(getAddressSpace()) == + getAssociatedType()->getPointerAddressSpace()) + return ChangeStatus::UNCHANGED; + + Type *NewPtrTy = PointerType::getWithSamePointeeType( + cast(getAssociatedType()), + static_cast(getAddressSpace())); + bool UseOriginalValue = + OriginalValue->getType()->getPointerAddressSpace() == + static_cast(getAddressSpace()); + + bool Changed = false; + + auto MakeChange = [&](Instruction *I, Use &U) { + Changed = true; + if (UseOriginalValue) { + A.changeUseAfterManifest(U, *OriginalValue); + return; + } + Instruction *CastInst = new AddrSpaceCastInst(OriginalValue, NewPtrTy); + CastInst->insertBefore(cast(I)); + A.changeUseAfterManifest(U, *CastInst); + }; + + auto Pred = [&](const Use &U, bool &) { + if (U.get() != AssociatedValue) + return true; + auto *Inst = dyn_cast(U.getUser()); + if (!Inst) + return true; + // This is a WA to make sure we only change uses from the corresponding + // CGSCC if the AA is run on CGSCC instead of the entire module. + if (!A.isRunOn(Inst->getFunction())) + return true; + if (isa(Inst) || isa(Inst)) + MakeChange(Inst, const_cast(U)); + 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(Attributor *A) const override { + if (!isValidState()) + return "addrspace()"; + return "addrspace(" + + (AssumedAddressSpace == NoAddressSpace + ? "none" + : std::to_string(AssumedAddressSpace)) + + ")"; + } + +private: + int32_t AssumedAddressSpace = NoAddressSpace; + + bool takeAddressSpace(int32_t AS) { + if (AssumedAddressSpace == NoAddressSpace) { + AssumedAddressSpace = AS; + return true; + } + return AssumedAddressSpace == AS; + } + + static Value *peelAddrspacecast(Value *V) { + if (auto *I = dyn_cast(V)) + return peelAddrspacecast(I->getPointerOperand()); + if (auto *C = dyn_cast(V)) + if (C->getOpcode() == Instruction::AddrSpaceCast) + return peelAddrspacecast(C->getOperand(0)); + return V; + } +}; + +struct AAAddressSpaceFloating final : AAAddressSpaceImpl { + AAAddressSpaceFloating(const IRPosition &IRP, Attributor &A) + : AAAddressSpaceImpl(IRP, A) {} + + void trackStatistics() const override { + STATS_DECLTRACK_FLOATING_ATTR(addrspace); + } +}; + +struct AAAddressSpaceReturned final : AAAddressSpaceImpl { + AAAddressSpaceReturned(const IRPosition &IRP, Attributor &A) + : AAAddressSpaceImpl(IRP, A) {} + + /// See AbstractAttribute::initialize(...). + void initialize(Attributor &A) override { + // TODO: we don't rewrite function argument for now because it will need to + // rewrite the function signature and all call sites. + (void)indicatePessimisticFixpoint(); + } + + void trackStatistics() const override { + STATS_DECLTRACK_FNRET_ATTR(addrspace); + } +}; + +struct AAAddressSpaceCallSiteReturned final : AAAddressSpaceImpl { + AAAddressSpaceCallSiteReturned(const IRPosition &IRP, Attributor &A) + : AAAddressSpaceImpl(IRP, A) {} + + void trackStatistics() const override { + STATS_DECLTRACK_CSRET_ATTR(addrspace); + } +}; + +struct AAAddressSpaceArgument final : AAAddressSpaceImpl { + AAAddressSpaceArgument(const IRPosition &IRP, Attributor &A) + : AAAddressSpaceImpl(IRP, A) {} + + void trackStatistics() const override { STATS_DECLTRACK_ARG_ATTR(addrspace); } +}; + +struct AAAddressSpaceCallSiteArgument final : AAAddressSpaceImpl { + AAAddressSpaceCallSiteArgument(const IRPosition &IRP, Attributor &A) + : AAAddressSpaceImpl(IRP, A) {} + + /// See AbstractAttribute::initialize(...). + void initialize(Attributor &A) override { + // TODO: we don't rewrite call site argument for now because it will need to + // rewrite the function signature of the callee. + (void)indicatePessimisticFixpoint(); + } + + 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; @@ -12055,6 +12232,7 @@ const char AAPointerInfo::ID = 0; const char AAAssumptionInfo::ID = 0; const char AAUnderlyingObjects::ID = 0; +const char AAAddressSpace::ID = 0; // Macro magic to create the static generator function for attributes that // follow the naming scheme. @@ -12173,6 +12351,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(AAAddressSpace) CREATE_ALL_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAValueSimplify) CREATE_ALL_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAIsDead) 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,154 @@ +; 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 ptr null, 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 + +;. +; CHECK: @dst = dso_local addrspace(1) externally_initialized global i32 0, align 4 +; CHECK: @g1 = dso_local addrspace(1) externally_initialized global ptr null, align 4 +; CHECK: @g2 = dso_local addrspace(1) externally_initialized global i32 0, align 4 +; CHECK: @s1 = dso_local addrspace(3) global i32 undef, align 4 +; CHECK: @s2 = dso_local addrspace(3) global i32 undef, align 4 +;. +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 nofree noundef nonnull writeonly align 4 dereferenceable(8) [[P:%.*]]) #[[ATTR0:[0-9]+]] { +; CHECK-NEXT: entry: +; CHECK-NEXT: [[TMP0:%.*]] = addrspacecast ptr [[P]] to ptr addrspace(1) +; CHECK-NEXT: [[TMP1:%.*]] = addrspacecast ptr [[P]] to ptr addrspace(1) +; CHECK-NEXT: store ptr addrspace(1) [[TMP0]], ptr addrspace(1) [[TMP1]], align 4 +; CHECK-NEXT: ret void +; +entry: + store ptr %p, 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: store i32 [[TMP1]], ptr addrspace(1) @dst, 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: store i32 [[TMP0]], ptr addrspace(1) @dst, 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: store i32 [[TMP1]], ptr addrspace(1) @dst, 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 nofree noundef nonnull writeonly align 4 dereferenceable(8) addrspacecast (ptr addrspace(1) @g1 to ptr)) #[[ATTR2:[0-9]+]] +; CHECK-NEXT: call void @_Z12global_writePi(ptr 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(8) 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(8) 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(8) 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 @@ -230,6 +230,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: [AAAddressSpace] 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 @@ -308,6 +310,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="{[AAAddressSpace] ; 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 @@ -29,7 +29,7 @@ ; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) ; CHECK-LABEL: define {{[^@]+}}@test_const_as_global2 ; CHECK-SAME: () #[[ATTR1]] { -; CHECK-NEXT: [[L2:%.*]] = load i32, ptr addrspacecast (ptr addrspace(4) @G to ptr), align 4 +; CHECK-NEXT: [[L2:%.*]] = load i32, ptr addrspace(4) @G, align 4 ; CHECK-NEXT: ret i32 [[L2]] ; %l2 = load i32, ptr addrspacecast (ptr addrspace(4) @G to ptr) @@ -41,8 +41,7 @@ ; CHECK-LABEL: define {{[^@]+}}@test_const_as_call1 ; 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: [[L1:%.*]] = load i32, ptr addrspace(4) [[P1]], align 4 ; CHECK-NEXT: ret i32 [[L1]] ; %p1 = call ptr addrspace(4) @ptr_to_const() @@ -56,8 +55,7 @@ ; CHECK-LABEL: define {{[^@]+}}@test_const_as_call2 ; 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: [[L2:%.*]] = load i32, ptr [[P2]], align 4 ; CHECK-NEXT: ret i32 [[L2]] ; %p2 = call ptr @ptr() @@ -72,8 +70,7 @@ ; CHECK-LABEL: define {{[^@]+}}@test_shared_as_call1 ; 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: [[L1:%.*]] = load i32, ptr addrspace(3) [[P1]], align 4 ; CHECK-NEXT: ret i32 [[L1]] ; %p1 = call ptr addrspace(3) @ptr_to_shared() @@ -87,8 +84,7 @@ ; CHECK-LABEL: define {{[^@]+}}@test_shared_as_call2 ; 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: [[L2:%.*]] = load i32, ptr [[P2]], align 4 ; CHECK-NEXT: ret i32 [[L2]] ; %p2 = call ptr @ptr() diff --git a/llvm/test/Transforms/Attributor/nocapture-1.ll b/llvm/test/Transforms/Attributor/nocapture-1.ll --- a/llvm/test/Transforms/Attributor/nocapture-1.ll +++ b/llvm/test/Transforms/Attributor/nocapture-1.ll @@ -257,7 +257,7 @@ ; TUNIT-NEXT: [[TMP:%.*]] = addrspacecast ptr addrspace(1) [[P]] to ptr ; TUNIT-NEXT: [[TMP2:%.*]] = select i1 [[B]], ptr [[TMP]], ptr [[Q]] ; TUNIT-NEXT: [[VAL:%.*]] = load i32, ptr [[TMP2]], align 4 -; TUNIT-NEXT: store i32 0, ptr [[TMP]], align 4 +; TUNIT-NEXT: store i32 0, ptr addrspace(1) [[P]], align 4 ; TUNIT-NEXT: store ptr [[Q]], ptr @g, align 8 ; TUNIT-NEXT: ret i32 [[VAL]] ; @@ -272,7 +272,7 @@ ; CGSCC-NEXT: [[TMP:%.*]] = addrspacecast ptr addrspace(1) [[P]] to ptr ; CGSCC-NEXT: [[TMP2:%.*]] = select i1 [[B]], ptr [[TMP]], ptr [[Q]] ; CGSCC-NEXT: [[VAL:%.*]] = load i32, ptr [[TMP2]], align 4 -; CGSCC-NEXT: store i32 0, ptr [[TMP]], align 4 +; CGSCC-NEXT: store i32 0, ptr addrspace(1) [[P]], align 4 ; CGSCC-NEXT: store ptr [[Q]], ptr @g, align 8 ; CGSCC-NEXT: ret i32 [[VAL]] ; diff --git a/llvm/test/Transforms/Attributor/value-simplify-gpu.ll b/llvm/test/Transforms/Attributor/value-simplify-gpu.ll --- a/llvm/test/Transforms/Attributor/value-simplify-gpu.ll +++ b/llvm/test/Transforms/Attributor/value-simplify-gpu.ll @@ -95,7 +95,7 @@ ; CHECK-SAME: () #[[ATTR2:[0-9]+]] { ; CHECK-NEXT: entry: ; CHECK-NEXT: store i32 1, ptr @ReachableKernelAS0, align 4 -; CHECK-NEXT: store i32 1, ptr addrspacecast (ptr addrspace(3) @ReachableKernel to ptr), align 4 +; CHECK-NEXT: store i32 1, ptr addrspace(3) @ReachableKernel, align 4 ; CHECK-NEXT: ret void ; entry: @@ -109,9 +109,9 @@ ; TUNIT-LABEL: define {{[^@]+}}@level2Kernela ; TUNIT-SAME: () #[[ATTR1]] { ; TUNIT-NEXT: entry: -; TUNIT-NEXT: [[TMP0:%.*]] = load i32, ptr addrspacecast (ptr addrspace(3) @ReachableKernel to ptr), align 4 +; TUNIT-NEXT: [[TMP0:%.*]] = load i32, ptr addrspace(3) @ReachableKernel, align 4 ; TUNIT-NEXT: [[TMP1:%.*]] = load i32, ptr @ReachableKernelAS0, align 4 -; TUNIT-NEXT: [[TMP2:%.*]] = load i32, ptr addrspacecast (ptr addrspace(3) @UnreachableKernel to ptr), align 4 +; TUNIT-NEXT: [[TMP2:%.*]] = load i32, ptr addrspace(3) @UnreachableKernel, align 4 ; TUNIT-NEXT: call void @use(i32 noundef [[TMP0]], i32 noundef [[TMP1]], i32 noundef [[TMP2]]) #[[ATTR6:[0-9]+]] ; TUNIT-NEXT: ret void ; @@ -119,9 +119,9 @@ ; CGSCC-LABEL: define {{[^@]+}}@level2Kernela ; CGSCC-SAME: () #[[ATTR3:[0-9]+]] { ; CGSCC-NEXT: entry: -; CGSCC-NEXT: [[TMP0:%.*]] = load i32, ptr addrspacecast (ptr addrspace(3) @ReachableKernel to ptr), align 4 +; CGSCC-NEXT: [[TMP0:%.*]] = load i32, ptr addrspace(3) @ReachableKernel, align 4 ; CGSCC-NEXT: [[TMP1:%.*]] = load i32, ptr @ReachableKernelAS0, align 4 -; CGSCC-NEXT: [[TMP2:%.*]] = load i32, ptr addrspacecast (ptr addrspace(3) @UnreachableKernel to ptr), align 4 +; CGSCC-NEXT: [[TMP2:%.*]] = load i32, ptr addrspace(3) @UnreachableKernel, align 4 ; CGSCC-NEXT: call void @use(i32 noundef [[TMP0]], i32 noundef [[TMP1]], i32 noundef [[TMP2]]) #[[ATTR4]] ; CGSCC-NEXT: ret void ; @@ -138,9 +138,9 @@ ; TUNIT-LABEL: define {{[^@]+}}@level2Kernelb ; TUNIT-SAME: () #[[ATTR1]] { ; TUNIT-NEXT: entry: -; TUNIT-NEXT: [[TMP0:%.*]] = load i32, ptr addrspacecast (ptr addrspace(3) @ReachableKernel to ptr), align 4 +; TUNIT-NEXT: [[TMP0:%.*]] = load i32, ptr addrspace(3) @ReachableKernel, align 4 ; TUNIT-NEXT: [[TMP1:%.*]] = load i32, ptr @ReachableKernelAS0, align 4 -; TUNIT-NEXT: [[TMP2:%.*]] = load i32, ptr addrspacecast (ptr addrspace(3) @UnreachableKernel to ptr), align 4 +; TUNIT-NEXT: [[TMP2:%.*]] = load i32, ptr addrspace(3) @UnreachableKernel, align 4 ; TUNIT-NEXT: call void @use(i32 noundef [[TMP0]], i32 noundef [[TMP1]], i32 noundef [[TMP2]]) #[[ATTR6]] ; TUNIT-NEXT: ret void ; @@ -148,9 +148,9 @@ ; CGSCC-LABEL: define {{[^@]+}}@level2Kernelb ; CGSCC-SAME: () #[[ATTR3]] { ; CGSCC-NEXT: entry: -; CGSCC-NEXT: [[TMP0:%.*]] = load i32, ptr addrspacecast (ptr addrspace(3) @ReachableKernel to ptr), align 4 +; CGSCC-NEXT: [[TMP0:%.*]] = load i32, ptr addrspace(3) @ReachableKernel, align 4 ; CGSCC-NEXT: [[TMP1:%.*]] = load i32, ptr @ReachableKernelAS0, align 4 -; CGSCC-NEXT: [[TMP2:%.*]] = load i32, ptr addrspacecast (ptr addrspace(3) @UnreachableKernel to ptr), align 4 +; CGSCC-NEXT: [[TMP2:%.*]] = load i32, ptr addrspace(3) @UnreachableKernel, align 4 ; CGSCC-NEXT: call void @use(i32 noundef [[TMP0]], i32 noundef [[TMP1]], i32 noundef [[TMP2]]) #[[ATTR4]] ; CGSCC-NEXT: ret void ; @@ -167,7 +167,7 @@ ; CHECK-LABEL: define {{[^@]+}}@level2Kernelall_late ; CHECK-SAME: () #[[ATTR2]] { ; CHECK-NEXT: entry: -; CHECK-NEXT: store i32 1, ptr addrspacecast (ptr addrspace(3) @UnreachableKernel to ptr), align 4 +; CHECK-NEXT: store i32 1, ptr addrspace(3) @UnreachableKernel, align 4 ; CHECK-NEXT: ret void ; entry: @@ -259,14 +259,14 @@ ; TUNIT-LABEL: define {{[^@]+}}@level2all_early ; TUNIT-SAME: (ptr noalias nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) [[ADDR:%.*]]) #[[ATTR2]] { ; TUNIT-NEXT: entry: -; TUNIT-NEXT: store i32 1, ptr addrspacecast (ptr addrspace(3) @ReachableNonKernel to ptr), align 4 +; TUNIT-NEXT: store i32 1, ptr addrspace(3) @ReachableNonKernel, align 4 ; TUNIT-NEXT: ret void ; ; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(write) ; CGSCC-LABEL: define {{[^@]+}}@level2all_early ; CGSCC-SAME: (ptr nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) [[ADDR:%.*]]) #[[ATTR2]] { ; CGSCC-NEXT: entry: -; CGSCC-NEXT: store i32 1, ptr addrspacecast (ptr addrspace(3) @ReachableNonKernel to ptr), align 4 +; CGSCC-NEXT: store i32 1, ptr addrspace(3) @ReachableNonKernel, align 4 ; CGSCC-NEXT: store i32 17, ptr [[ADDR]], align 4 ; CGSCC-NEXT: ret void ; @@ -281,8 +281,8 @@ ; TUNIT-LABEL: define {{[^@]+}}@level2a ; TUNIT-SAME: () #[[ATTR1]] { ; TUNIT-NEXT: entry: -; TUNIT-NEXT: [[TMP0:%.*]] = load i32, ptr addrspacecast (ptr addrspace(3) @ReachableNonKernel to ptr), align 4 -; TUNIT-NEXT: [[TMP1:%.*]] = load i32, ptr addrspacecast (ptr addrspace(3) @UnreachableNonKernel to ptr), align 4 +; TUNIT-NEXT: [[TMP0:%.*]] = load i32, ptr addrspace(3) @ReachableNonKernel, align 4 +; TUNIT-NEXT: [[TMP1:%.*]] = load i32, ptr addrspace(3) @UnreachableNonKernel, align 4 ; TUNIT-NEXT: call void @use(i32 noundef [[TMP0]], i32 noundef [[TMP1]], i32 17) #[[ATTR6]] ; TUNIT-NEXT: ret void ; @@ -290,8 +290,8 @@ ; CGSCC-LABEL: define {{[^@]+}}@level2a ; CGSCC-SAME: (ptr nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[ADDR:%.*]]) #[[ATTR3]] { ; CGSCC-NEXT: entry: -; CGSCC-NEXT: [[TMP0:%.*]] = load i32, ptr addrspacecast (ptr addrspace(3) @ReachableNonKernel to ptr), align 4 -; CGSCC-NEXT: [[TMP1:%.*]] = load i32, ptr addrspacecast (ptr addrspace(3) @UnreachableNonKernel to ptr), align 4 +; CGSCC-NEXT: [[TMP0:%.*]] = load i32, ptr addrspace(3) @ReachableNonKernel, align 4 +; CGSCC-NEXT: [[TMP1:%.*]] = load i32, ptr addrspace(3) @UnreachableNonKernel, align 4 ; CGSCC-NEXT: [[QQQQ2:%.*]] = load i32, ptr [[ADDR]], align 4 ; CGSCC-NEXT: call void @use(i32 noundef [[TMP0]], i32 noundef [[TMP1]], i32 [[QQQQ2]]) #[[ATTR4]] ; CGSCC-NEXT: ret void @@ -309,8 +309,8 @@ ; TUNIT-LABEL: define {{[^@]+}}@level2b ; TUNIT-SAME: () #[[ATTR1]] { ; TUNIT-NEXT: entry: -; TUNIT-NEXT: [[TMP0:%.*]] = load i32, ptr addrspacecast (ptr addrspace(3) @ReachableNonKernel to ptr), align 4 -; TUNIT-NEXT: [[TMP1:%.*]] = load i32, ptr addrspacecast (ptr addrspace(3) @UnreachableNonKernel to ptr), align 4 +; TUNIT-NEXT: [[TMP0:%.*]] = load i32, ptr addrspace(3) @ReachableNonKernel, align 4 +; TUNIT-NEXT: [[TMP1:%.*]] = load i32, ptr addrspace(3) @UnreachableNonKernel, align 4 ; TUNIT-NEXT: call void @use(i32 noundef [[TMP0]], i32 noundef [[TMP1]], i32 17) #[[ATTR6]] ; TUNIT-NEXT: ret void ; @@ -318,8 +318,8 @@ ; CGSCC-LABEL: define {{[^@]+}}@level2b ; CGSCC-SAME: (ptr nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[ADDR:%.*]]) #[[ATTR3]] { ; CGSCC-NEXT: entry: -; CGSCC-NEXT: [[TMP0:%.*]] = load i32, ptr addrspacecast (ptr addrspace(3) @ReachableNonKernel to ptr), align 4 -; CGSCC-NEXT: [[TMP1:%.*]] = load i32, ptr addrspacecast (ptr addrspace(3) @UnreachableNonKernel to ptr), align 4 +; CGSCC-NEXT: [[TMP0:%.*]] = load i32, ptr addrspace(3) @ReachableNonKernel, align 4 +; CGSCC-NEXT: [[TMP1:%.*]] = load i32, ptr addrspace(3) @UnreachableNonKernel, align 4 ; CGSCC-NEXT: [[TMP2:%.*]] = load i32, ptr [[ADDR]], align 4 ; CGSCC-NEXT: call void @use(i32 noundef [[TMP0]], i32 noundef [[TMP1]], i32 [[TMP2]]) #[[ATTR4]] ; CGSCC-NEXT: ret void @@ -337,14 +337,14 @@ ; TUNIT-LABEL: define {{[^@]+}}@level2all_late ; TUNIT-SAME: (ptr noalias nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) [[ADDR:%.*]]) #[[ATTR2]] { ; TUNIT-NEXT: entry: -; TUNIT-NEXT: store i32 1, ptr addrspacecast (ptr addrspace(3) @UnreachableNonKernel to ptr), align 4 +; TUNIT-NEXT: store i32 1, ptr addrspace(3) @UnreachableNonKernel, align 4 ; TUNIT-NEXT: ret void ; ; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(write) ; CGSCC-LABEL: define {{[^@]+}}@level2all_late ; CGSCC-SAME: (ptr noalias nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) [[ADDR:%.*]]) #[[ATTR2]] { ; CGSCC-NEXT: entry: -; CGSCC-NEXT: store i32 1, ptr addrspacecast (ptr addrspace(3) @UnreachableNonKernel to ptr), align 4 +; CGSCC-NEXT: store i32 1, ptr addrspace(3) @UnreachableNonKernel, align 4 ; CGSCC-NEXT: store i32 5, ptr [[ADDR]], align 4 ; CGSCC-NEXT: ret void ; diff --git a/llvm/test/Transforms/Attributor/value-simplify.ll b/llvm/test/Transforms/Attributor/value-simplify.ll --- a/llvm/test/Transforms/Attributor/value-simplify.ll +++ b/llvm/test/Transforms/Attributor/value-simplify.ll @@ -800,7 +800,8 @@ ; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(write) ; TUNIT-LABEL: define {{[^@]+}}@user ; TUNIT-SAME: () #[[ATTR4]] { -; TUNIT-NEXT: store i32 0, ptr addrspacecast (ptr addrspace(3) @ConstAS3Ptr to ptr), align 4 +; TUNIT-NEXT: [[TMP1:%.*]] = addrspacecast ptr addrspacecast (ptr addrspace(3) @ConstAS3Ptr to ptr) to ptr addrspace(3) +; TUNIT-NEXT: store i32 0, ptr addrspace(3) [[TMP1]], align 4 ; TUNIT-NEXT: ret void ; ; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(write)