Skip to content

Commit b90c7a2

Browse files
committed
[ValueTracking] Handle nonnull attributes at callsite
1 parent 91e0cd3 commit b90c7a2

File tree

10 files changed

+62
-36
lines changed

10 files changed

+62
-36
lines changed

llvm/include/llvm/IR/InstrTypes.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1591,6 +1591,14 @@ class CallBase : public Instruction {
15911591
/// Determine whether the argument or parameter has the given attribute.
15921592
bool paramHasAttr(unsigned ArgNo, Attribute::AttrKind Kind) const;
15931593

1594+
/// Return true if this argument has the nonnull attribute on either the
1595+
/// CallBase instruction or the called function. Also returns true if at least
1596+
/// one byte is known to be dereferenceable and the pointer is in
1597+
/// addrspace(0). If \p AllowUndefOrPoison is true, respect the semantics of
1598+
/// nonnull attribute and return true even if the argument can be undef or
1599+
/// poison.
1600+
bool paramHasNonNullAttr(unsigned ArgNo, bool AllowUndefOrPoison) const;
1601+
15941602
/// Get the attribute of a given kind at a position.
15951603
Attribute getAttributeAtIndex(unsigned i, Attribute::AttrKind Kind) const {
15961604
return getAttributes().getAttributeAtIndex(i, Kind);

llvm/lib/Analysis/ValueTracking.cpp

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2660,13 +2660,16 @@ static bool isKnownNonNullFromDominatingCondition(const Value *V,
26602660

26612661
// If the value is used as an argument to a call or invoke, then argument
26622662
// attributes may provide an answer about null-ness.
2663-
if (const auto *CB = dyn_cast<CallBase>(U))
2664-
if (auto *CalledFunc = CB->getCalledFunction())
2665-
for (const Argument &Arg : CalledFunc->args())
2666-
if (CB->getArgOperand(Arg.getArgNo()) == V &&
2667-
Arg.hasNonNullAttr(/* AllowUndefOrPoison */ false) &&
2668-
DT->dominates(CB, CtxI))
2669-
return true;
2663+
if (V->getType()->isPointerTy()) {
2664+
if (const auto *CB = dyn_cast<CallBase>(U))
2665+
if (auto *CalledFunc = CB->getCalledFunction())
2666+
for (const Argument &Arg : CalledFunc->args())
2667+
if (CB->getArgOperand(Arg.getArgNo()) == V &&
2668+
CB->paramHasNonNullAttr(Arg.getArgNo(),
2669+
/*AllowUndefOrPoison=*/false) &&
2670+
DT->dominates(CB, CtxI))
2671+
return true;
2672+
}
26702673

26712674
// If the value is used as a load/store, then the pointer must be non null.
26722675
if (V == getLoadStorePointerOperand(U)) {

llvm/lib/IR/Instructions.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -432,6 +432,24 @@ bool CallBase::paramHasAttr(unsigned ArgNo, Attribute::AttrKind Kind) const {
432432
}
433433
}
434434

435+
bool CallBase::paramHasNonNullAttr(unsigned ArgNo,
436+
bool AllowUndefOrPoison) const {
437+
assert(getArgOperand(ArgNo)->getType()->isPointerTy() &&
438+
"Argument must be a pointer");
439+
if (paramHasAttr(ArgNo, Attribute::NonNull) &&
440+
(AllowUndefOrPoison || paramHasAttr(ArgNo, Attribute::NoUndef)))
441+
return true;
442+
443+
Attribute Attr = getParamAttr(ArgNo, Attribute::Dereferenceable);
444+
if (Attr.isValid() && Attr.getDereferenceableBytes() > 0 &&
445+
!NullPointerIsDefined(
446+
getCaller(),
447+
getArgOperand(ArgNo)->getType()->getPointerAddressSpace()))
448+
return true;
449+
450+
return false;
451+
}
452+
435453
bool CallBase::hasFnAttrOnCalledFunction(Attribute::AttrKind Kind) const {
436454
if (auto *F = dyn_cast<Function>(getCalledOperand()))
437455
return F->getAttributes().hasFnAttr(Kind);

llvm/test/Analysis/ValueTracking/known-nonnull-at.ll

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -225,8 +225,7 @@ define i1 @test_known_nonnull_at_callsite(ptr %src) {
225225
; CHECK-LABEL: @test_known_nonnull_at_callsite(
226226
; CHECK-NEXT: entry:
227227
; CHECK-NEXT: call void @callee(ptr noundef nonnull [[SRC:%.*]])
228-
; CHECK-NEXT: [[NONNULL:%.*]] = icmp eq ptr [[SRC]], null
229-
; CHECK-NEXT: ret i1 [[NONNULL]]
228+
; CHECK-NEXT: ret i1 false
230229
;
231230
entry:
232231
call void @callee(ptr noundef nonnull %src)
@@ -238,8 +237,7 @@ define i1 @test_known_nonnull_mixed(ptr %src) {
238237
; CHECK-LABEL: @test_known_nonnull_mixed(
239238
; CHECK-NEXT: entry:
240239
; CHECK-NEXT: call void @callee2(ptr nonnull [[SRC:%.*]])
241-
; CHECK-NEXT: [[NONNULL:%.*]] = icmp eq ptr [[SRC]], null
242-
; CHECK-NEXT: ret i1 [[NONNULL]]
240+
; CHECK-NEXT: ret i1 false
243241
;
244242
entry:
245243
call void @callee2(ptr nonnull %src)
@@ -251,8 +249,7 @@ define i1 @test_known_nonnull_at_callsite_dereferenceable(ptr %src) {
251249
; CHECK-LABEL: @test_known_nonnull_at_callsite_dereferenceable(
252250
; CHECK-NEXT: entry:
253251
; CHECK-NEXT: call void @callee(ptr dereferenceable(1) [[SRC:%.*]])
254-
; CHECK-NEXT: [[NONNULL:%.*]] = icmp eq ptr [[SRC]], null
255-
; CHECK-NEXT: ret i1 [[NONNULL]]
252+
; CHECK-NEXT: ret i1 false
256253
;
257254
entry:
258255
call void @callee(ptr dereferenceable(1) %src)

llvm/test/Transforms/InstCombine/align-addr.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ define void @test3(ptr sret(%struct.s) %a4) {
112112
; Check that the alignment is bumped up the alignment of the sret type.
113113
; CHECK-LABEL: @test3(
114114
; CHECK-NEXT: call void @llvm.memset.p0.i64(ptr noundef nonnull align 4 dereferenceable(16) [[A4:%.*]], i8 0, i64 16, i1 false)
115-
; CHECK-NEXT: call void @use(ptr [[A4]])
115+
; CHECK-NEXT: call void @use(ptr nonnull [[A4]])
116116
; CHECK-NEXT: ret void
117117
;
118118
call void @llvm.memset.p0.i64(ptr %a4, i8 0, i64 16, i1 false)

llvm/test/Transforms/InstCombine/memset_chk-1.ll

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,15 +92,15 @@ define i32 @test_rauw(ptr %a, ptr %b, ptr %c) {
9292
; CHECK-NEXT: [[CALL49:%.*]] = call i64 @strlen(ptr noundef nonnull dereferenceable(1) [[A:%.*]])
9393
; CHECK-NEXT: [[ADD180:%.*]] = add i64 [[CALL49]], 1
9494
; CHECK-NEXT: [[YO107:%.*]] = call i64 @llvm.objectsize.i64.p0(ptr [[B:%.*]], i1 false, i1 false, i1 false)
95-
; CHECK-NEXT: [[CALL50:%.*]] = call ptr @__memmove_chk(ptr [[B]], ptr [[A]], i64 [[ADD180]], i64 [[YO107]])
95+
; CHECK-NEXT: [[CALL50:%.*]] = call ptr @__memmove_chk(ptr [[B]], ptr nonnull [[A]], i64 [[ADD180]], i64 [[YO107]])
9696
; CHECK-NEXT: [[STRLEN:%.*]] = call i64 @strlen(ptr noundef nonnull dereferenceable(1) [[B]])
9797
; CHECK-NEXT: [[STRCHR1:%.*]] = getelementptr inbounds i8, ptr [[B]], i64 [[STRLEN]]
9898
; CHECK-NEXT: [[D:%.*]] = load ptr, ptr [[C:%.*]], align 8
9999
; CHECK-NEXT: [[SUB182:%.*]] = ptrtoint ptr [[D]] to i64
100100
; CHECK-NEXT: [[SUB183:%.*]] = ptrtoint ptr [[B]] to i64
101101
; CHECK-NEXT: [[SUB184:%.*]] = sub i64 [[SUB182]], [[SUB183]]
102102
; CHECK-NEXT: [[ADD52_I_I:%.*]] = add nsw i64 [[SUB184]], 1
103-
; CHECK-NEXT: call void @llvm.memset.p0.i64(ptr align 1 [[STRCHR1]], i8 0, i64 [[ADD52_I_I]], i1 false)
103+
; CHECK-NEXT: call void @llvm.memset.p0.i64(ptr nonnull align 1 [[STRCHR1]], i8 0, i64 [[ADD52_I_I]], i1 false)
104104
; CHECK-NEXT: ret i32 4
105105
;
106106
entry:

llvm/test/Transforms/InstCombine/sprintf-1.ll

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ define i32 @test_simplify7(ptr %dst, ptr %str) {
103103
; NOSTPCPY-LABEL: @test_simplify7(
104104
; NOSTPCPY-NEXT: [[STRLEN:%.*]] = call i32 @strlen(ptr noundef nonnull dereferenceable(1) [[STR:%.*]])
105105
; NOSTPCPY-NEXT: [[LENINC:%.*]] = add i32 [[STRLEN]], 1
106-
; NOSTPCPY-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 1 [[DST:%.*]], ptr align 1 [[STR]], i32 [[LENINC]], i1 false)
106+
; NOSTPCPY-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 1 [[DST:%.*]], ptr nonnull align 1 [[STR]], i32 [[LENINC]], i1 false)
107107
; NOSTPCPY-NEXT: ret i32 [[STRLEN]]
108108
;
109109
%r = call i32 (ptr, ptr, ...) @sprintf(ptr %dst, ptr @percent_s, ptr %str)
@@ -133,7 +133,7 @@ define i32 @test_simplify9(ptr %dst, ptr %str) {
133133
; NOSTPCPY-LABEL: @test_simplify9(
134134
; NOSTPCPY-NEXT: [[STRLEN:%.*]] = call i32 @strlen(ptr noundef nonnull dereferenceable(1) [[STR:%.*]])
135135
; NOSTPCPY-NEXT: [[LENINC:%.*]] = add i32 [[STRLEN]], 1
136-
; NOSTPCPY-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 1 [[DST:%.*]], ptr align 1 [[STR]], i32 [[LENINC]], i1 false)
136+
; NOSTPCPY-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 1 [[DST:%.*]], ptr nonnull align 1 [[STR]], i32 [[LENINC]], i1 false)
137137
; NOSTPCPY-NEXT: ret i32 [[STRLEN]]
138138
;
139139
%r = call i32 (ptr, ptr, ...) @sprintf(ptr %dst, ptr @percent_s, ptr %str)

llvm/test/Transforms/InstCombine/stpncpy-1.ll

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -70,11 +70,11 @@ define void @fold_stpncpy_overlap(ptr %dst, i64 %n) {
7070
define void @call_stpncpy_overlap(ptr %dst, i64 %n) {
7171
; ANY-LABEL: @call_stpncpy_overlap(
7272
; ANY-NEXT: [[ES_2:%.*]] = call ptr @stpncpy(ptr noundef nonnull dereferenceable(1) [[DST:%.*]], ptr noundef nonnull dereferenceable(1) [[DST]], i64 2)
73-
; ANY-NEXT: call void @sink(ptr [[DST]], ptr [[ES_2]])
73+
; ANY-NEXT: call void @sink(ptr nonnull [[DST]], ptr [[ES_2]])
7474
; ANY-NEXT: [[ES_3:%.*]] = call ptr @stpncpy(ptr noundef nonnull dereferenceable(1) [[DST]], ptr noundef nonnull dereferenceable(1) [[DST]], i64 3)
75-
; ANY-NEXT: call void @sink(ptr [[DST]], ptr [[ES_3]])
76-
; ANY-NEXT: [[ES_N:%.*]] = call ptr @stpncpy(ptr [[DST]], ptr [[DST]], i64 [[N:%.*]])
77-
; ANY-NEXT: call void @sink(ptr [[DST]], ptr [[ES_N]])
75+
; ANY-NEXT: call void @sink(ptr nonnull [[DST]], ptr [[ES_3]])
76+
; ANY-NEXT: [[ES_N:%.*]] = call ptr @stpncpy(ptr nonnull [[DST]], ptr nonnull [[DST]], i64 [[N:%.*]])
77+
; ANY-NEXT: call void @sink(ptr nonnull [[DST]], ptr [[ES_N]])
7878
; ANY-NEXT: ret void
7979
;
8080
; Do not transform stpncpy(D, D, 2).
@@ -428,9 +428,9 @@ define void @fold_stpncpy_s(ptr %dst, ptr %src) {
428428
define void @call_stpncpy_s(ptr %dst, ptr %src, i64 %n) {
429429
; ANY-LABEL: @call_stpncpy_s(
430430
; ANY-NEXT: [[ES_2:%.*]] = call ptr @stpncpy(ptr noundef nonnull dereferenceable(1) [[DST:%.*]], ptr noundef nonnull dereferenceable(1) [[SRC:%.*]], i64 2)
431-
; ANY-NEXT: call void @sink(ptr [[DST]], ptr [[ES_2]])
432-
; ANY-NEXT: [[ES_N:%.*]] = call ptr @stpncpy(ptr [[DST]], ptr [[SRC]], i64 [[N:%.*]])
433-
; ANY-NEXT: call void @sink(ptr [[DST]], ptr [[ES_N]])
431+
; ANY-NEXT: call void @sink(ptr nonnull [[DST]], ptr [[ES_2]])
432+
; ANY-NEXT: [[ES_N:%.*]] = call ptr @stpncpy(ptr nonnull [[DST]], ptr nonnull [[SRC]], i64 [[N:%.*]])
433+
; ANY-NEXT: call void @sink(ptr nonnull [[DST]], ptr [[ES_N]])
434434
; ANY-NEXT: ret void
435435
;
436436
; Do not transform stpncpy(D, S, 2). Both *D and *S must be derefernceable

llvm/test/Transforms/InstCombine/strlcpy-1.ll

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -229,18 +229,18 @@ define void @fold_strlcpy_s_0(ptr %dst, ptr %s, i64 %n) {
229229
define void @call_strlcpy_s0_n(ptr %dst, ptr %s, i64 %n) {
230230
; ANY-LABEL: @call_strlcpy_s0_n(
231231
; ANY-NEXT: [[NS_2:%.*]] = call i64 @strlcpy(ptr noundef nonnull dereferenceable(1) [[DST:%.*]], ptr noundef nonnull dereferenceable(1) [[S:%.*]], i64 2)
232-
; ANY-NEXT: call void @sink(ptr [[DST]], i64 [[NS_2]])
233-
; ANY-NEXT: [[NS_N:%.*]] = call i64 @strlcpy(ptr [[DST]], ptr noundef nonnull dereferenceable(1) [[S]], i64 [[N:%.*]])
234-
; ANY-NEXT: call void @sink(ptr [[DST]], i64 [[NS_N]])
232+
; ANY-NEXT: call void @sink(ptr nonnull [[DST]], i64 [[NS_2]])
233+
; ANY-NEXT: [[NS_N:%.*]] = call i64 @strlcpy(ptr nonnull [[DST]], ptr noundef nonnull dereferenceable(1) [[S]], i64 [[N:%.*]])
234+
; ANY-NEXT: call void @sink(ptr nonnull [[DST]], i64 [[NS_N]])
235235
; ANY-NEXT: [[NZ:%.*]] = or i64 [[N]], 1
236236
; ANY-NEXT: [[NS_NZ:%.*]] = call i64 @strlcpy(ptr noundef nonnull dereferenceable(1) [[DST]], ptr noundef nonnull dereferenceable(1) [[S]], i64 [[NZ]])
237-
; ANY-NEXT: call void @sink(ptr [[DST]], i64 [[NS_NZ]])
238-
; ANY-NEXT: [[NS0_N:%.*]] = call i64 @strlcpy(ptr [[DST]], ptr noundef nonnull dereferenceable(1) getelementptr inbounds nuw (i8, ptr @s4, i64 4), i64 [[N]])
239-
; ANY-NEXT: call void @sink(ptr [[DST]], i64 [[NS0_N]])
240-
; ANY-NEXT: [[NS1_N:%.*]] = call i64 @strlcpy(ptr [[DST]], ptr noundef nonnull dereferenceable(1) getelementptr inbounds nuw (i8, ptr @s4, i64 3), i64 [[N]])
241-
; ANY-NEXT: call void @sink(ptr [[DST]], i64 [[NS1_N]])
242-
; ANY-NEXT: [[NS4_N:%.*]] = call i64 @strlcpy(ptr [[DST]], ptr noundef nonnull dereferenceable(1) @s4, i64 [[N]])
243-
; ANY-NEXT: call void @sink(ptr [[DST]], i64 [[NS4_N]])
237+
; ANY-NEXT: call void @sink(ptr nonnull [[DST]], i64 [[NS_NZ]])
238+
; ANY-NEXT: [[NS0_N:%.*]] = call i64 @strlcpy(ptr nonnull [[DST]], ptr noundef nonnull dereferenceable(1) getelementptr inbounds nuw (i8, ptr @s4, i64 4), i64 [[N]])
239+
; ANY-NEXT: call void @sink(ptr nonnull [[DST]], i64 [[NS0_N]])
240+
; ANY-NEXT: [[NS1_N:%.*]] = call i64 @strlcpy(ptr nonnull [[DST]], ptr noundef nonnull dereferenceable(1) getelementptr inbounds nuw (i8, ptr @s4, i64 3), i64 [[N]])
241+
; ANY-NEXT: call void @sink(ptr nonnull [[DST]], i64 [[NS1_N]])
242+
; ANY-NEXT: [[NS4_N:%.*]] = call i64 @strlcpy(ptr nonnull [[DST]], ptr noundef nonnull dereferenceable(1) @s4, i64 [[N]])
243+
; ANY-NEXT: call void @sink(ptr nonnull [[DST]], i64 [[NS4_N]])
244244
; ANY-NEXT: ret void
245245
;
246246
%ns_2 = call i64 @strlcpy(ptr %dst, ptr %s, i64 2)

llvm/test/Transforms/InstCombine/strstr-1.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ define ptr @test_simplify4(ptr %str) {
5858
define i1 @test_simplify5(ptr %str, ptr %pat) {
5959
; CHECK-LABEL: @test_simplify5(
6060
; CHECK-NEXT: [[STRLEN:%.*]] = call i64 @strlen(ptr noundef nonnull dereferenceable(1) [[PAT:%.*]])
61-
; CHECK-NEXT: [[STRNCMP:%.*]] = call i32 @strncmp(ptr [[STR:%.*]], ptr [[PAT]], i64 [[STRLEN]])
61+
; CHECK-NEXT: [[STRNCMP:%.*]] = call i32 @strncmp(ptr [[STR:%.*]], ptr nonnull [[PAT]], i64 [[STRLEN]])
6262
; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 [[STRNCMP]], 0
6363
; CHECK-NEXT: ret i1 [[CMP1]]
6464
;

0 commit comments

Comments
 (0)