Skip to content

Commit

Permalink
Automerge: [LVI] Handle nonnull attributes at callsite (#125377)
Browse files Browse the repository at this point in the history
This patch is the followup of
llvm/llvm-project#124908.
  • Loading branch information
dtcxzyw authored and github-actions[bot] committed Feb 3, 2025
2 parents 8604610 + f17b9dd commit d230658
Show file tree
Hide file tree
Showing 2 changed files with 112 additions and 2 deletions.
13 changes: 11 additions & 2 deletions llvm/lib/Analysis/LazyValueInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -624,10 +624,12 @@ LazyValueInfoImpl::solveBlockValueImpl(Value *Val, BasicBlock *BB) {
return getFromRangeMetadata(BBI);
}

static void AddNonNullPointer(Value *Ptr, NonNullPointerSet &PtrSet) {
static void AddNonNullPointer(Value *Ptr, NonNullPointerSet &PtrSet,
bool IsDereferenced = true) {
// TODO: Use NullPointerIsDefined instead.
if (Ptr->getType()->getPointerAddressSpace() == 0)
PtrSet.insert(getUnderlyingObject(Ptr));
PtrSet.insert(IsDereferenced ? getUnderlyingObject(Ptr)
: Ptr->stripInBoundsOffsets());
}

static void AddNonNullPointersByInstruction(
Expand All @@ -646,6 +648,13 @@ static void AddNonNullPointersByInstruction(
AddNonNullPointer(MI->getRawDest(), PtrSet);
if (MemTransferInst *MTI = dyn_cast<MemTransferInst>(MI))
AddNonNullPointer(MTI->getRawSource(), PtrSet);
} else if (auto *CB = dyn_cast<CallBase>(I)) {
for (auto &U : CB->args()) {
if (U->getType()->isPointerTy() &&
CB->paramHasNonNullAttr(CB->getArgOperandNo(&U),
/*AllowUndefOrPoison=*/false))
AddNonNullPointer(U.get(), PtrSet, /*IsDereferenced=*/false);
}
}
}

Expand Down
101 changes: 101 additions & 0 deletions llvm/test/Transforms/CorrelatedValuePropagation/non-null.ll
Original file line number Diff line number Diff line change
Expand Up @@ -344,4 +344,105 @@ define i1 @test_store_same_block(ptr %arg) {
ret i1 %cmp
}


define i1 @test_known_nonnull_at_callsite(ptr %src) {
; CHECK-LABEL: @test_known_nonnull_at_callsite(
; CHECK-NEXT: entry:
; CHECK-NEXT: call void @callee(ptr noundef nonnull [[SRC:%.*]])
; CHECK-NEXT: [[NONNULL:%.*]] = icmp eq ptr [[SRC]], null
; CHECK-NEXT: ret i1 false
;
entry:
call void @callee(ptr noundef nonnull %src)
%nonnull = icmp eq ptr %src, null
ret i1 %nonnull
}

define i1 @test_known_nonnull_mixed(ptr %src) {
; CHECK-LABEL: @test_known_nonnull_mixed(
; CHECK-NEXT: entry:
; CHECK-NEXT: call void @callee2(ptr nonnull [[SRC:%.*]])
; CHECK-NEXT: [[NONNULL:%.*]] = icmp eq ptr [[SRC]], null
; CHECK-NEXT: ret i1 false
;
entry:
call void @callee2(ptr nonnull %src)
%nonnull = icmp eq ptr %src, null
ret i1 %nonnull
}

define i1 @test_known_nonnull_at_callsite_dereferenceable(ptr %src) {
; CHECK-LABEL: @test_known_nonnull_at_callsite_dereferenceable(
; CHECK-NEXT: entry:
; CHECK-NEXT: call void @callee(ptr dereferenceable(1) [[SRC:%.*]])
; CHECK-NEXT: [[NONNULL:%.*]] = icmp eq ptr [[SRC]], null
; CHECK-NEXT: ret i1 false
;
entry:
call void @callee(ptr dereferenceable(1) %src)
%nonnull = icmp eq ptr %src, null
ret i1 %nonnull
}

define i1 @test_known_nonnull_at_callsite_gep_inbounds(ptr %src, i64 %x) {
; CHECK-LABEL: @test_known_nonnull_at_callsite_gep_inbounds(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i8, ptr [[SRC:%.*]], i64 [[X:%.*]]
; CHECK-NEXT: call void @callee(ptr noundef nonnull [[GEP]])
; CHECK-NEXT: [[NONNULL:%.*]] = icmp eq ptr [[SRC]], null
; CHECK-NEXT: ret i1 false
;
entry:
%gep = getelementptr inbounds i8, ptr %src, i64 %x
call void @callee(ptr noundef nonnull %gep)
%nonnull = icmp eq ptr %src, null
ret i1 %nonnull
}

; Negative tests

define i1 @test_known_nonnull_at_callsite_without_noundef(ptr %src) {
; CHECK-LABEL: @test_known_nonnull_at_callsite_without_noundef(
; CHECK-NEXT: entry:
; CHECK-NEXT: call void @callee(ptr nonnull [[SRC:%.*]])
; CHECK-NEXT: [[NONNULL:%.*]] = icmp eq ptr [[SRC]], null
; CHECK-NEXT: ret i1 [[NONNULL]]
;
entry:
call void @callee(ptr nonnull %src)
%nonnull = icmp eq ptr %src, null
ret i1 %nonnull
}

define i1 @test_known_nonnull_at_callsite_dereferenceable_null_is_defined(ptr %src) #0 {
; CHECK-LABEL: @test_known_nonnull_at_callsite_dereferenceable_null_is_defined(
; CHECK-NEXT: entry:
; CHECK-NEXT: call void @callee(ptr dereferenceable(1) [[SRC:%.*]])
; CHECK-NEXT: [[NONNULL:%.*]] = icmp eq ptr [[SRC]], null
; CHECK-NEXT: ret i1 [[NONNULL]]
;
entry:
call void @callee(ptr dereferenceable(1) %src)
%nonnull = icmp eq ptr %src, null
ret i1 %nonnull
}

define i1 @test_known_nonnull_at_callsite_gep_without_inbounds(ptr %src, i64 %x) {
; CHECK-LABEL: @test_known_nonnull_at_callsite_gep_without_inbounds(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[GEP:%.*]] = getelementptr i8, ptr [[SRC:%.*]], i64 [[X:%.*]]
; CHECK-NEXT: call void @callee(ptr noundef nonnull [[GEP]])
; CHECK-NEXT: [[NONNULL:%.*]] = icmp eq ptr [[SRC]], null
; CHECK-NEXT: ret i1 [[NONNULL]]
;
entry:
%gep = getelementptr i8, ptr %src, i64 %x
call void @callee(ptr noundef nonnull %gep)
%nonnull = icmp eq ptr %src, null
ret i1 %nonnull
}

declare void @callee(ptr)
declare void @callee2(ptr noundef)

attributes #0 = { null_pointer_is_valid }

0 comments on commit d230658

Please sign in to comment.