Bug type: crash
Component: Attributor
Bug location: llvm/lib/Transforms/IPO/AttributorAttributes.cpp: AANoCaptureImpl::updateImpl
Issue title: [attributor] Crash on `null_pointer_is_valid` function
Labels: crash-on-valid
llvm::Attributor
Reported by: lanza

With

```
target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"
target triple = "aarch64-none-linux-android28"

; Function Attrs: null_pointer_is_valid
define i64 @foo() #0 {
  call fastcc void @bar(ptr null)
  ret i64 0
}

define fastcc void @bar(ptr %0) {
  store i16 0, ptr %0, align 2
  ret void
}

attributes #0 = { null_pointer_is_valid }
```

and running

```
opt -passes=attributor file.ll
```

we crash with

```
opt: llvm-project/llvm/lib/Transforms/IPO/AttributorAttributes.cpp:5901: virtual ChangeStatus (anonymous namespace)::AANoCaptureImpl::updateImpl(Attributor &): Assertion `F && "Expected a function!"' failed.
PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace.
Stack dump:
0.      Program arguments: opt -passes=attributor reduced.ll
 #0 0x000000000165bf38 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (llvm-project/build/Release/bin/opt+0x165bf38)
 #1 0x0000000001659a40 llvm::sys::RunSignalHandlers() (llvm-project/build/Release/bin/opt+0x1659a40)
 #2 0x000000000165c938 SignalHandler(int) Signals.cpp:0:0
 #3 0x00007f3ec923e6f0 __restore_rt (/lib64/libc.so.6+0x3e6f0)
 #4 0x00007f3ec928b94c __pthread_kill_implementation (/lib64/libc.so.6+0x8b94c)
 #5 0x00007f3ec923e646 gsignal (/lib64/libc.so.6+0x3e646)
 #6 0x00007f3ec92287f3 abort (/lib64/libc.so.6+0x287f3)
 #7 0x00007f3ec922871b _nl_load_domain.cold (/lib64/libc.so.6+0x2871b)
 #8 0x00007f3ec9237386 (/lib64/libc.so.6+0x37386)
 #9 0x0000000002f2a65b (anonymous namespace)::AANoCaptureImpl::updateImpl(llvm::Attributor&) AttributorAttributes.cpp:0:0
