Skip to content

Commit 2d61692

Browse files
authored
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
1 parent b17d445 commit 2d61692

File tree

2 files changed

+69
-2
lines changed

2 files changed

+69
-2
lines changed

llvm/lib/Transforms/IPO/AttributorAttributes.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5690,6 +5690,9 @@ bool AANoCapture::isImpliedByIR(Attributor &A, const IRPosition &IRP,
56905690
return V.use_empty();
56915691

56925692
// You cannot "capture" null in the default address space.
5693+
//
5694+
// FIXME: This should use NullPointerIsDefined to account for the function
5695+
// attribute.
56935696
if (isa<UndefValue>(V) || (isa<ConstantPointerNull>(V) &&
56945697
V.getType()->getPointerAddressSpace() == 0)) {
56955698
return true;
@@ -5899,10 +5902,13 @@ ChangeStatus AANoCaptureImpl::updateImpl(Attributor &A) {
58995902

59005903
const Function *F =
59015904
isArgumentPosition() ? IRP.getAssociatedFunction() : IRP.getAnchorScope();
5902-
assert(F && "Expected a function!");
5903-
const IRPosition &FnPos = IRPosition::function(*F);
5905+
5906+
// TODO: Is the checkForAllUses below useful for constants?
5907+
if (!F)
5908+
return indicatePessimisticFixpoint();
59045909

59055910
AANoCapture::StateType T;
5911+
const IRPosition &FnPos = IRPosition::function(*F);
59065912

59075913
// Readonly means we cannot capture through memory.
59085914
bool IsKnown;
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals all --version 4
2+
; RUN: opt -S -passes=attributor < %s | FileCheck %s
3+
4+
define void @null_ptr_is_valid_call_with_null() #0 {
5+
; CHECK-LABEL: define void @null_ptr_is_valid_call_with_null(
6+
; CHECK-SAME: ) #[[ATTR0:[0-9]+]] {
7+
; CHECK-NEXT: call void @store_as0(ptr nofree noundef writeonly align 4294967296 null) #[[ATTR4:[0-9]+]]
8+
; CHECK-NEXT: ret void
9+
;
10+
call void @store_as0(ptr null)
11+
ret void
12+
}
13+
14+
define void @null_ptr_is_valid_call_with_undef() #0 {
15+
; CHECK-LABEL: define void @null_ptr_is_valid_call_with_undef(
16+
; CHECK-SAME: ) #[[ATTR1:[0-9]+]] {
17+
; CHECK-NEXT: call void @store_as0(ptr undef) #[[ATTR4]]
18+
; CHECK-NEXT: ret void
19+
;
20+
call void @store_as0(ptr undef)
21+
ret void
22+
}
23+
24+
define void @store_as0(ptr %0) {
25+
; CHECK-LABEL: define void @store_as0(
26+
; CHECK-SAME: ptr nocapture nofree noundef nonnull writeonly align 2 dereferenceable(2) [[TMP0:%.*]]) #[[ATTR2:[0-9]+]] {
27+
; CHECK-NEXT: store i16 0, ptr [[TMP0]], align 2
28+
; CHECK-NEXT: ret void
29+
;
30+
store i16 0, ptr %0, align 2
31+
ret void
32+
}
33+
34+
define void @call_store_as1() {
35+
; CHECK-LABEL: define void @call_store_as1(
36+
; CHECK-SAME: ) #[[ATTR3:[0-9]+]] {
37+
; CHECK-NEXT: call void @store_as1(ptr addrspace(1) nocapture nofree noundef writeonly align 4294967296 null) #[[ATTR4]]
38+
; CHECK-NEXT: ret void
39+
;
40+
call void @store_as1(ptr addrspace(1) null)
41+
ret void
42+
}
43+
44+
define void @store_as1(ptr addrspace(1) %arg) {
45+
; CHECK-LABEL: define void @store_as1(
46+
; CHECK-SAME: ptr addrspace(1) nocapture nofree noundef writeonly align 2 dereferenceable_or_null(2) [[ARG:%.*]]) #[[ATTR2]] {
47+
; CHECK-NEXT: store i16 0, ptr addrspace(1) [[ARG]], align 2
48+
; CHECK-NEXT: ret void
49+
;
50+
store i16 0, ptr addrspace(1) %arg, align 2
51+
ret void
52+
}
53+
54+
attributes #0 = { null_pointer_is_valid }
55+
;.
56+
; CHECK: attributes #[[ATTR0]] = { mustprogress nofree norecurse nosync nounwind null_pointer_is_valid willreturn memory(write) }
57+
; CHECK: attributes #[[ATTR1]] = { mustprogress nofree norecurse nosync nounwind null_pointer_is_valid willreturn memory(none) }
58+
; CHECK: attributes #[[ATTR2]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write) }
59+
; CHECK: attributes #[[ATTR3]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) }
60+
; CHECK: attributes #[[ATTR4]] = { nofree nosync nounwind willreturn memory(write) }
61+
;.

0 commit comments

Comments
 (0)