diff --git a/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp b/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp index 312aebf46db7c..a948a554e2799 100644 --- a/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp +++ b/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp @@ -632,6 +632,7 @@ Value *LibCallSimplifier::optimizeStringLength(CallInst *CI, IRBuilderBase &B, unsigned CharSize, Value *Bound) { Value *Src = CI->getArgOperand(0); + Type *CharTy = B.getIntNTy(CharSize); if (Bound) { if (ConstantInt *BoundCst = dyn_cast(Bound)) { @@ -641,20 +642,26 @@ Value *LibCallSimplifier::optimizeStringLength(CallInst *CI, IRBuilderBase &B, 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); + if (uint64_t Len = GetStringLength(Src, CharSize)) { + Value *LenC = ConstantInt::get(CI->getType(), Len - 1); + // Fold strlen("xyz") -> 3 and strnlen("xyz", 2) -> 2 + // and strnlen("xyz", Bound) -> min(3, Bound) for nonconstant Bound. + if (Bound) + return B.CreateBinaryIntrinsic(Intrinsic::umin, LenC, Bound); + return LenC; + } + + if (Bound) + // Punt for strnlen for now. + return nullptr; // If s is a constant pointer pointing to a string literal, we can fold // strlen(s + x) to strlen(s) - x, when x is known to be in the range diff --git a/llvm/test/Transforms/InstCombine/strnlen-1.ll b/llvm/test/Transforms/InstCombine/strnlen-1.ll index d07e8ddb9893d..d17c11e21964c 100644 --- a/llvm/test/Transforms/InstCombine/strnlen-1.ll +++ b/llvm/test/Transforms/InstCombine/strnlen-1.ll @@ -95,8 +95,7 @@ define i64 @fold_strnlen_s5_0() { define i64 @fold_strnlen_s5_4() { ; CHECK-LABEL: @fold_strnlen_s5_4( -; CHECK-NEXT: [[LEN:%.*]] = call i64 @strnlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([6 x i8], [6 x i8]* @s5, i64 0, i64 0), i64 4) -; CHECK-NEXT: ret i64 [[LEN]] +; CHECK-NEXT: ret i64 4 ; %ptr = getelementptr [6 x i8], [6 x i8]* @s5, i32 0, i32 0 %len = call i64 @strnlen(i8* %ptr, i64 4) @@ -108,8 +107,7 @@ define i64 @fold_strnlen_s5_4() { define i64 @fold_strnlen_s5_5() { ; CHECK-LABEL: @fold_strnlen_s5_5( -; CHECK-NEXT: [[LEN:%.*]] = call i64 @strnlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([6 x i8], [6 x i8]* @s5, i64 0, i64 0), i64 5) -; CHECK-NEXT: ret i64 [[LEN]] +; CHECK-NEXT: ret i64 5 ; %ptr = getelementptr [6 x i8], [6 x i8]* @s5, i32 0, i32 0 %len = call i64 @strnlen(i8* %ptr, i64 5) @@ -121,8 +119,7 @@ define i64 @fold_strnlen_s5_5() { define i64 @fold_strnlen_s5_m1() { ; CHECK-LABEL: @fold_strnlen_s5_m1( -; CHECK-NEXT: [[LEN:%.*]] = call i64 @strnlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([6 x i8], [6 x i8]* @s5, i64 0, i64 0), i64 -1) -; CHECK-NEXT: ret i64 [[LEN]] +; CHECK-NEXT: ret i64 5 ; %ptr = getelementptr [6 x i8], [6 x i8]* @s5, i32 0, i32 0 %len = call i64 @strnlen(i8* %ptr, i64 -1) @@ -134,8 +131,7 @@ define i64 @fold_strnlen_s5_m1() { define i64 @fold_strnlen_s5_3_p4_5() { ; CHECK-LABEL: @fold_strnlen_s5_3_p4_5( -; CHECK-NEXT: [[LEN:%.*]] = call i64 @strnlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([9 x i8], [9 x i8]* @s5_3, i64 0, i64 4), i64 5) -; CHECK-NEXT: ret i64 [[LEN]] +; CHECK-NEXT: ret i64 1 ; %ptr = getelementptr [9 x i8], [9 x i8]* @s5_3, i32 0, i32 4 %len = call i64 @strnlen(i8* %ptr, i64 5) @@ -143,12 +139,11 @@ define i64 @fold_strnlen_s5_3_p4_5() { } -; Fold strnlen(s5_3 + 5, 5) to 1. +; Fold strnlen(s5_3 + 5, 5) to 0. define i64 @fold_strnlen_s5_3_p5_5() { ; CHECK-LABEL: @fold_strnlen_s5_3_p5_5( -; CHECK-NEXT: [[LEN:%.*]] = call i64 @strnlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([9 x i8], [9 x i8]* @s5_3, i64 0, i64 5), i64 5) -; CHECK-NEXT: ret i64 [[LEN]] +; CHECK-NEXT: ret i64 0 ; %ptr = getelementptr [9 x i8], [9 x i8]* @s5_3, i32 0, i32 5 %len = call i64 @strnlen(i8* %ptr, i64 5) @@ -160,8 +155,7 @@ define i64 @fold_strnlen_s5_3_p5_5() { define i64 @fold_strnlen_s5_3_p6_5() { ; CHECK-LABEL: @fold_strnlen_s5_3_p6_5( -; CHECK-NEXT: [[LEN:%.*]] = call i64 @strnlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([9 x i8], [9 x i8]* @s5_3, i64 0, i64 6), i64 5) -; CHECK-NEXT: ret i64 [[LEN]] +; CHECK-NEXT: ret i64 3 ; %ptr = getelementptr [9 x i8], [9 x i8]* @s5_3, i32 0, i32 6 %len = call i64 @strnlen(i8* %ptr, i64 5) diff --git a/llvm/test/Transforms/InstCombine/strnlen-3.ll b/llvm/test/Transforms/InstCombine/strnlen-3.ll index 585a69d1b6db0..877eae813c683 100644 --- a/llvm/test/Transforms/InstCombine/strnlen-3.ll +++ b/llvm/test/Transforms/InstCombine/strnlen-3.ll @@ -126,8 +126,8 @@ define i64 @call_strnlen_s5_3_pi_n(i64 zeroext %i, i64 %n) { define i64 @fold_strnlen_a3_n(i64 %n) { ; CHECK-LABEL: @fold_strnlen_a3_n( -; CHECK-NEXT: [[LEN:%.*]] = call i64 @strnlen(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @a3, i64 0, i64 0), i64 [[N:%.*]]) -; CHECK-NEXT: ret i64 [[LEN]] +; CHECK-NEXT: [[TMP1:%.*]] = call i64 @llvm.umin.i64(i64 [[N:%.*]], i64 3) +; CHECK-NEXT: ret i64 [[TMP1]] ; %ptr = getelementptr [3 x i8], [3 x i8]* @a3, i64 0, i64 0 @@ -140,8 +140,8 @@ define i64 @fold_strnlen_a3_n(i64 %n) { define i64 @fold_strnlen_s3_n(i64 %n) { ; CHECK-LABEL: @fold_strnlen_s3_n( -; CHECK-NEXT: [[LEN:%.*]] = call i64 @strnlen(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @s3, i64 0, i64 0), i64 [[N:%.*]]) -; CHECK-NEXT: ret i64 [[LEN]] +; CHECK-NEXT: [[TMP1:%.*]] = call i64 @llvm.umin.i64(i64 [[N:%.*]], i64 3) +; CHECK-NEXT: ret i64 [[TMP1]] ; %ptr = getelementptr [4 x i8], [4 x i8]* @s3, i64 0, i64 0