Index: llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp =================================================================== --- llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp +++ llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp @@ -903,6 +903,26 @@ return Constant::getNullValue(CI->getType()); } + Value *NullPtr = Constant::getNullValue(CI->getType()); + + if (ConstantInt *CharC = dyn_cast(CharVal)) { + // Fold memrchr(S, C, N) for a constant C. + size_t Pos = Str.rfind(CharC->getZExtValue(), EndOff); + if (Pos == StringRef::npos) + // When the character is not in the source array fold the result + // to null regardless of Size. + return Constant::getNullValue(CI->getType()); + + if (LenC) { + // Fold memrchr(s, c, N) --> N <= Pos ? null : s + Pos for constant N. + Value *Cmp = B.CreateICmpULE(Size, ConstantInt::get(Size->getType(), Pos), + "memrchr.cmp"); + Value *SrcPlus = B.CreateGEP(B.getInt8Ty(), SrcStr, B.getInt64(Pos), + "memrchr.ptr_plus"); + return B.CreateSelect(Cmp, NullPtr, SrcPlus, "memrchr.sel"); + } + } + return nullptr; } Index: llvm/test/Transforms/InstCombine/memrchr-3.ll =================================================================== --- llvm/test/Transforms/InstCombine/memrchr-3.ll +++ llvm/test/Transforms/InstCombine/memrchr-3.ll @@ -105,8 +105,7 @@ define i8* @fold_memrchr_a12345_5_5() { ; CHECK-LABEL: @fold_memrchr_a12345_5_5( -; CHECK-NEXT: [[RET:%.*]] = call i8* @memrchr(i8* noundef nonnull dereferenceable(5) getelementptr inbounds ([5 x i8], [5 x i8]* @a12345, i64 0, i64 0), i32 5, i64 5) -; CHECK-NEXT: ret i8* [[RET]] +; CHECK-NEXT: ret i8* getelementptr inbounds ([5 x i8], [5 x i8]* @a12345, i64 0, i64 4) ; %ptr = getelementptr [5 x i8], [5 x i8]* @a12345, i32 0, i32 0 @@ -119,8 +118,7 @@ define i8* @fold_memrchr_a12345_5_4() { ; CHECK-LABEL: @fold_memrchr_a12345_5_4( -; CHECK-NEXT: [[RET:%.*]] = call i8* @memrchr(i8* noundef nonnull dereferenceable(4) getelementptr inbounds ([5 x i8], [5 x i8]* @a12345, i64 0, i64 0), i32 5, i64 4) -; CHECK-NEXT: ret i8* [[RET]] +; CHECK-NEXT: ret i8* null ; %ptr = getelementptr [5 x i8], [5 x i8]* @a12345, i32 0, i32 0 @@ -133,8 +131,7 @@ define i8* @fold_memrchr_a12345_4_5() { ; CHECK-LABEL: @fold_memrchr_a12345_4_5( -; CHECK-NEXT: [[RET:%.*]] = call i8* @memrchr(i8* noundef nonnull dereferenceable(5) getelementptr inbounds ([5 x i8], [5 x i8]* @a12345, i64 0, i64 0), i32 4, i64 5) -; CHECK-NEXT: ret i8* [[RET]] +; CHECK-NEXT: ret i8* getelementptr inbounds ([5 x i8], [5 x i8]* @a12345, i64 0, i64 3) ; %ptr = getelementptr [5 x i8], [5 x i8]* @a12345, i32 0, i32 0 @@ -147,8 +144,7 @@ define i8* @fold_memrchr_a12345p1_1_4() { ; CHECK-LABEL: @fold_memrchr_a12345p1_1_4( -; CHECK-NEXT: [[RET:%.*]] = call i8* @memrchr(i8* noundef nonnull dereferenceable(4) getelementptr inbounds ([5 x i8], [5 x i8]* @a12345, i64 0, i64 1), i32 5, i64 4) -; CHECK-NEXT: ret i8* [[RET]] +; CHECK-NEXT: ret i8* getelementptr inbounds ([5 x i8], [5 x i8]* @a12345, i64 0, i64 4) ; %ptr = getelementptr [5 x i8], [5 x i8]* @a12345, i32 0, i32 1 @@ -161,8 +157,7 @@ define i8* @fold_memrchr_a12345_2_5() { ; CHECK-LABEL: @fold_memrchr_a12345_2_5( -; CHECK-NEXT: [[RET:%.*]] = call i8* @memrchr(i8* noundef nonnull dereferenceable(5) getelementptr inbounds ([5 x i8], [5 x i8]* @a12345, i64 0, i64 0), i32 2, i64 5) -; CHECK-NEXT: ret i8* [[RET]] +; CHECK-NEXT: ret i8* getelementptr inbounds ([5 x i8], [5 x i8]* @a12345, i64 0, i64 1) ; %ptr = getelementptr [5 x i8], [5 x i8]* @a12345, i32 0, i32 0 @@ -175,8 +170,7 @@ define i8* @fold_memrchr_a12345_0_n(i64 %0) { ; CHECK-LABEL: @fold_memrchr_a12345_0_n( -; CHECK-NEXT: [[RET:%.*]] = call i8* @memrchr(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @a12345, i64 0, i64 0), i32 0, i64 [[TMP0:%.*]]) -; CHECK-NEXT: ret i8* [[RET]] +; CHECK-NEXT: ret i8* null ; %ptr = getelementptr [5 x i8], [5 x i8]* @a12345, i32 0, i32 0 @@ -189,8 +183,7 @@ define i8* @fold_memrchr_a123123_3_5() { ; CHECK-LABEL: @fold_memrchr_a123123_3_5( -; CHECK-NEXT: [[RET:%.*]] = call i8* @memrchr(i8* noundef nonnull dereferenceable(5) getelementptr inbounds ([6 x i8], [6 x i8]* @a123123, i64 0, i64 0), i32 3, i64 5) -; CHECK-NEXT: ret i8* [[RET]] +; CHECK-NEXT: ret i8* getelementptr inbounds ([6 x i8], [6 x i8]* @a123123, i64 0, i64 2) ; %ptr = getelementptr [6 x i8], [6 x i8]* @a123123, i32 0, i32 0 @@ -203,8 +196,7 @@ define i8* @fold_memrchr_a123123_3_6() { ; CHECK-LABEL: @fold_memrchr_a123123_3_6( -; CHECK-NEXT: [[RET:%.*]] = call i8* @memrchr(i8* noundef nonnull dereferenceable(6) getelementptr inbounds ([6 x i8], [6 x i8]* @a123123, i64 0, i64 0), i32 3, i64 6) -; CHECK-NEXT: ret i8* [[RET]] +; CHECK-NEXT: ret i8* getelementptr inbounds ([6 x i8], [6 x i8]* @a123123, i64 0, i64 5) ; %ptr = getelementptr [6 x i8], [6 x i8]* @a123123, i32 0, i32 0 @@ -216,8 +208,7 @@ define i8* @fold_memrchr_a123123_2_6() { ; CHECK-LABEL: @fold_memrchr_a123123_2_6( -; CHECK-NEXT: [[RET:%.*]] = call i8* @memrchr(i8* noundef nonnull dereferenceable(6) getelementptr inbounds ([6 x i8], [6 x i8]* @a123123, i64 0, i64 0), i32 2, i64 6) -; CHECK-NEXT: ret i8* [[RET]] +; CHECK-NEXT: ret i8* getelementptr inbounds ([6 x i8], [6 x i8]* @a123123, i64 0, i64 4) ; %ptr = getelementptr [6 x i8], [6 x i8]* @a123123, i32 0, i32 0 @@ -229,8 +220,7 @@ define i8* @fold_memrchr_a123123_1_6() { ; CHECK-LABEL: @fold_memrchr_a123123_1_6( -; CHECK-NEXT: [[RET:%.*]] = call i8* @memrchr(i8* noundef nonnull dereferenceable(6) getelementptr inbounds ([6 x i8], [6 x i8]* @a123123, i64 0, i64 0), i32 1, i64 6) -; CHECK-NEXT: ret i8* [[RET]] +; CHECK-NEXT: ret i8* getelementptr inbounds ([6 x i8], [6 x i8]* @a123123, i64 0, i64 3) ; %ptr = getelementptr [6 x i8], [6 x i8]* @a123123, i32 0, i32 0 @@ -243,8 +233,7 @@ define i8* @fold_memrchr_a123123_0_6() { ; CHECK-LABEL: @fold_memrchr_a123123_0_6( -; CHECK-NEXT: [[RET:%.*]] = call i8* @memrchr(i8* noundef nonnull dereferenceable(6) getelementptr inbounds ([6 x i8], [6 x i8]* @a123123, i64 0, i64 0), i32 0, i64 6) -; CHECK-NEXT: ret i8* [[RET]] +; CHECK-NEXT: ret i8* null ; %ptr = getelementptr [6 x i8], [6 x i8]* @a123123, i32 0, i32 0