Index: llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp =================================================================== --- llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp +++ llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp @@ -2591,6 +2591,14 @@ } if (FormatStr[1] == 's') { + // snprintf(NULL, 0, "%s", str) to strlen(str) + if (isa(CI->getArgOperand(0)) && N == 0) + if (auto *V = emitStrLen(CI->getArgOperand(3), B, DL, TLI)) { + if (CI->getType() != V->getType()) + V = B.CreateTrunc(V, CI->getType()); + return V; + } + // snprintf(dest, size, "%s", str) to llvm.memcpy(dest, str, len+1, 1) StringRef Str; if (!getConstantStringInfo(CI->getArgOperand(3), Str)) Index: llvm/test/Transforms/InstCombine/snprintf.ll =================================================================== --- llvm/test/Transforms/InstCombine/snprintf.ll +++ llvm/test/Transforms/InstCombine/snprintf.ll @@ -136,3 +136,23 @@ %call = call i32 (i8*, i64, i8*, ...) @snprintf(i8* %buf, i64 32, i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str.3, i64 0, i64 0), i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i64 0, i64 0)) #2 ret i32 %call } + + +define i32 @snprint_unknown_str_len(i8* %fmt, i8* %s) { +; CHECK-LABEL: @snprint_unknown_str_len( +; CHECK-NEXT: [[LEN:%.*]] = call i32 (i8*, i64, i8*, ...) @snprintf(i8* null, i64 0, i8* [[FMT:%.*]], i8* [[S:%.*]]) +; CHECK-NEXT: ret i32 [[LEN]] +; + %len = call i32 (i8*, i64, i8*, ...) @snprintf(i8* null, i64 0, i8* %fmt, i8* %s) + ret i32 %len +} + +define i32 @snprint_to_strlen(i8* %s) { +; CHECK-LABEL: @snprint_to_strlen( +; CHECK-NEXT: [[STRLEN:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) [[S:%.*]]) +; CHECK-NEXT: [[TMP1:%.*]] = trunc i64 [[STRLEN]] to i32 +; CHECK-NEXT: ret i32 [[TMP1]] +; + %len = call i32 (i8*, i64, i8*, ...) @snprintf(i8* null, i64 0, i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str.3, i64 0, i64 0), i8* %s) + ret i32 %len +}