Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ValueTracking] Handle nonnull attributes at callsite #124908

Merged
merged 4 commits into from
Jan 29, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions llvm/include/llvm/IR/InstrTypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -1591,6 +1591,14 @@ class CallBase : public Instruction {
/// Determine whether the argument or parameter has the given attribute.
bool paramHasAttr(unsigned ArgNo, Attribute::AttrKind Kind) const;

/// Return true if this argument has the nonnull attribute on either the
/// CallBase instruction or the called function. Also returns true if at least
/// one byte is known to be dereferenceable and the pointer is in
/// addrspace(0). If \p AllowUndefOrPoison is true, respect the semantics of
/// nonnull attribute and return true even if the argument can be undef or
/// poison.
bool paramHasNonNullAttr(unsigned ArgNo, bool AllowUndefOrPoison) const;

/// Get the attribute of a given kind at a position.
Attribute getAttributeAtIndex(unsigned i, Attribute::AttrKind Kind) const {
return getAttributes().getAttributeAtIndex(i, Kind);
Expand Down
36 changes: 19 additions & 17 deletions llvm/lib/Analysis/ValueTracking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2652,40 +2652,42 @@ static bool isKnownNonNullFromDominatingCondition(const Value *V,
return false;

unsigned NumUsesExplored = 0;
for (const auto *U : V->users()) {
for (auto &U : V->uses()) {
// Avoid massive lists
if (NumUsesExplored >= DomConditionsMaxUses)
break;
NumUsesExplored++;

const Instruction *UI = cast<Instruction>(U.getUser());
// If the value is used as an argument to a call or invoke, then argument
// attributes may provide an answer about null-ness.
if (const auto *CB = dyn_cast<CallBase>(U))
if (auto *CalledFunc = CB->getCalledFunction())
for (const Argument &Arg : CalledFunc->args())
if (CB->getArgOperand(Arg.getArgNo()) == V &&
Arg.hasNonNullAttr(/* AllowUndefOrPoison */ false) &&
DT->dominates(CB, CtxI))
return true;
if (V->getType()->isPointerTy()) {
if (const auto *CB = dyn_cast<CallBase>(UI)) {
if (CB->isArgOperand(&U) &&
CB->paramHasNonNullAttr(CB->getArgOperandNo(&U),
/*AllowUndefOrPoison=*/false) &&
DT->dominates(CB, CtxI))
return true;
}
}

// If the value is used as a load/store, then the pointer must be non null.
if (V == getLoadStorePointerOperand(U)) {
const Instruction *I = cast<Instruction>(U);
if (!NullPointerIsDefined(I->getFunction(),
if (V == getLoadStorePointerOperand(UI)) {
if (!NullPointerIsDefined(UI->getFunction(),
V->getType()->getPointerAddressSpace()) &&
DT->dominates(I, CtxI))
DT->dominates(UI, CtxI))
return true;
}

if ((match(U, m_IDiv(m_Value(), m_Specific(V))) ||
match(U, m_IRem(m_Value(), m_Specific(V)))) &&
isValidAssumeForContext(cast<Instruction>(U), CtxI, DT))
if ((match(UI, m_IDiv(m_Value(), m_Specific(V))) ||
match(UI, m_IRem(m_Value(), m_Specific(V)))) &&
isValidAssumeForContext(UI, CtxI, DT))
return true;

// Consider only compare instructions uniquely controlling a branch
Value *RHS;
CmpPredicate Pred;
if (!match(U, m_c_ICmp(Pred, m_Specific(V), m_Value(RHS))))
if (!match(UI, m_c_ICmp(Pred, m_Specific(V), m_Value(RHS))))
continue;

bool NonNullIfTrue;
Expand All @@ -2698,7 +2700,7 @@ static bool isKnownNonNullFromDominatingCondition(const Value *V,

SmallVector<const User *, 4> WorkList;
SmallPtrSet<const User *, 4> Visited;
for (const auto *CmpU : U->users()) {
for (const auto *CmpU : UI->users()) {
assert(WorkList.empty() && "Should be!");
if (Visited.insert(CmpU).second)
WorkList.push_back(CmpU);
Expand Down
17 changes: 17 additions & 0 deletions llvm/lib/IR/Instructions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -432,6 +432,23 @@ bool CallBase::paramHasAttr(unsigned ArgNo, Attribute::AttrKind Kind) const {
}
}

bool CallBase::paramHasNonNullAttr(unsigned ArgNo,
bool AllowUndefOrPoison) const {
assert(getArgOperand(ArgNo)->getType()->isPointerTy() &&
"Argument must be a pointer");
if (paramHasAttr(ArgNo, Attribute::NonNull) &&
(AllowUndefOrPoison || paramHasAttr(ArgNo, Attribute::NoUndef)))
return true;

if (getParamDereferenceableBytes(ArgNo) > 0 &&
!NullPointerIsDefined(
getCaller(),
getArgOperand(ArgNo)->getType()->getPointerAddressSpace()))
return true;

return false;
}

bool CallBase::hasFnAttrOnCalledFunction(Attribute::AttrKind Kind) const {
if (auto *F = dyn_cast<Function>(getCalledOperand()))
return F->getAttributes().hasFnAttr(Kind);
Expand Down
67 changes: 67 additions & 0 deletions llvm/test/Analysis/ValueTracking/known-nonnull-at.ll
Original file line number Diff line number Diff line change
Expand Up @@ -220,3 +220,70 @@ return:
%retval.0 = phi ptr [ %1, %if.end ], [ null, %entry ]
ret ptr %retval.0
}

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: 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: 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: ret i1 false
;
entry:
call void @callee(ptr dereferenceable(1) %src)
%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) null_pointer_is_valid {
; 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
}

declare void @callee(ptr)
declare void @callee2(ptr noundef)
2 changes: 1 addition & 1 deletion llvm/test/Transforms/InstCombine/align-addr.ll
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ define void @test3(ptr sret(%struct.s) %a4) {
; Check that the alignment is bumped up the alignment of the sret type.
; CHECK-LABEL: @test3(
; CHECK-NEXT: call void @llvm.memset.p0.i64(ptr noundef nonnull align 4 dereferenceable(16) [[A4:%.*]], i8 0, i64 16, i1 false)
; CHECK-NEXT: call void @use(ptr [[A4]])
; CHECK-NEXT: call void @use(ptr nonnull [[A4]])
; CHECK-NEXT: ret void
;
call void @llvm.memset.p0.i64(ptr %a4, i8 0, i64 16, i1 false)
Expand Down
4 changes: 2 additions & 2 deletions llvm/test/Transforms/InstCombine/memset_chk-1.ll
Original file line number Diff line number Diff line change
Expand Up @@ -92,15 +92,15 @@ define i32 @test_rauw(ptr %a, ptr %b, ptr %c) {
; CHECK-NEXT: [[CALL49:%.*]] = call i64 @strlen(ptr noundef nonnull dereferenceable(1) [[A:%.*]])
; CHECK-NEXT: [[ADD180:%.*]] = add i64 [[CALL49]], 1
; CHECK-NEXT: [[YO107:%.*]] = call i64 @llvm.objectsize.i64.p0(ptr [[B:%.*]], i1 false, i1 false, i1 false)
; CHECK-NEXT: [[CALL50:%.*]] = call ptr @__memmove_chk(ptr [[B]], ptr [[A]], i64 [[ADD180]], i64 [[YO107]])
; CHECK-NEXT: [[CALL50:%.*]] = call ptr @__memmove_chk(ptr [[B]], ptr nonnull [[A]], i64 [[ADD180]], i64 [[YO107]])
; CHECK-NEXT: [[STRLEN:%.*]] = call i64 @strlen(ptr noundef nonnull dereferenceable(1) [[B]])
; CHECK-NEXT: [[STRCHR1:%.*]] = getelementptr inbounds i8, ptr [[B]], i64 [[STRLEN]]
; CHECK-NEXT: [[D:%.*]] = load ptr, ptr [[C:%.*]], align 8
; CHECK-NEXT: [[SUB182:%.*]] = ptrtoint ptr [[D]] to i64
; CHECK-NEXT: [[SUB183:%.*]] = ptrtoint ptr [[B]] to i64
; CHECK-NEXT: [[SUB184:%.*]] = sub i64 [[SUB182]], [[SUB183]]
; CHECK-NEXT: [[ADD52_I_I:%.*]] = add nsw i64 [[SUB184]], 1
; CHECK-NEXT: call void @llvm.memset.p0.i64(ptr align 1 [[STRCHR1]], i8 0, i64 [[ADD52_I_I]], i1 false)
; CHECK-NEXT: call void @llvm.memset.p0.i64(ptr nonnull align 1 [[STRCHR1]], i8 0, i64 [[ADD52_I_I]], i1 false)
; CHECK-NEXT: ret i32 4
;
entry:
Expand Down
4 changes: 2 additions & 2 deletions llvm/test/Transforms/InstCombine/sprintf-1.ll
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ define i32 @test_simplify7(ptr %dst, ptr %str) {
; NOSTPCPY-LABEL: @test_simplify7(
; NOSTPCPY-NEXT: [[STRLEN:%.*]] = call i32 @strlen(ptr noundef nonnull dereferenceable(1) [[STR:%.*]])
; NOSTPCPY-NEXT: [[LENINC:%.*]] = add i32 [[STRLEN]], 1
; NOSTPCPY-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 1 [[DST:%.*]], ptr align 1 [[STR]], i32 [[LENINC]], i1 false)
; NOSTPCPY-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 1 [[DST:%.*]], ptr nonnull align 1 [[STR]], i32 [[LENINC]], i1 false)
; NOSTPCPY-NEXT: ret i32 [[STRLEN]]
;
%r = call i32 (ptr, ptr, ...) @sprintf(ptr %dst, ptr @percent_s, ptr %str)
Expand Down Expand Up @@ -133,7 +133,7 @@ define i32 @test_simplify9(ptr %dst, ptr %str) {
; NOSTPCPY-LABEL: @test_simplify9(
; NOSTPCPY-NEXT: [[STRLEN:%.*]] = call i32 @strlen(ptr noundef nonnull dereferenceable(1) [[STR:%.*]])
; NOSTPCPY-NEXT: [[LENINC:%.*]] = add i32 [[STRLEN]], 1
; NOSTPCPY-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 1 [[DST:%.*]], ptr align 1 [[STR]], i32 [[LENINC]], i1 false)
; NOSTPCPY-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 1 [[DST:%.*]], ptr nonnull align 1 [[STR]], i32 [[LENINC]], i1 false)
; NOSTPCPY-NEXT: ret i32 [[STRLEN]]
;
%r = call i32 (ptr, ptr, ...) @sprintf(ptr %dst, ptr @percent_s, ptr %str)
Expand Down
14 changes: 7 additions & 7 deletions llvm/test/Transforms/InstCombine/stpncpy-1.ll
Original file line number Diff line number Diff line change
Expand Up @@ -70,11 +70,11 @@ define void @fold_stpncpy_overlap(ptr %dst, i64 %n) {
define void @call_stpncpy_overlap(ptr %dst, i64 %n) {
; ANY-LABEL: @call_stpncpy_overlap(
; ANY-NEXT: [[ES_2:%.*]] = call ptr @stpncpy(ptr noundef nonnull dereferenceable(1) [[DST:%.*]], ptr noundef nonnull dereferenceable(1) [[DST]], i64 2)
; ANY-NEXT: call void @sink(ptr [[DST]], ptr [[ES_2]])
; ANY-NEXT: call void @sink(ptr nonnull [[DST]], ptr [[ES_2]])
; ANY-NEXT: [[ES_3:%.*]] = call ptr @stpncpy(ptr noundef nonnull dereferenceable(1) [[DST]], ptr noundef nonnull dereferenceable(1) [[DST]], i64 3)
; ANY-NEXT: call void @sink(ptr [[DST]], ptr [[ES_3]])
; ANY-NEXT: [[ES_N:%.*]] = call ptr @stpncpy(ptr [[DST]], ptr [[DST]], i64 [[N:%.*]])
; ANY-NEXT: call void @sink(ptr [[DST]], ptr [[ES_N]])
; ANY-NEXT: call void @sink(ptr nonnull [[DST]], ptr [[ES_3]])
; ANY-NEXT: [[ES_N:%.*]] = call ptr @stpncpy(ptr nonnull [[DST]], ptr nonnull [[DST]], i64 [[N:%.*]])
; ANY-NEXT: call void @sink(ptr nonnull [[DST]], ptr [[ES_N]])
; ANY-NEXT: ret void
;
; Do not transform stpncpy(D, D, 2).
Expand Down Expand Up @@ -428,9 +428,9 @@ define void @fold_stpncpy_s(ptr %dst, ptr %src) {
define void @call_stpncpy_s(ptr %dst, ptr %src, i64 %n) {
; ANY-LABEL: @call_stpncpy_s(
; ANY-NEXT: [[ES_2:%.*]] = call ptr @stpncpy(ptr noundef nonnull dereferenceable(1) [[DST:%.*]], ptr noundef nonnull dereferenceable(1) [[SRC:%.*]], i64 2)
; ANY-NEXT: call void @sink(ptr [[DST]], ptr [[ES_2]])
; ANY-NEXT: [[ES_N:%.*]] = call ptr @stpncpy(ptr [[DST]], ptr [[SRC]], i64 [[N:%.*]])
; ANY-NEXT: call void @sink(ptr [[DST]], ptr [[ES_N]])
; ANY-NEXT: call void @sink(ptr nonnull [[DST]], ptr [[ES_2]])
; ANY-NEXT: [[ES_N:%.*]] = call ptr @stpncpy(ptr nonnull [[DST]], ptr nonnull [[SRC]], i64 [[N:%.*]])
; ANY-NEXT: call void @sink(ptr nonnull [[DST]], ptr [[ES_N]])
; ANY-NEXT: ret void
;
; Do not transform stpncpy(D, S, 2). Both *D and *S must be derefernceable
Expand Down
20 changes: 10 additions & 10 deletions llvm/test/Transforms/InstCombine/strlcpy-1.ll
Original file line number Diff line number Diff line change
Expand Up @@ -229,18 +229,18 @@ define void @fold_strlcpy_s_0(ptr %dst, ptr %s, i64 %n) {
define void @call_strlcpy_s0_n(ptr %dst, ptr %s, i64 %n) {
; ANY-LABEL: @call_strlcpy_s0_n(
; ANY-NEXT: [[NS_2:%.*]] = call i64 @strlcpy(ptr noundef nonnull dereferenceable(1) [[DST:%.*]], ptr noundef nonnull dereferenceable(1) [[S:%.*]], i64 2)
; ANY-NEXT: call void @sink(ptr [[DST]], i64 [[NS_2]])
; ANY-NEXT: [[NS_N:%.*]] = call i64 @strlcpy(ptr [[DST]], ptr noundef nonnull dereferenceable(1) [[S]], i64 [[N:%.*]])
; ANY-NEXT: call void @sink(ptr [[DST]], i64 [[NS_N]])
; ANY-NEXT: call void @sink(ptr nonnull [[DST]], i64 [[NS_2]])
; ANY-NEXT: [[NS_N:%.*]] = call i64 @strlcpy(ptr nonnull [[DST]], ptr noundef nonnull dereferenceable(1) [[S]], i64 [[N:%.*]])
; ANY-NEXT: call void @sink(ptr nonnull [[DST]], i64 [[NS_N]])
; ANY-NEXT: [[NZ:%.*]] = or i64 [[N]], 1
; ANY-NEXT: [[NS_NZ:%.*]] = call i64 @strlcpy(ptr noundef nonnull dereferenceable(1) [[DST]], ptr noundef nonnull dereferenceable(1) [[S]], i64 [[NZ]])
; ANY-NEXT: call void @sink(ptr [[DST]], i64 [[NS_NZ]])
; ANY-NEXT: [[NS0_N:%.*]] = call i64 @strlcpy(ptr [[DST]], ptr noundef nonnull dereferenceable(1) getelementptr inbounds nuw (i8, ptr @s4, i64 4), i64 [[N]])
; ANY-NEXT: call void @sink(ptr [[DST]], i64 [[NS0_N]])
; ANY-NEXT: [[NS1_N:%.*]] = call i64 @strlcpy(ptr [[DST]], ptr noundef nonnull dereferenceable(1) getelementptr inbounds nuw (i8, ptr @s4, i64 3), i64 [[N]])
; ANY-NEXT: call void @sink(ptr [[DST]], i64 [[NS1_N]])
; ANY-NEXT: [[NS4_N:%.*]] = call i64 @strlcpy(ptr [[DST]], ptr noundef nonnull dereferenceable(1) @s4, i64 [[N]])
; ANY-NEXT: call void @sink(ptr [[DST]], i64 [[NS4_N]])
; ANY-NEXT: call void @sink(ptr nonnull [[DST]], i64 [[NS_NZ]])
; 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]])
; ANY-NEXT: call void @sink(ptr nonnull [[DST]], i64 [[NS0_N]])
; 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]])
; ANY-NEXT: call void @sink(ptr nonnull [[DST]], i64 [[NS1_N]])
; ANY-NEXT: [[NS4_N:%.*]] = call i64 @strlcpy(ptr nonnull [[DST]], ptr noundef nonnull dereferenceable(1) @s4, i64 [[N]])
; ANY-NEXT: call void @sink(ptr nonnull [[DST]], i64 [[NS4_N]])
; ANY-NEXT: ret void
;
%ns_2 = call i64 @strlcpy(ptr %dst, ptr %s, i64 2)
Expand Down
16 changes: 8 additions & 8 deletions llvm/test/Transforms/InstCombine/strncpy-4.ll
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,11 @@ define void @fold_strncpy_overlap(ptr %dst, i64 %n) {
define void @call_strncpy_overlap(ptr %dst, i64 %n) {
; CHECK-LABEL: @call_strncpy_overlap(
; CHECK-NEXT: [[ED_2:%.*]] = call ptr @strncpy(ptr noundef nonnull dereferenceable(1) [[DST:%.*]], ptr noundef nonnull dereferenceable(1) [[DST]], i64 2)
; CHECK-NEXT: call void @sink(ptr [[DST]], ptr [[ED_2]])
; CHECK-NEXT: call void @sink(ptr nonnull [[DST]], ptr [[ED_2]])
; CHECK-NEXT: [[ED_3:%.*]] = call ptr @strncpy(ptr noundef nonnull dereferenceable(1) [[DST]], ptr noundef nonnull dereferenceable(1) [[DST]], i64 3)
; CHECK-NEXT: call void @sink(ptr [[DST]], ptr [[ED_3]])
; CHECK-NEXT: [[ED_N:%.*]] = call ptr @strncpy(ptr [[DST]], ptr [[DST]], i64 [[N:%.*]])
; CHECK-NEXT: call void @sink(ptr [[DST]], ptr [[ED_N]])
; CHECK-NEXT: call void @sink(ptr nonnull [[DST]], ptr [[ED_3]])
; CHECK-NEXT: [[ED_N:%.*]] = call ptr @strncpy(ptr nonnull [[DST]], ptr nonnull [[DST]], i64 [[N:%.*]])
; CHECK-NEXT: call void @sink(ptr nonnull [[DST]], ptr [[ED_N]])
; CHECK-NEXT: ret void
;

Expand Down Expand Up @@ -141,11 +141,11 @@ define void @fold_strncpy_s(ptr %dst, ptr %src, i64 %n) {
define void @call_strncpy_s(ptr %dst, ptr %src, i64 %n) {
; CHECK-LABEL: @call_strncpy_s(
; CHECK-NEXT: [[ED_2:%.*]] = call ptr @strncpy(ptr noundef nonnull dereferenceable(1) [[DST:%.*]], ptr noundef nonnull dereferenceable(1) [[SRC:%.*]], i64 2)
; CHECK-NEXT: call void @sink(ptr [[DST]], ptr [[ED_2]])
; CHECK-NEXT: call void @sink(ptr nonnull [[DST]], ptr [[ED_2]])
; CHECK-NEXT: [[ED_9:%.*]] = call ptr @strncpy(ptr noundef nonnull dereferenceable(1) [[DST]], ptr noundef nonnull dereferenceable(1) [[SRC]], i64 9)
; CHECK-NEXT: call void @sink(ptr [[DST]], ptr [[ED_9]])
; CHECK-NEXT: [[ED_N:%.*]] = call ptr @strncpy(ptr [[DST]], ptr [[SRC]], i64 [[N:%.*]])
; CHECK-NEXT: call void @sink(ptr [[DST]], ptr [[ED_N]])
; CHECK-NEXT: call void @sink(ptr nonnull [[DST]], ptr [[ED_9]])
; CHECK-NEXT: [[ED_N:%.*]] = call ptr @strncpy(ptr nonnull [[DST]], ptr nonnull [[SRC]], i64 [[N:%.*]])
; CHECK-NEXT: call void @sink(ptr nonnull [[DST]], ptr [[ED_N]])
; CHECK-NEXT: ret void
;
; Do not transform strncpy(D, S, 2) when S is unknown. Both *D and *S must
Expand Down
2 changes: 1 addition & 1 deletion llvm/test/Transforms/InstCombine/strstr-1.ll
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ define ptr @test_simplify4(ptr %str) {
define i1 @test_simplify5(ptr %str, ptr %pat) {
; CHECK-LABEL: @test_simplify5(
; CHECK-NEXT: [[STRLEN:%.*]] = call i64 @strlen(ptr noundef nonnull dereferenceable(1) [[PAT:%.*]])
; CHECK-NEXT: [[STRNCMP:%.*]] = call i32 @strncmp(ptr [[STR:%.*]], ptr [[PAT]], i64 [[STRLEN]])
; CHECK-NEXT: [[STRNCMP:%.*]] = call i32 @strncmp(ptr [[STR:%.*]], ptr nonnull [[PAT]], i64 [[STRLEN]])
; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 [[STRNCMP]], 0
; CHECK-NEXT: ret i1 [[CMP1]]
;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,10 @@
declare void @zero_args()
declare void @two_args(ptr, ptr)

; TODO: Could be non-null based on call-site attributes.
define i1 @test_zero_args_nonnull(ptr %p) {
dtcxzyw marked this conversation as resolved.
Show resolved Hide resolved
; CHECK-LABEL: @test_zero_args_nonnull(
; CHECK-NEXT: call void @zero_args(ptr noundef nonnull [[P:%.*]])
; CHECK-NEXT: [[C:%.*]] = icmp ne ptr [[P]], null
; CHECK-NEXT: ret i1 [[C]]
; CHECK-NEXT: ret i1 true
;
call void @zero_args(ptr nonnull noundef %p)
%c = icmp ne ptr %p, null
Expand All @@ -27,12 +25,10 @@ define i1 @test_zero_args_maybe_null(ptr %p) {
ret i1 %c
}

; TODO: Could be non-null based on call-site attributes.
define i1 @test_two_args_nonnull(ptr %p) {
; CHECK-LABEL: @test_two_args_nonnull(
; CHECK-NEXT: call void @two_args(ptr noundef nonnull [[P:%.*]])
; CHECK-NEXT: [[C:%.*]] = icmp ne ptr [[P]], null
; CHECK-NEXT: ret i1 [[C]]
; CHECK-NEXT: ret i1 true
;
call void @two_args(ptr nonnull noundef %p)
%c = icmp ne ptr %p, null
Expand Down
Loading