[llvm] [ValueTracking] Handle nonnull attributes at callsite (PR #124908)
Yingwei Zheng via llvm-commits
llvm-commits at lists.llvm.org
Wed Jan 29 03:38:13 PST 2025
https://github.com/dtcxzyw created https://github.com/llvm/llvm-project/pull/124908
Alive2: https://alive2.llvm.org/ce/z/yJfskv
Closes https://github.com/llvm/llvm-project/issues/124540.
>From 91e0cd3b91610ddfe2861339724c2135efb428af Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Wed, 29 Jan 2025 19:15:51 +0800
Subject: [PATCH 1/2] [ValueTracking] Add pre-commit tests. NFC.
---
.../ValueTracking/known-nonnull-at.ll | 70 +++++++++++++++++++
1 file changed, 70 insertions(+)
diff --git a/llvm/test/Analysis/ValueTracking/known-nonnull-at.ll b/llvm/test/Analysis/ValueTracking/known-nonnull-at.ll
index 79d2653a3a1466..0cd8d8270f2e9d 100644
--- a/llvm/test/Analysis/ValueTracking/known-nonnull-at.ll
+++ b/llvm/test/Analysis/ValueTracking/known-nonnull-at.ll
@@ -220,3 +220,73 @@ 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: [[NONNULL:%.*]] = icmp eq ptr [[SRC]], null
+; CHECK-NEXT: ret i1 [[NONNULL]]
+;
+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 [[NONNULL]]
+;
+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 [[NONNULL]]
+;
+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)
>From b90c7a2dbded44fe10ecb53710810cb9c758ebf8 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Wed, 29 Jan 2025 19:35:20 +0800
Subject: [PATCH 2/2] [ValueTracking] Handle nonnull attributes at callsite
---
llvm/include/llvm/IR/InstrTypes.h | 8 ++++++++
llvm/lib/Analysis/ValueTracking.cpp | 17 +++++++++-------
llvm/lib/IR/Instructions.cpp | 18 +++++++++++++++++
.../ValueTracking/known-nonnull-at.ll | 9 +++------
.../test/Transforms/InstCombine/align-addr.ll | 2 +-
.../Transforms/InstCombine/memset_chk-1.ll | 4 ++--
llvm/test/Transforms/InstCombine/sprintf-1.ll | 4 ++--
llvm/test/Transforms/InstCombine/stpncpy-1.ll | 14 ++++++-------
llvm/test/Transforms/InstCombine/strlcpy-1.ll | 20 +++++++++----------
llvm/test/Transforms/InstCombine/strstr-1.ll | 2 +-
10 files changed, 62 insertions(+), 36 deletions(-)
diff --git a/llvm/include/llvm/IR/InstrTypes.h b/llvm/include/llvm/IR/InstrTypes.h
index 47ddc7555594c5..6ff90e1d095aac 100644
--- a/llvm/include/llvm/IR/InstrTypes.h
+++ b/llvm/include/llvm/IR/InstrTypes.h
@@ -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);
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index b63a0a07f7de29..e83fad07dd32f0 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -2660,13 +2660,16 @@ static bool isKnownNonNullFromDominatingCondition(const Value *V,
// 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>(U))
+ if (auto *CalledFunc = CB->getCalledFunction())
+ for (const Argument &Arg : CalledFunc->args())
+ if (CB->getArgOperand(Arg.getArgNo()) == V &&
+ CB->paramHasNonNullAttr(Arg.getArgNo(),
+ /*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)) {
diff --git a/llvm/lib/IR/Instructions.cpp b/llvm/lib/IR/Instructions.cpp
index c9f5807765e400..ef4a5aca1e8a2a 100644
--- a/llvm/lib/IR/Instructions.cpp
+++ b/llvm/lib/IR/Instructions.cpp
@@ -432,6 +432,24 @@ 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;
+
+ Attribute Attr = getParamAttr(ArgNo, Attribute::Dereferenceable);
+ if (Attr.isValid() && Attr.getDereferenceableBytes() > 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);
diff --git a/llvm/test/Analysis/ValueTracking/known-nonnull-at.ll b/llvm/test/Analysis/ValueTracking/known-nonnull-at.ll
index 0cd8d8270f2e9d..dff7e13b8a2e77 100644
--- a/llvm/test/Analysis/ValueTracking/known-nonnull-at.ll
+++ b/llvm/test/Analysis/ValueTracking/known-nonnull-at.ll
@@ -225,8 +225,7 @@ 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 [[NONNULL]]
+; CHECK-NEXT: ret i1 false
;
entry:
call void @callee(ptr noundef nonnull %src)
@@ -238,8 +237,7 @@ 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 [[NONNULL]]
+; CHECK-NEXT: ret i1 false
;
entry:
call void @callee2(ptr nonnull %src)
@@ -251,8 +249,7 @@ 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 [[NONNULL]]
+; CHECK-NEXT: ret i1 false
;
entry:
call void @callee(ptr dereferenceable(1) %src)
diff --git a/llvm/test/Transforms/InstCombine/align-addr.ll b/llvm/test/Transforms/InstCombine/align-addr.ll
index 6ef4d85fe4e412..b77037e592b54b 100644
--- a/llvm/test/Transforms/InstCombine/align-addr.ll
+++ b/llvm/test/Transforms/InstCombine/align-addr.ll
@@ -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)
diff --git a/llvm/test/Transforms/InstCombine/memset_chk-1.ll b/llvm/test/Transforms/InstCombine/memset_chk-1.ll
index 44b549e400dd85..9020f174fb5b7d 100644
--- a/llvm/test/Transforms/InstCombine/memset_chk-1.ll
+++ b/llvm/test/Transforms/InstCombine/memset_chk-1.ll
@@ -92,7 +92,7 @@ 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
@@ -100,7 +100,7 @@ define i32 @test_rauw(ptr %a, ptr %b, ptr %c) {
; 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:
diff --git a/llvm/test/Transforms/InstCombine/sprintf-1.ll b/llvm/test/Transforms/InstCombine/sprintf-1.ll
index 0749015059415c..1d87758340f710 100644
--- a/llvm/test/Transforms/InstCombine/sprintf-1.ll
+++ b/llvm/test/Transforms/InstCombine/sprintf-1.ll
@@ -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)
@@ -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)
diff --git a/llvm/test/Transforms/InstCombine/stpncpy-1.ll b/llvm/test/Transforms/InstCombine/stpncpy-1.ll
index 87f54918b7d25e..6ef9b425ae9d93 100644
--- a/llvm/test/Transforms/InstCombine/stpncpy-1.ll
+++ b/llvm/test/Transforms/InstCombine/stpncpy-1.ll
@@ -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).
@@ -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
diff --git a/llvm/test/Transforms/InstCombine/strlcpy-1.ll b/llvm/test/Transforms/InstCombine/strlcpy-1.ll
index fd9d0580426f0a..ad538259ae9625 100644
--- a/llvm/test/Transforms/InstCombine/strlcpy-1.ll
+++ b/llvm/test/Transforms/InstCombine/strlcpy-1.ll
@@ -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)
diff --git a/llvm/test/Transforms/InstCombine/strstr-1.ll b/llvm/test/Transforms/InstCombine/strstr-1.ll
index 68de7614aad2ba..083ee47bb47d1f 100644
--- a/llvm/test/Transforms/InstCombine/strstr-1.ll
+++ b/llvm/test/Transforms/InstCombine/strstr-1.ll
@@ -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]]
;
More information about the llvm-commits
mailing list