[InstCombine] Fold strnlen of constant strings.

Reviewed By: nikic

Differential Revision: https://reviews.llvm.org/D123817
This commit is contained in:
Martin Sebor 2022-04-26 16:12:57 -06:00
parent a1bb5719ec
commit 449adafabe
3 changed files with 24 additions and 23 deletions

View File

@ -632,6 +632,7 @@ Value *LibCallSimplifier::optimizeStringLength(CallInst *CI, IRBuilderBase &B,
unsigned CharSize, unsigned CharSize,
Value *Bound) { Value *Bound) {
Value *Src = CI->getArgOperand(0); Value *Src = CI->getArgOperand(0);
Type *CharTy = B.getIntNTy(CharSize);
if (Bound) { if (Bound) {
if (ConstantInt *BoundCst = dyn_cast<ConstantInt>(Bound)) { if (ConstantInt *BoundCst = dyn_cast<ConstantInt>(Bound)) {
@ -641,20 +642,26 @@ Value *LibCallSimplifier::optimizeStringLength(CallInst *CI, IRBuilderBase &B,
if (BoundCst->isOne()) { if (BoundCst->isOne()) {
// Fold strnlen(s, 1) -> *s ? 1 : 0 for any s. // Fold strnlen(s, 1) -> *s ? 1 : 0 for any s.
Type *CharTy = B.getIntNTy(CharSize);
Value *CharVal = B.CreateLoad(CharTy, Src, "strnlen.char0"); Value *CharVal = B.CreateLoad(CharTy, Src, "strnlen.char0");
Value *ZeroChar = ConstantInt::get(CharTy, 0); Value *ZeroChar = ConstantInt::get(CharTy, 0);
Value *Cmp = B.CreateICmpNE(CharVal, ZeroChar, "strnlen.char0cmp"); Value *Cmp = B.CreateICmpNE(CharVal, ZeroChar, "strnlen.char0cmp");
return B.CreateZExt(Cmp, CI->getType()); 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)) {
if (uint64_t Len = GetStringLength(Src, CharSize)) Value *LenC = ConstantInt::get(CI->getType(), Len - 1);
return 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 // 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 // strlen(s + x) to strlen(s) - x, when x is known to be in the range

View File

@ -95,8 +95,7 @@ define i64 @fold_strnlen_s5_0() {
define i64 @fold_strnlen_s5_4() { define i64 @fold_strnlen_s5_4() {
; CHECK-LABEL: @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 4
; CHECK-NEXT: ret i64 [[LEN]]
; ;
%ptr = getelementptr [6 x i8], [6 x i8]* @s5, i32 0, i32 0 %ptr = getelementptr [6 x i8], [6 x i8]* @s5, i32 0, i32 0
%len = call i64 @strnlen(i8* %ptr, i64 4) %len = call i64 @strnlen(i8* %ptr, i64 4)
@ -108,8 +107,7 @@ define i64 @fold_strnlen_s5_4() {
define i64 @fold_strnlen_s5_5() { define i64 @fold_strnlen_s5_5() {
; CHECK-LABEL: @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 5
; CHECK-NEXT: ret i64 [[LEN]]
; ;
%ptr = getelementptr [6 x i8], [6 x i8]* @s5, i32 0, i32 0 %ptr = getelementptr [6 x i8], [6 x i8]* @s5, i32 0, i32 0
%len = call i64 @strnlen(i8* %ptr, i64 5) %len = call i64 @strnlen(i8* %ptr, i64 5)
@ -121,8 +119,7 @@ define i64 @fold_strnlen_s5_5() {
define i64 @fold_strnlen_s5_m1() { define i64 @fold_strnlen_s5_m1() {
; CHECK-LABEL: @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 5
; CHECK-NEXT: ret i64 [[LEN]]
; ;
%ptr = getelementptr [6 x i8], [6 x i8]* @s5, i32 0, i32 0 %ptr = getelementptr [6 x i8], [6 x i8]* @s5, i32 0, i32 0
%len = call i64 @strnlen(i8* %ptr, i64 -1) %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() { define i64 @fold_strnlen_s5_3_p4_5() {
; CHECK-LABEL: @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 1
; CHECK-NEXT: ret i64 [[LEN]]
; ;
%ptr = getelementptr [9 x i8], [9 x i8]* @s5_3, i32 0, i32 4 %ptr = getelementptr [9 x i8], [9 x i8]* @s5_3, i32 0, i32 4
%len = call i64 @strnlen(i8* %ptr, i64 5) %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() { define i64 @fold_strnlen_s5_3_p5_5() {
; CHECK-LABEL: @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 0
; CHECK-NEXT: ret i64 [[LEN]]
; ;
%ptr = getelementptr [9 x i8], [9 x i8]* @s5_3, i32 0, i32 5 %ptr = getelementptr [9 x i8], [9 x i8]* @s5_3, i32 0, i32 5
%len = call i64 @strnlen(i8* %ptr, i64 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() { define i64 @fold_strnlen_s5_3_p6_5() {
; CHECK-LABEL: @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 3
; CHECK-NEXT: ret i64 [[LEN]]
; ;
%ptr = getelementptr [9 x i8], [9 x i8]* @s5_3, i32 0, i32 6 %ptr = getelementptr [9 x i8], [9 x i8]* @s5_3, i32 0, i32 6
%len = call i64 @strnlen(i8* %ptr, i64 5) %len = call i64 @strnlen(i8* %ptr, i64 5)

View File

@ -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) { define i64 @fold_strnlen_a3_n(i64 %n) {
; CHECK-LABEL: @fold_strnlen_a3_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: [[TMP1:%.*]] = call i64 @llvm.umin.i64(i64 [[N:%.*]], i64 3)
; CHECK-NEXT: ret i64 [[LEN]] ; CHECK-NEXT: ret i64 [[TMP1]]
; ;
%ptr = getelementptr [3 x i8], [3 x i8]* @a3, i64 0, i64 0 %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) { define i64 @fold_strnlen_s3_n(i64 %n) {
; CHECK-LABEL: @fold_strnlen_s3_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: [[TMP1:%.*]] = call i64 @llvm.umin.i64(i64 [[N:%.*]], i64 3)
; CHECK-NEXT: ret i64 [[LEN]] ; CHECK-NEXT: ret i64 [[TMP1]]
; ;
%ptr = getelementptr [4 x i8], [4 x i8]* @s3, i64 0, i64 0 %ptr = getelementptr [4 x i8], [4 x i8]* @s3, i64 0, i64 0