Index: include/llvm/Analysis/TargetLibraryInfo.def =================================================================== --- include/llvm/Analysis/TargetLibraryInfo.def +++ include/llvm/Analysis/TargetLibraryInfo.def @@ -372,6 +372,15 @@ /// float __sinpif(float x); TLI_DEFINE_ENUM_INTERNAL(sinpif) TLI_DEFINE_STRING_INTERNAL("__sinpif") +/// int __small_fprintf(FILE *stream, const char *format, ...); +TLI_DEFINE_ENUM_INTERNAL(small_fprintf) +TLI_DEFINE_STRING_INTERNAL("__small_fprintf") +/// int __small_printf(const char *format, ...); +TLI_DEFINE_ENUM_INTERNAL(small_printf) +TLI_DEFINE_STRING_INTERNAL("__small_printf") +/// int __small_sprintf(char *str, const char *format, ...); +TLI_DEFINE_ENUM_INTERNAL(small_sprintf) +TLI_DEFINE_STRING_INTERNAL("__small_sprintf") /// double __sqrt_finite(double x); TLI_DEFINE_ENUM_INTERNAL(sqrt_finite) TLI_DEFINE_STRING_INTERNAL("__sqrt_finite") Index: lib/Analysis/TargetLibraryInfo.cpp =================================================================== --- lib/Analysis/TargetLibraryInfo.cpp +++ lib/Analysis/TargetLibraryInfo.cpp @@ -152,13 +152,21 @@ TLI.setAvailableWithName(LibFunc_fputs, "fputs$UNIX2003"); } - // iprintf and friends are only available on XCore and TCE. - if (T.getArch() != Triple::xcore && T.getArch() != Triple::tce) { + // iprintf and friends are only available on XCore, TCE, and WASI. + if (T.getArch() != Triple::xcore && T.getArch() != Triple::tce && + T.getOS() != Triple::WASI) { TLI.setUnavailable(LibFunc_iprintf); TLI.setUnavailable(LibFunc_siprintf); TLI.setUnavailable(LibFunc_fiprintf); } + // __small_printf and friends are only available on WASI. + if (T.getOS() != Triple::WASI) { + TLI.setUnavailable(LibFunc_small_printf); + TLI.setUnavailable(LibFunc_small_sprintf); + TLI.setUnavailable(LibFunc_small_fprintf); + } + if (T.isOSWindows() && !T.isOSCygMing()) { // Win32 does not support long double TLI.setUnavailable(LibFunc_acosl); @@ -738,6 +746,7 @@ case LibFunc_stat: case LibFunc_statvfs: case LibFunc_siprintf: + case LibFunc_small_sprintf: case LibFunc_sprintf: return (NumParams >= 2 && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(1)->isPointerTy() && @@ -835,6 +844,7 @@ case LibFunc_getenv: case LibFunc_getpwnam: case LibFunc_iprintf: + case LibFunc_small_printf: case LibFunc_pclose: case LibFunc_perror: case LibFunc_printf: @@ -914,6 +924,7 @@ FTy.getParamType(1)->isPointerTy()); case LibFunc_fscanf: case LibFunc_fiprintf: + case LibFunc_small_fprintf: case LibFunc_fprintf: return (NumParams >= 2 && FTy.getReturnType()->isIntegerTy() && FTy.getParamType(0)->isPointerTy() && Index: lib/Transforms/Utils/SimplifyLibCalls.cpp =================================================================== --- lib/Transforms/Utils/SimplifyLibCalls.cpp +++ lib/Transforms/Utils/SimplifyLibCalls.cpp @@ -104,6 +104,12 @@ }); } +static bool callHasFP128Argument(const CallInst *CI) { + return any_of(CI->operands(), [](const Use &OI) { + return OI->getType()->isFP128Ty(); + }); +} + static Value *convertStrToNumber(CallInst *CI, StringRef &Str, int64_t Base) { if (Base < 2 || Base > 36) // handle special zero base @@ -2031,6 +2037,20 @@ B.Insert(New); return New; } + + // printf(format, ...) -> __small_printf(format, ...) if no 128-bit floating point + // arguments. + if (TLI->has(LibFunc_small_printf) && !callHasFP128Argument(CI)) { + Module *M = B.GetInsertBlock()->getParent()->getParent(); + auto SmallPrintFFn = + M->getOrInsertFunction(TLI->getName(LibFunc_small_printf), + FT, Callee->getAttributes()); + CallInst *New = cast(CI->clone()); + New->setCalledFunction(SmallPrintFFn); + B.Insert(New); + return New; + } + return nullptr; } @@ -2110,6 +2130,20 @@ B.Insert(New); return New; } + + // sprintf(str, format, ...) -> __small_sprintf(str, format, ...) if no 128-bit + // floating point arguments. + if (TLI->has(LibFunc_small_sprintf) && !callHasFP128Argument(CI)) { + Module *M = B.GetInsertBlock()->getParent()->getParent(); + auto SmallSPrintFFn = + M->getOrInsertFunction(TLI->getName(LibFunc_small_sprintf), + FT, Callee->getAttributes()); + CallInst *New = cast(CI->clone()); + New->setCalledFunction(SmallSPrintFFn); + B.Insert(New); + return New; + } + return nullptr; } @@ -2267,6 +2301,20 @@ B.Insert(New); return New; } + + // fprintf(stream, format, ...) -> __small_fprintf(stream, format, ...) if no + // 128-bit floating point arguments. + if (TLI->has(LibFunc_small_fprintf) && !callHasFP128Argument(CI)) { + Module *M = B.GetInsertBlock()->getParent()->getParent(); + auto SmallFPrintFFn = + M->getOrInsertFunction(TLI->getName(LibFunc_small_fprintf), + FT, Callee->getAttributes()); + CallInst *New = cast(CI->clone()); + New->setCalledFunction(SmallFPrintFFn); + B.Insert(New); + return New; + } + return nullptr; } Index: test/Transforms/InstCombine/fprintf-1.ll =================================================================== --- test/Transforms/InstCombine/fprintf-1.ll +++ test/Transforms/InstCombine/fprintf-1.ll @@ -2,6 +2,7 @@ ; ; RUN: opt < %s -instcombine -S | FileCheck %s ; RUN: opt < %s -mtriple xcore-xmos-elf -instcombine -S | FileCheck %s -check-prefix=CHECK-IPRINTF +; RUN: opt < %s -mtriple wasm32-unknown-wasi -instcombine -S | FileCheck %s -check-prefix=CHECK-SMALL-PRINTF target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:128:128" @@ -11,6 +12,7 @@ @percent_c = constant [3 x i8] c"%c\00" @percent_d = constant [3 x i8] c"%d\00" @percent_f = constant [3 x i8] c"%f\00" +@percent_Lf = constant [4 x i8] c"%Lf\00" @percent_s = constant [3 x i8] c"%s\00" declare i32 @fprintf(%FILE*, i8*, ...) @@ -61,6 +63,17 @@ ; CHECK-IPRINTF-NEXT: ret void } +; Check fprintf(fp, fmt, ...) -> __small_fprintf(fp, fmt, ...) if no fp128. + +define void @test_simplify6(%FILE* %fp) { +; CHECK-SMALL-PRINTF-LABEL: @test_simplify6( + %fmt = getelementptr [3 x i8], [3 x i8]* @percent_f, i32 0, i32 0 + call i32 (%FILE*, i8*, ...) @fprintf(%FILE* %fp, i8* %fmt, double 1.87) +; CHECK-SMALL-PRINTF-NEXT: call i32 (%FILE*, i8*, ...) @__small_fprintf(%FILE* %fp, i8* getelementptr inbounds ([3 x i8], [3 x i8]* @percent_f, i32 0, i32 0), double 1.870000e+00) + ret void +; CHECK-SMALL-PRINTF-NEXT: ret void +} + define void @test_simplify5(%FILE* %fp) { ; CHECK-LABEL: @test_simplify5( %fmt = getelementptr [13 x i8], [13 x i8]* @hello_world, i32 0, i32 0 @@ -96,3 +109,12 @@ ret i32 %1 ; CHECK-NEXT: ret i32 %1 } + +define void @test_no_simplify4(%FILE* %fp) { +; CHECK-SMALL-PRINTF-LABEL: @test_no_simplify4( + %fmt = getelementptr [4 x i8], [4 x i8]* @percent_Lf, i32 0, i32 0 + call i32 (%FILE*, i8*, ...) @fprintf(%FILE* %fp, i8* %fmt, fp128 0xLC0000000000000003FFFDEB851EB851E) +; CHECK-SMALL-PRINTF-NEXT: call i32 (%FILE*, i8*, ...) @fprintf(%FILE* %fp, i8* getelementptr inbounds ([4 x i8], [4 x i8]* @percent_Lf, i32 0, i32 0), fp128 0xLC0000000000000003FFFDEB851EB851E) + ret void +; CHECK-SMALL-PRINTF-NEXT: ret void +} Index: test/Transforms/InstCombine/printf-1.ll =================================================================== --- test/Transforms/InstCombine/printf-1.ll +++ test/Transforms/InstCombine/printf-1.ll @@ -2,6 +2,7 @@ ; ; RUN: opt < %s -instcombine -S | FileCheck %s ; RUN: opt < %s -mtriple xcore-xmos-elf -instcombine -S | FileCheck %s -check-prefix=CHECK-IPRINTF +; RUN: opt < %s -mtriple wasm32-unknown-wasi -instcombine -S | FileCheck %s -check-prefix=CHECK-SMALL-PRINTF target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:128:128" @@ -12,6 +13,7 @@ @percent_c = constant [3 x i8] c"%c\00" @percent_d = constant [3 x i8] c"%d\00" @percent_f = constant [3 x i8] c"%f\00" +@percent_Lf = constant [4 x i8] c"%Lf\00" @percent_s = constant [4 x i8] c"%s\0A\00" @empty = constant [1 x i8] c"\00" ; CHECK: [[$STR:@[a-z0-9]+]] = private unnamed_addr constant [12 x i8] c"hello world\00", align 1 @@ -104,6 +106,17 @@ ; CHECK-IPRINTF-NEXT: ret void } +; Check printf(format, ...) -> __small_printf(format, ...) if no fp128. + +define void @test_simplify8() { +; CHECK-SMALL-PRINTF-LABEL: @test_simplify8( + %fmt = getelementptr [3 x i8], [3 x i8]* @percent_f, i32 0, i32 0 + call i32 (i8*, ...) @printf(i8* %fmt, double 1.87) +; CHECK-SMALL-PRINTF-NEXT: call i32 (i8*, ...) @__small_printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @percent_f, i32 0, i32 0), double 1.870000e+00) + ret void +; CHECK-SMALL-PRINTF-NEXT: ret void +} + define void @test_no_simplify1() { ; CHECK-IPRINTF-LABEL: @test_no_simplify1( %fmt = getelementptr [3 x i8], [3 x i8]* @percent_f, i32 0, i32 0 @@ -129,3 +142,12 @@ ret i32 %ret ; CHECK-NEXT: ret i32 %ret } + +define void @test_no_simplify4() { +; CHECK-SMALL-PRINTF-LABEL: @test_no_simplify4( + %fmt = getelementptr [4 x i8], [4 x i8]* @percent_Lf, i32 0, i32 0 + call i32 (i8*, ...) @printf(i8* %fmt, fp128 0xLC0000000000000003FFFDEB851EB851E) +; CHECK-SMALL-PRINTF-NEXT: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @percent_Lf, i32 0, i32 0), fp128 0xLC0000000000000003FFFDEB851EB851E) + ret void +; CHECK-SMALL-PRINTF-NEXT: ret void +} Index: test/Transforms/InstCombine/sprintf-1.ll =================================================================== --- test/Transforms/InstCombine/sprintf-1.ll +++ test/Transforms/InstCombine/sprintf-1.ll @@ -2,6 +2,7 @@ ; ; RUN: opt < %s -instcombine -S | FileCheck %s ; RUN: opt < %s -mtriple xcore-xmos-elf -instcombine -S | FileCheck %s -check-prefix=CHECK-IPRINTF +; RUN: opt < %s -mtriple wasm32-unknown-wasi -instcombine -S | FileCheck %s -check-prefix=CHECK-SMALL-PRINTF target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:128:128" @@ -12,6 +13,7 @@ @percent_c = constant [3 x i8] c"%c\00" @percent_d = constant [3 x i8] c"%d\00" @percent_f = constant [3 x i8] c"%f\00" +@percent_Lf = constant [4 x i8] c"%Lf\00" @percent_s = constant [3 x i8] c"%s\00" declare i32 @sprintf(i8*, i8*, ...) @@ -82,6 +84,17 @@ ; CHECK-IPRINTF-NEXT: ret void } +; Check sprintf(dst, format, ...) -> __small_sprintf(str, format, ...) if no fp128. + +define void @test_simplify7(i8* %dst) { +; CHECK-SMALL-PRINTF-LABEL: @test_simplify7( + %fmt = getelementptr [3 x i8], [3 x i8]* @percent_f, i32 0, i32 0 + call i32 (i8*, i8*, ...) @sprintf(i8* %dst, i8* %fmt, double 1.87) +; CHECK-SMALL-PRINTF-NEXT: call i32 (i8*, i8*, ...) @__small_sprintf(i8* %dst, i8* getelementptr inbounds ([3 x i8], [3 x i8]* @percent_f, i32 0, i32 0), double 1.870000e+00) + ret void +; CHECK-SMALL-PRINTF-NEXT: ret void +} + define void @test_no_simplify1(i8* %dst) { ; CHECK-IPRINTF-LABEL: @test_no_simplify1( %fmt = getelementptr [3 x i8], [3 x i8]* @percent_f, i32 0, i32 0 @@ -98,3 +111,12 @@ ret void ; CHECK-NEXT: ret void } + +define void @test_no_simplify3(i8* %dst) { +; CHECK-SMALL-PRINTF-LABEL: @test_no_simplify3( + %fmt = getelementptr [4 x i8], [4 x i8]* @percent_Lf, i32 0, i32 0 + call i32 (i8*, i8*, ...) @sprintf(i8* %dst, i8* %fmt, fp128 0xLC0000000000000003FFFDEB851EB851E) +; CHECK-SMALL-PRINTF-NEXT: call i32 (i8*, i8*, ...) @sprintf(i8* %dst, i8* getelementptr inbounds ([4 x i8], [4 x i8]* @percent_Lf, i32 0, i32 0), fp128 0xLC0000000000000003FFFDEB851EB851E) + ret void +; CHECK-SMALL-PRINTF-NEXT: ret void +} Index: unittests/Analysis/TargetLibraryInfoTest.cpp =================================================================== --- unittests/Analysis/TargetLibraryInfoTest.cpp +++ unittests/Analysis/TargetLibraryInfoTest.cpp @@ -493,6 +493,9 @@ "declare i32 @fiprintf(%struct*, i8*, ...)\n" "declare i32 @iprintf(i8*, ...)\n" "declare i32 @siprintf(i8*, i8*, ...)\n" + "declare i32 @__small_fprintf(%struct*, i8*, ...)\n" + "declare i32 @__small_printf(i8*, ...)\n" + "declare i32 @__small_sprintf(i8*, i8*, ...)\n" "declare i32 @htonl(i32)\n" "declare i16 @htons(i16)\n"