diff --git a/llvm/lib/Analysis/CaptureTracking.cpp b/llvm/lib/Analysis/CaptureTracking.cpp index 076f4176c0219..bd0d417b1ed33 100644 --- a/llvm/lib/Analysis/CaptureTracking.cpp +++ b/llvm/lib/Analysis/CaptureTracking.cpp @@ -359,6 +359,12 @@ UseCaptureInfo llvm::DetermineUseCaptureKind(const Use &U, const Value *Base) { case Instruction::AddrSpaceCast: // The original value is not captured via this if the new value isn't. return UseCaptureInfo::passthrough(); + case Instruction::PtrToAddr: + // We treat ptrtoaddr as a location-independent capture of the address even + // if it is ultimately not used. Continuing recursive analysis after + // ptrtoaddr would be possible, but we'd need logic to do that correctly, + // which is not the same as the current pointer following logic. + return CaptureComponents::Address; case Instruction::ICmp: { unsigned Idx = U.getOperandNo(); unsigned OtherIdx = 1 - Idx; diff --git a/llvm/test/Transforms/FunctionAttrs/nocapture.ll b/llvm/test/Transforms/FunctionAttrs/nocapture.ll index 9d6acc410de75..26b5dc2dc7760 100644 --- a/llvm/test/Transforms/FunctionAttrs/nocapture.ll +++ b/llvm/test/Transforms/FunctionAttrs/nocapture.ll @@ -1082,6 +1082,65 @@ define i64 @captures_not_ret_only(ptr %p) { ret i64 %int } +@gi = global i64 0 + +;; Unlike ptrtoint, ptrtoaddr only captures the address +define i64 @captures_ptrtoaddr_stored(ptr %p) { +; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(write, argmem: none, inaccessiblemem: none) +; FNATTRS-LABEL: define noundef i64 @captures_ptrtoaddr_stored +; FNATTRS-SAME: (ptr captures(address) [[P:%.*]]) #[[ATTR1]] { +; FNATTRS-NEXT: [[INT:%.*]] = ptrtoaddr ptr [[P]] to i64 +; FNATTRS-NEXT: store i64 [[INT]], ptr @gi, align 8 +; FNATTRS-NEXT: ret i64 0 +; +; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(write) +; ATTRIBUTOR-LABEL: define i64 @captures_ptrtoaddr_stored +; ATTRIBUTOR-SAME: (ptr nofree writeonly [[P:%.*]]) #[[ATTR1]] { +; ATTRIBUTOR-NEXT: [[INT:%.*]] = ptrtoaddr ptr [[P]] to i64 +; ATTRIBUTOR-NEXT: store i64 [[INT]], ptr @gi, align 8 +; ATTRIBUTOR-NEXT: ret i64 0 +; + %int = ptrtoaddr ptr %p to i64 + store i64 %int, ptr @gi, align 8 + ret i64 0 +} + +;; Note: ptrtoaddr is a location-independent capture, so we don't get captures(ret: address) here. +define i64 @captures_ptrtoaddr_ret(ptr %p) { +; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) +; FNATTRS-LABEL: define i64 @captures_ptrtoaddr_ret +; FNATTRS-SAME: (ptr captures(address) [[P:%.*]]) #[[ATTR0]] { +; FNATTRS-NEXT: [[INT:%.*]] = ptrtoaddr ptr [[P]] to i64 +; FNATTRS-NEXT: ret i64 [[INT]] +; +; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) +; ATTRIBUTOR-LABEL: define i64 @captures_ptrtoaddr_ret +; ATTRIBUTOR-SAME: (ptr nofree readnone [[P:%.*]]) #[[ATTR0]] { +; ATTRIBUTOR-NEXT: [[INT:%.*]] = ptrtoaddr ptr [[P]] to i64 +; ATTRIBUTOR-NEXT: ret i64 [[INT]] +; + %int = ptrtoaddr ptr %p to i64 + ret i64 %int +} + +;; Note: ptrtoaddr is a location-independent capture, so we don't get captures(none) here. +define i64 @captures_ptrtoaddr_ignored(ptr %p) { +; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) +; FNATTRS-LABEL: define noundef i64 @captures_ptrtoaddr_ignored +; FNATTRS-SAME: (ptr captures(address) [[P:%.*]]) #[[ATTR0]] { +; FNATTRS-NEXT: [[INT:%.*]] = ptrtoaddr ptr [[P]] to i64 +; FNATTRS-NEXT: ret i64 0 +; +; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) +; ATTRIBUTOR-LABEL: define i64 @captures_ptrtoaddr_ignored +; ATTRIBUTOR-SAME: (ptr nofree readnone [[P:%.*]]) #[[ATTR0]] { +; ATTRIBUTOR-NEXT: [[INT:%.*]] = ptrtoaddr ptr [[P]] to i64 +; ATTRIBUTOR-NEXT: ret i64 0 +; + %int = ptrtoaddr ptr %p to i64 + ret i64 0 +} + define void @captures_read_provenance(ptr %p) { ; FNATTRS-LABEL: define void @captures_read_provenance ; FNATTRS-SAME: (ptr captures(address, read_provenance) [[P:%.*]]) {