Skip to content

Commit f17b9dd

Browse files
authored
[LVI] Handle nonnull attributes at callsite (llvm#125377)
This patch is the followup of llvm#124908.
1 parent edc8c35 commit f17b9dd

File tree

2 files changed

+112
-2
lines changed

2 files changed

+112
-2
lines changed

llvm/lib/Analysis/LazyValueInfo.cpp

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -624,10 +624,12 @@ LazyValueInfoImpl::solveBlockValueImpl(Value *Val, BasicBlock *BB) {
624624
return getFromRangeMetadata(BBI);
625625
}
626626

627-
static void AddNonNullPointer(Value *Ptr, NonNullPointerSet &PtrSet) {
627+
static void AddNonNullPointer(Value *Ptr, NonNullPointerSet &PtrSet,
628+
bool IsDereferenced = true) {
628629
// TODO: Use NullPointerIsDefined instead.
629630
if (Ptr->getType()->getPointerAddressSpace() == 0)
630-
PtrSet.insert(getUnderlyingObject(Ptr));
631+
PtrSet.insert(IsDereferenced ? getUnderlyingObject(Ptr)
632+
: Ptr->stripInBoundsOffsets());
631633
}
632634

633635
static void AddNonNullPointersByInstruction(
@@ -646,6 +648,13 @@ static void AddNonNullPointersByInstruction(
646648
AddNonNullPointer(MI->getRawDest(), PtrSet);
647649
if (MemTransferInst *MTI = dyn_cast<MemTransferInst>(MI))
648650
AddNonNullPointer(MTI->getRawSource(), PtrSet);
651+
} else if (auto *CB = dyn_cast<CallBase>(I)) {
652+
for (auto &U : CB->args()) {
653+
if (U->getType()->isPointerTy() &&
654+
CB->paramHasNonNullAttr(CB->getArgOperandNo(&U),
655+
/*AllowUndefOrPoison=*/false))
656+
AddNonNullPointer(U.get(), PtrSet, /*IsDereferenced=*/false);
657+
}
649658
}
650659
}
651660

llvm/test/Transforms/CorrelatedValuePropagation/non-null.ll

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -344,4 +344,105 @@ define i1 @test_store_same_block(ptr %arg) {
344344
ret i1 %cmp
345345
}
346346

347+
348+
define i1 @test_known_nonnull_at_callsite(ptr %src) {
349+
; CHECK-LABEL: @test_known_nonnull_at_callsite(
350+
; CHECK-NEXT: entry:
351+
; CHECK-NEXT: call void @callee(ptr noundef nonnull [[SRC:%.*]])
352+
; CHECK-NEXT: [[NONNULL:%.*]] = icmp eq ptr [[SRC]], null
353+
; CHECK-NEXT: ret i1 false
354+
;
355+
entry:
356+
call void @callee(ptr noundef nonnull %src)
357+
%nonnull = icmp eq ptr %src, null
358+
ret i1 %nonnull
359+
}
360+
361+
define i1 @test_known_nonnull_mixed(ptr %src) {
362+
; CHECK-LABEL: @test_known_nonnull_mixed(
363+
; CHECK-NEXT: entry:
364+
; CHECK-NEXT: call void @callee2(ptr nonnull [[SRC:%.*]])
365+
; CHECK-NEXT: [[NONNULL:%.*]] = icmp eq ptr [[SRC]], null
366+
; CHECK-NEXT: ret i1 false
367+
;
368+
entry:
369+
call void @callee2(ptr nonnull %src)
370+
%nonnull = icmp eq ptr %src, null
371+
ret i1 %nonnull
372+
}
373+
374+
define i1 @test_known_nonnull_at_callsite_dereferenceable(ptr %src) {
375+
; CHECK-LABEL: @test_known_nonnull_at_callsite_dereferenceable(
376+
; CHECK-NEXT: entry:
377+
; CHECK-NEXT: call void @callee(ptr dereferenceable(1) [[SRC:%.*]])
378+
; CHECK-NEXT: [[NONNULL:%.*]] = icmp eq ptr [[SRC]], null
379+
; CHECK-NEXT: ret i1 false
380+
;
381+
entry:
382+
call void @callee(ptr dereferenceable(1) %src)
383+
%nonnull = icmp eq ptr %src, null
384+
ret i1 %nonnull
385+
}
386+
387+
define i1 @test_known_nonnull_at_callsite_gep_inbounds(ptr %src, i64 %x) {
388+
; CHECK-LABEL: @test_known_nonnull_at_callsite_gep_inbounds(
389+
; CHECK-NEXT: entry:
390+
; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i8, ptr [[SRC:%.*]], i64 [[X:%.*]]
391+
; CHECK-NEXT: call void @callee(ptr noundef nonnull [[GEP]])
392+
; CHECK-NEXT: [[NONNULL:%.*]] = icmp eq ptr [[SRC]], null
393+
; CHECK-NEXT: ret i1 false
394+
;
395+
entry:
396+
%gep = getelementptr inbounds i8, ptr %src, i64 %x
397+
call void @callee(ptr noundef nonnull %gep)
398+
%nonnull = icmp eq ptr %src, null
399+
ret i1 %nonnull
400+
}
401+
402+
; Negative tests
403+
404+
define i1 @test_known_nonnull_at_callsite_without_noundef(ptr %src) {
405+
; CHECK-LABEL: @test_known_nonnull_at_callsite_without_noundef(
406+
; CHECK-NEXT: entry:
407+
; CHECK-NEXT: call void @callee(ptr nonnull [[SRC:%.*]])
408+
; CHECK-NEXT: [[NONNULL:%.*]] = icmp eq ptr [[SRC]], null
409+
; CHECK-NEXT: ret i1 [[NONNULL]]
410+
;
411+
entry:
412+
call void @callee(ptr nonnull %src)
413+
%nonnull = icmp eq ptr %src, null
414+
ret i1 %nonnull
415+
}
416+
417+
define i1 @test_known_nonnull_at_callsite_dereferenceable_null_is_defined(ptr %src) #0 {
418+
; CHECK-LABEL: @test_known_nonnull_at_callsite_dereferenceable_null_is_defined(
419+
; CHECK-NEXT: entry:
420+
; CHECK-NEXT: call void @callee(ptr dereferenceable(1) [[SRC:%.*]])
421+
; CHECK-NEXT: [[NONNULL:%.*]] = icmp eq ptr [[SRC]], null
422+
; CHECK-NEXT: ret i1 [[NONNULL]]
423+
;
424+
entry:
425+
call void @callee(ptr dereferenceable(1) %src)
426+
%nonnull = icmp eq ptr %src, null
427+
ret i1 %nonnull
428+
}
429+
430+
define i1 @test_known_nonnull_at_callsite_gep_without_inbounds(ptr %src, i64 %x) {
431+
; CHECK-LABEL: @test_known_nonnull_at_callsite_gep_without_inbounds(
432+
; CHECK-NEXT: entry:
433+
; CHECK-NEXT: [[GEP:%.*]] = getelementptr i8, ptr [[SRC:%.*]], i64 [[X:%.*]]
434+
; CHECK-NEXT: call void @callee(ptr noundef nonnull [[GEP]])
435+
; CHECK-NEXT: [[NONNULL:%.*]] = icmp eq ptr [[SRC]], null
436+
; CHECK-NEXT: ret i1 [[NONNULL]]
437+
;
438+
entry:
439+
%gep = getelementptr i8, ptr %src, i64 %x
440+
call void @callee(ptr noundef nonnull %gep)
441+
%nonnull = icmp eq ptr %src, null
442+
ret i1 %nonnull
443+
}
444+
445+
declare void @callee(ptr)
446+
declare void @callee2(ptr noundef)
447+
347448
attributes #0 = { null_pointer_is_valid }

0 commit comments

Comments
 (0)