/// 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
}
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);
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;
declare i64 @strnlen(i8*, i64)
+@ax = external global [0 x i8]
@s5 = constant [6 x i8] c"12345\00"
@s5_3 = constant [9 x i8] c"12345\00xyz"
}
+; 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)
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)
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)
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
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)
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)
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)
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
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
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
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