[llvm] 25febbd - [InstCombine] Fold strnlen with a bound of zero and one.
Martin Sebor via llvm-commits
llvm-commits at lists.llvm.org
Tue Apr 26 13:03:22 PDT 2022
Author: Martin Sebor
Date: 2022-04-26T14:02:50-06:00
New Revision: 25febbd155a5f2edcbe6115e6944cf9ee0367f5e
URL: https://github.com/llvm/llvm-project/commit/25febbd155a5f2edcbe6115e6944cf9ee0367f5e
DIFF: https://github.com/llvm/llvm-project/commit/25febbd155a5f2edcbe6115e6944cf9ee0367f5e.diff
LOG: [InstCombine] Fold strnlen with a bound of zero and one.
Reviewed By: nikic
Differential Revision: https://reviews.llvm.org/D123816
Added:
Modified:
llvm/include/llvm/Transforms/Utils/SimplifyLibCalls.h
llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp
llvm/test/Transforms/InstCombine/strnlen-1.ll
llvm/test/Transforms/InstCombine/strnlen-2.ll
llvm/test/Transforms/InstCombine/strnlen-3.ll
llvm/test/Transforms/InstCombine/strnlen-5.ll
Removed:
################################################################################
diff --git a/llvm/include/llvm/Transforms/Utils/SimplifyLibCalls.h b/llvm/include/llvm/Transforms/Utils/SimplifyLibCalls.h
index 7eca16275cbbb..90a208a68a435 100644
--- a/llvm/include/llvm/Transforms/Utils/SimplifyLibCalls.h
+++ b/llvm/include/llvm/Transforms/Utils/SimplifyLibCalls.h
@@ -237,8 +237,9 @@ class LibCallSimplifier {
/// function by checking for an existing function with name FuncName + f
bool hasFloatVersion(StringRef FuncName);
- /// Shared code to optimize strlen+wcslen.
- Value *optimizeStringLength(CallInst *CI, IRBuilderBase &B, unsigned CharSize);
+ /// Shared code to optimize strlen+wcslen and strnlen+wcsnlen.
+ Value *optimizeStringLength(CallInst *CI, IRBuilderBase &B, unsigned CharSize,
+ Value *Bound = nullptr);
};
} // End llvm namespace
diff --git a/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp b/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp
index 455632730570d..8d59a5ed28d04 100644
--- a/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp
+++ b/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp
@@ -629,9 +629,29 @@ Value *LibCallSimplifier::optimizeStrNCpy(CallInst *CI, IRBuilderBase &B) {
}
Value *LibCallSimplifier::optimizeStringLength(CallInst *CI, IRBuilderBase &B,
- unsigned CharSize) {
+ unsigned CharSize,
+ Value *Bound) {
Value *Src = CI->getArgOperand(0);
+ if (Bound) {
+ if (ConstantInt *BoundCst = dyn_cast<ConstantInt>(Bound)) {
+ if (BoundCst->isZero())
+ // Fold strnlen(s, 0) -> 0 for any s, constant or otherwise.
+ return ConstantInt::get(CI->getType(), 0);
+
+ if (BoundCst->isOne()) {
+ // Fold strnlen(s, 1) -> *s ? 1 : 0 for any s.
+ Type *CharTy = B.getIntNTy(CharSize);
+ Value *CharVal = B.CreateLoad(CharTy, Src, "strnlen.char0");
+ Value *ZeroChar = ConstantInt::get(CharTy, 0);
+ Value *Cmp = B.CreateICmpNE(CharVal, ZeroChar, "strnlen.char0cmp");
+ return B.CreateZExt(Cmp, CI->getType());
+ }
+ }
+ // Otherwise punt for strnlen for now.
+ return nullptr;
+ }
+
// Constant folding: strlen("xyz") -> 3
if (uint64_t Len = GetStringLength(Src, CharSize))
return ConstantInt::get(CI->getType(), Len - 1);
@@ -719,6 +739,9 @@ Value *LibCallSimplifier::optimizeStrLen(CallInst *CI, IRBuilderBase &B) {
Value *LibCallSimplifier::optimizeStrNLen(CallInst *CI, IRBuilderBase &B) {
Value *Bound = CI->getArgOperand(1);
+ if (Value *V = optimizeStringLength(CI, B, 8, Bound))
+ return V;
+
if (isKnownNonZero(Bound, DL))
annotateNonNullNoUndefBasedOnAccess(CI, 0);
return nullptr;
diff --git a/llvm/test/Transforms/InstCombine/strnlen-1.ll b/llvm/test/Transforms/InstCombine/strnlen-1.ll
index f8fabbe8fe615..d07e8ddb9893d 100644
--- a/llvm/test/Transforms/InstCombine/strnlen-1.ll
+++ b/llvm/test/Transforms/InstCombine/strnlen-1.ll
@@ -6,6 +6,7 @@
declare i64 @strnlen(i8*, i64)
+ at ax = external global [0 x i8]
@s5 = constant [6 x i8] c"12345\00"
@s5_3 = constant [9 x i8] c"12345\00xyz"
@@ -51,12 +52,38 @@ define i64 @access_strnlen_p_nz(i8* %ptr, i64 %n) {
}
+; Fold strnlen(ax, 0) to 0.
+
+define i64 @fold_strnlen_ax_0() {
+; CHECK-LABEL: @fold_strnlen_ax_0(
+; CHECK-NEXT: ret i64 0
+;
+ %ptr = getelementptr [0 x i8], [0 x i8]* @ax, i32 0, i32 0
+ %len = call i64 @strnlen(i8* %ptr, i64 0)
+ ret i64 %len
+}
+
+
+; Fold strnlen(ax, 1) to *ax ? 1 : 0.
+
+define i64 @fold_strnlen_ax_1() {
+; CHECK-LABEL: @fold_strnlen_ax_1(
+; CHECK-NEXT: [[STRNLEN_CHAR0:%.*]] = load i8, i8* getelementptr inbounds ([0 x i8], [0 x i8]* @ax, i64 0, i64 0), align 1
+; CHECK-NEXT: [[STRNLEN_CHAR0CMP_NOT:%.*]] = icmp ne i8 [[STRNLEN_CHAR0]], 0
+; CHECK-NEXT: [[STRNLEN_SEL:%.*]] = zext i1 [[STRNLEN_CHAR0CMP_NOT]] to i64
+; CHECK-NEXT: ret i64 [[STRNLEN_SEL]]
+;
+ %ptr = getelementptr [0 x i8], [0 x i8]* @ax, i32 0, i32 0
+ %len = call i64 @strnlen(i8* %ptr, i64 1)
+ ret i64 %len
+}
+
+
; Fold strnlen(s5, 0) to 0.
define i64 @fold_strnlen_s5_0() {
; CHECK-LABEL: @fold_strnlen_s5_0(
-; CHECK-NEXT: [[LEN:%.*]] = call i64 @strnlen(i8* getelementptr inbounds ([6 x i8], [6 x i8]* @s5, i64 0, i64 0), i64 0)
-; CHECK-NEXT: ret i64 [[LEN]]
+; CHECK-NEXT: ret i64 0
;
%ptr = getelementptr [6 x i8], [6 x i8]* @s5, i32 0, i32 0
%len = call i64 @strnlen(i8* %ptr, i64 0)
diff --git a/llvm/test/Transforms/InstCombine/strnlen-2.ll b/llvm/test/Transforms/InstCombine/strnlen-2.ll
index a58ea6b296369..2c16d85f3fb98 100644
--- a/llvm/test/Transforms/InstCombine/strnlen-2.ll
+++ b/llvm/test/Transforms/InstCombine/strnlen-2.ll
@@ -17,9 +17,7 @@ declare i64 @strnlen(i8*, i64)
define i64 @fold_strnlen_s3_s5_0(i1 %C) {
; CHECK-LABEL: @fold_strnlen_s3_s5_0(
-; CHECK-NEXT: [[PTR:%.*]] = select i1 [[C:%.*]], i8* getelementptr inbounds ([4 x i8], [4 x i8]* @s3, i64 0, i64 0), i8* getelementptr inbounds ([7 x i8], [7 x i8]* @s6, i64 0, i64 0)
-; CHECK-NEXT: [[LEN:%.*]] = call i64 @strnlen(i8* [[PTR]], i64 0)
-; CHECK-NEXT: ret i64 [[LEN]]
+; CHECK-NEXT: ret i64 0
;
%ptr = select i1 %C, i8* getelementptr ([4 x i8], [4 x i8]* @s3, i64 0, i64 0), i8* getelementptr ([7 x i8], [7 x i8]* @s6, i64 0, i64 0)
@@ -32,9 +30,7 @@ define i64 @fold_strnlen_s3_s5_0(i1 %C) {
define i64 @fold_strnlen_s3_s5_1(i1 %C) {
; CHECK-LABEL: @fold_strnlen_s3_s5_1(
-; CHECK-NEXT: [[PTR:%.*]] = select i1 [[C:%.*]], i8* getelementptr inbounds ([4 x i8], [4 x i8]* @s3, i64 0, i64 0), i8* getelementptr inbounds ([7 x i8], [7 x i8]* @s6, i64 0, i64 0)
-; CHECK-NEXT: [[LEN:%.*]] = call i64 @strnlen(i8* noundef nonnull dereferenceable(1) [[PTR]], i64 1)
-; CHECK-NEXT: ret i64 [[LEN]]
+; CHECK-NEXT: ret i64 1
;
%ptr = select i1 %C, i8* getelementptr ([4 x i8], [4 x i8]* @s3, i64 0, i64 0), i8* getelementptr ([7 x i8], [7 x i8]* @s6, i64 0, i64 0)
diff --git a/llvm/test/Transforms/InstCombine/strnlen-3.ll b/llvm/test/Transforms/InstCombine/strnlen-3.ll
index 9d1004a1b0800..585a69d1b6db0 100644
--- a/llvm/test/Transforms/InstCombine/strnlen-3.ll
+++ b/llvm/test/Transforms/InstCombine/strnlen-3.ll
@@ -18,9 +18,7 @@ declare i64 @strnlen(i8*, i64)
define i64 @fold_strnlen_sx_pi_0(i64 %i) {
; CHECK-LABEL: @fold_strnlen_sx_pi_0(
-; CHECK-NEXT: [[PTR:%.*]] = getelementptr [0 x i8], [0 x i8]* @sx, i64 0, i64 [[I:%.*]]
-; CHECK-NEXT: [[LEN:%.*]] = call i64 @strnlen(i8* [[PTR]], i64 0)
-; CHECK-NEXT: ret i64 [[LEN]]
+; CHECK-NEXT: ret i64 0
;
%ptr = getelementptr [0 x i8], [0 x i8]* @sx, i64 0, i64 %i
@@ -78,9 +76,7 @@ define i64 @call_strnlen_a3_pi_3(i64 %i) {
define i64 @fold_strnlen_s3_pi_0(i64 %i) {
; CHECK-LABEL: @fold_strnlen_s3_pi_0(
-; CHECK-NEXT: [[PTR:%.*]] = getelementptr inbounds [4 x i8], [4 x i8]* @s3, i64 0, i64 [[I:%.*]]
-; CHECK-NEXT: [[LEN:%.*]] = call i64 @strnlen(i8* nonnull [[PTR]], i64 0)
-; CHECK-NEXT: ret i64 [[LEN]]
+; CHECK-NEXT: ret i64 0
;
%ptr = getelementptr inbounds [4 x i8], [4 x i8]* @s3, i64 0, i64 %i
%len = call i64 @strnlen(i8* %ptr, i64 0)
@@ -92,8 +88,7 @@ define i64 @fold_strnlen_s3_pi_0(i64 %i) {
define i64 @call_strnlen_s5_pi_0(i64 zeroext %i) {
; CHECK-LABEL: @call_strnlen_s5_pi_0(
-; CHECK-NEXT: [[LEN:%.*]] = call i64 @strnlen(i8* getelementptr inbounds ([6 x i8], [6 x i8]* @s5, i64 0, i64 0), i64 0)
-; CHECK-NEXT: ret i64 [[LEN]]
+; CHECK-NEXT: ret i64 0
;
%ptr = getelementptr [6 x i8], [6 x i8]* @s5, i32 0, i32 0
%len = call i64 @strnlen(i8* %ptr, i64 0)
@@ -105,9 +100,7 @@ define i64 @call_strnlen_s5_pi_0(i64 zeroext %i) {
define i64 @fold_strnlen_s5_3_pi_0(i64 zeroext %i) {
; CHECK-LABEL: @fold_strnlen_s5_3_pi_0(
-; CHECK-NEXT: [[PTR:%.*]] = getelementptr [10 x i8], [10 x i8]* @s5_3, i64 0, i64 [[I:%.*]]
-; CHECK-NEXT: [[LEN:%.*]] = call i64 @strnlen(i8* [[PTR]], i64 0)
-; CHECK-NEXT: ret i64 [[LEN]]
+; CHECK-NEXT: ret i64 0
;
%ptr = getelementptr [10 x i8], [10 x i8]* @s5_3, i32 0, i64 %i
%len = call i64 @strnlen(i8* %ptr, i64 0)
diff --git a/llvm/test/Transforms/InstCombine/strnlen-5.ll b/llvm/test/Transforms/InstCombine/strnlen-5.ll
index 125ffda245892..790ad12ea4e63 100644
--- a/llvm/test/Transforms/InstCombine/strnlen-5.ll
+++ b/llvm/test/Transforms/InstCombine/strnlen-5.ll
@@ -15,9 +15,7 @@ declare i64 @strnlen(i8*, i64)
define i1 @fold_strnlen_ax_0_eqz() {
; CHECK-LABEL: @fold_strnlen_ax_0_eqz(
-; CHECK-NEXT: [[LEN:%.*]] = tail call i64 @strnlen(i8* getelementptr inbounds ([0 x i8], [0 x i8]* @ax, i64 0, i64 0), i64 0)
-; CHECK-NEXT: [[EQZ:%.*]] = icmp eq i64 [[LEN]], 0
-; CHECK-NEXT: ret i1 [[EQZ]]
+; CHECK-NEXT: ret i1 true
;
%ptr = getelementptr [0 x i8], [0 x i8]* @ax, i64 0, i64 0
@@ -31,9 +29,7 @@ define i1 @fold_strnlen_ax_0_eqz() {
define i1 @fold_strnlen_ax_0_gtz() {
; CHECK-LABEL: @fold_strnlen_ax_0_gtz(
-; CHECK-NEXT: [[LEN:%.*]] = tail call i64 @strnlen(i8* getelementptr inbounds ([0 x i8], [0 x i8]* @ax, i64 0, i64 0), i64 0)
-; CHECK-NEXT: [[GTZ:%.*]] = icmp ne i64 [[LEN]], 0
-; CHECK-NEXT: ret i1 [[GTZ]]
+; CHECK-NEXT: ret i1 false
;
%ptr = getelementptr [0 x i8], [0 x i8]* @ax, i64 0, i64 0
@@ -47,9 +43,9 @@ define i1 @fold_strnlen_ax_0_gtz() {
define i1 @fold_strnlen_ax_1_eqz() {
; CHECK-LABEL: @fold_strnlen_ax_1_eqz(
-; CHECK-NEXT: [[LEN:%.*]] = tail call i64 @strnlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([0 x i8], [0 x i8]* @ax, i64 0, i64 0), i64 1)
-; CHECK-NEXT: [[EQZ:%.*]] = icmp eq i64 [[LEN]], 0
-; CHECK-NEXT: ret i1 [[EQZ]]
+; CHECK-NEXT: [[STRNLEN_CHAR0:%.*]] = load i8, i8* getelementptr inbounds ([0 x i8], [0 x i8]* @ax, i64 0, i64 0), align 1
+; CHECK-NEXT: [[STRNLEN_CHAR0CMP_NOT:%.*]] = icmp eq i8 [[STRNLEN_CHAR0]], 0
+; CHECK-NEXT: ret i1 [[STRNLEN_CHAR0CMP_NOT]]
;
%ptr = getelementptr [0 x i8], [0 x i8]* @ax, i64 0, i64 0
@@ -63,9 +59,9 @@ define i1 @fold_strnlen_ax_1_eqz() {
define i1 @fold_strnlen_ax_1_neqz() {
; CHECK-LABEL: @fold_strnlen_ax_1_neqz(
-; CHECK-NEXT: [[LEN:%.*]] = tail call i64 @strnlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([0 x i8], [0 x i8]* @ax, i64 0, i64 0), i64 1)
-; CHECK-NEXT: [[NEZ:%.*]] = icmp ne i64 [[LEN]], 0
-; CHECK-NEXT: ret i1 [[NEZ]]
+; CHECK-NEXT: [[STRNLEN_CHAR0:%.*]] = load i8, i8* getelementptr inbounds ([0 x i8], [0 x i8]* @ax, i64 0, i64 0), align 1
+; CHECK-NEXT: [[STRNLEN_CHAR0CMP:%.*]] = icmp ne i8 [[STRNLEN_CHAR0]], 0
+; CHECK-NEXT: ret i1 [[STRNLEN_CHAR0CMP]]
;
%ptr = getelementptr [0 x i8], [0 x i8]* @ax, i64 0, i64 0
More information about the llvm-commits
mailing list