#10 0x0000000002ec8492 llvm::AbstractAttribute::update(llvm::Attributor&) (llvm-project/build/Release/bin/opt+0x2ec8492)
#11 0x0000000002ed3b83 llvm::Attributor::updateAA(llvm::AbstractAttribute&) (llvm-project/build/Release/bin/opt+0x2ed3b83)
#12 0x0000000002eec289 llvm::AANoCapture const* llvm::Attributor::getOrCreateAAFor<llvm::AANoCapture>(llvm::IRPosition, llvm::AbstractAttribute const*, llvm::DepClassTy, bool, bool) Attributor.cpp:0:0
#13 0x0000000002f1ab57 (anonymous namespace)::AANoAliasCallSiteArgument::updateImpl(llvm::Attributor&) AttributorAttributes.cpp:0:0
#14 0x0000000002ec8492 llvm::AbstractAttribute::update(llvm::Attributor&) (llvm-project/build/Release/bin/opt+0x2ec8492)
#15 0x0000000002ed3b83 llvm::Attributor::updateAA(llvm::AbstractAttribute&) (llvm-project/build/Release/bin/opt+0x2ed3b83)
#16 0x0000000002efba19 llvm::AANoAlias const* llvm::Attributor::getOrCreateAAFor<llvm::AANoAlias>(llvm::IRPosition, llvm::AbstractAttribute const*, llvm::DepClassTy, bool, bool) Attributor.cpp:0:0
#17 0x0000000002ede880 void llvm::Attributor::checkAndQueryIRAttr<(llvm::Attribute::AttrKind)20, llvm::AANoAlias>(llvm::IRPosition const&, llvm::AttributeSet) (llvm-project/build/Release/bin/opt+0x2ede880)
#18 0x0000000002edd545 llvm::Attributor::identifyDefaultAbstractAttributes(llvm::Function&) (llvm-project/build/Release/bin/opt+0x2edd545)
#19 0x0000000002ee0800 runAttributorOnFunctions(llvm::InformationCache&, llvm::SetVector<llvm::Function*, llvm::SmallVector<llvm::Function*, 0u>, llvm::DenseSet<llvm::Function*, llvm::DenseMapInfo<llvm::Function*, void>>, 0u>&, llvm::AnalysisGetter&, llvm::CallGraphUpdater&, bool, bool) Attributor.cpp:0:0
#20 0x0000000002edfc41 llvm::AttributorPass::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (llvm-project/build/Release/bin/opt+0x2edfc41)
#21 0x0000000002b6fcdd llvm::detail::PassModel<llvm::Module, llvm::AttributorPass, llvm::AnalysisManager<llvm::Module>>::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) PassBuilderPipelines.cpp:0:0
#22 0x0000000001853e56 llvm::PassManager<llvm::Module, llvm::AnalysisManager<llvm::Module>>::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (llvm-project/build/Release/bin/opt+0x1853e56)
#23 0x0000000002afaa4b llvm::runPassPipeline(llvm::StringRef, llvm::Module&, llvm::TargetMachine*, llvm::TargetLibraryInfoImpl*, llvm::ToolOutputFile*, llvm::ToolOutputFile*, llvm::ToolOutputFile*, llvm::StringRef, llvm::ArrayRef<llvm::PassPlugin>, llvm::ArrayRef<std::function<void (llvm::PassBuilder&)>>, llvm::opt_tool::OutputKind, llvm::opt_tool::VerifierKind, bool, bool, bool, bool, bool, bool, bool) (llvm-project/build/Release/bin/opt+0x2afaa4b)
#24 0x0000000001622f36 optMain (llvm-project/build/Release/bin/opt+0x1622f36)
```

Comments: author: lanza
body: https://github.com/llvm/llvm-project/blob/0f52f4ddd909eb38f2a691ffed8469263fe5f635/llvm/lib/Transforms/IPO/AttributorAttributes.cpp#L5901
author: dtcxzyw
body: cc @arsenm 
author: arsenm
body: Just returning on the null function seems to work, but I don't understand exactly why it reaches here. AANoCapture::isImpliedByIR is incorrectly reimplementing NullPointerIsDefined but fixing that doesn't seem to help any 

Fix patch:
commit 2d61692d4b75b7d92b44bfafb1011c1723955151
Author: Matt Arsenault <Matthew.Arsenault@amd.com>
Date:   Thu May 23 19:31:33 2024 +0200

    Attributor: Do not assume function context in AANoCapture (#91462)
    
    If the calling function has the null_pointer_is_valid attribute, somehow
    a null constant reaches here. I'm not sure why exactly, it doesn't
    happen for other types of constants.
    
    Fixes #87856

diff --git a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp
index 41b66aafe7d3..1b3bf3c732ed 100644
--- a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp
+++ b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp
@@ -5690,6 +5690,9 @@ bool AANoCapture::isImpliedByIR(Attributor &A, const IRPosition &IRP,
     return V.use_empty();
 
   // You cannot "capture" null in the default address space.
+  //
+  // FIXME: This should use NullPointerIsDefined to account for the function
+  // attribute.
   if (isa<UndefValue>(V) || (isa<ConstantPointerNull>(V) &&
                              V.getType()->getPointerAddressSpace() == 0)) {
     return true;
@@ -5899,10 +5902,13 @@ ChangeStatus AANoCaptureImpl::updateImpl(Attributor &A) {
 
   const Function *F =
       isArgumentPosition() ? IRP.getAssociatedFunction() : IRP.getAnchorScope();
-  assert(F && "Expected a function!");
-  const IRPosition &FnPos = IRPosition::function(*F);
+
+  // TODO: Is the checkForAllUses below useful for constants?
+  if (!F)
+    return indicatePessimisticFixpoint();
 
   AANoCapture::StateType T;
+  const IRPosition &FnPos = IRPosition::function(*F);
 
   // Readonly means we cannot capture through memory.
   bool IsKnown;


Regression tests:
file: llvm/test/Transforms/Attributor/issue87856.ll
commands: opt -S -passes=attributor < %s
tests: test_name: <module>
test_body: 
define void @null_ptr_is_valid_call_with_null() #0 {
;
  call void @store_as0(ptr null)
  ret void
}

define void @null_ptr_is_valid_call_with_undef() #0 {
;
  call void @store_as0(ptr undef)
  ret void
}

define void @store_as0(ptr %0) {
;
  store i16 0, ptr %0, align 2
  ret void
}

define void @call_store_as1() {
;
  call void @store_as1(ptr addrspace(1) null)
  ret void
}

define void @store_as1(ptr addrspace(1) %arg) {
;
  store i16 0, ptr addrspace(1) %arg, align 2
  ret void
}

attributes #0 = { null_pointer_is_valid }
;.
;.