[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