From b4f9991f383e1a864eb6d994400394f489060b27 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 3 Apr 2019 01:08:35 +0000 Subject: [PATCH] [WebAssembly] Add Emscripten OS definition + small_printf The Emscripten OS provides a definition of __EMSCRIPTEN__, and also that it supports iprintf optimizations. Also define small_printf optimizations, which is a printf with float support but not long double (which in wasm can be useful since long doubles are 128 bit and force linking of float128 emulation code). This part is based on sunfish's https://reviews.llvm.org/D57620 (which can't land yet since the WASI integration isn't ready yet). Differential Revision: https://reviews.llvm.org/D60167 llvm-svn: 357552 --- clang/lib/Basic/Targets.cpp | 4 ++ clang/lib/Basic/Targets/OSTargets.h | 15 ++++++++ llvm/include/llvm/ADT/Triple.h | 8 +++- llvm/include/llvm/Analysis/TargetLibraryInfo.def | 9 +++++ llvm/lib/Analysis/TargetLibraryInfo.cpp | 15 +++++++- llvm/lib/Support/Triple.cpp | 2 + llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp | 48 ++++++++++++++++++++++++ 7 files changed, 98 insertions(+), 3 deletions(-) diff --git a/clang/lib/Basic/Targets.cpp b/clang/lib/Basic/Targets.cpp index e6fcf93..e9af371 100644 --- a/clang/lib/Basic/Targets.cpp +++ b/clang/lib/Basic/Targets.cpp @@ -576,6 +576,8 @@ TargetInfo *AllocateTarget(const llvm::Triple &Triple, switch (Triple.getOS()) { case llvm::Triple::WASI: return new WASITargetInfo(Triple, Opts); + case llvm::Triple::Emscripten: + return new EmscriptenTargetInfo(Triple, Opts); case llvm::Triple::UnknownOS: return new WebAssemblyOSTargetInfo(Triple, Opts); default: @@ -589,6 +591,8 @@ TargetInfo *AllocateTarget(const llvm::Triple &Triple, switch (Triple.getOS()) { case llvm::Triple::WASI: return new WASITargetInfo(Triple, Opts); + case llvm::Triple::Emscripten: + return new EmscriptenTargetInfo(Triple, Opts); case llvm::Triple::UnknownOS: return new WebAssemblyOSTargetInfo(Triple, Opts); default: diff --git a/clang/lib/Basic/Targets/OSTargets.h b/clang/lib/Basic/Targets/OSTargets.h index e8715dc..a0e8061 100644 --- a/clang/lib/Basic/Targets/OSTargets.h +++ b/clang/lib/Basic/Targets/OSTargets.h @@ -848,6 +848,21 @@ public: : WebAssemblyOSTargetInfo(Triple, Opts) {} }; +// Emscripten target +template +class LLVM_LIBRARY_VISIBILITY EmscriptenTargetInfo + : public WebAssemblyOSTargetInfo { + void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, + MacroBuilder &Builder) const final { + WebAssemblyOSTargetInfo::getOSDefines(Opts, Triple, Builder); + Builder.defineMacro("__EMSCRIPTEN__"); + } + +public: + explicit EmscriptenTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : WebAssemblyOSTargetInfo(Triple, Opts) {} +}; + } // namespace targets } // namespace clang #endif // LLVM_CLANG_LIB_BASIC_TARGETS_OSTARGETS_H diff --git a/llvm/include/llvm/ADT/Triple.h b/llvm/include/llvm/ADT/Triple.h index 25494c5..f2e7a2a 100644 --- a/llvm/include/llvm/ADT/Triple.h +++ b/llvm/include/llvm/ADT/Triple.h @@ -186,7 +186,8 @@ public: HermitCore, // HermitCore Unikernel/Multikernel Hurd, // GNU/Hurd WASI, // Experimental WebAssembly OS - LastOSType = WASI + Emscripten, + LastOSType = Emscripten }; enum EnvironmentType { UnknownEnvironment, @@ -592,6 +593,11 @@ public: return getOS() == Triple::WASI; } + /// Tests whether the OS is Emscripten. + bool isOSEmscripten() const { + return getOS() == Triple::Emscripten; + } + /// Tests whether the OS uses glibc. bool isOSGlibc() const { return (getOS() == Triple::Linux || getOS() == Triple::KFreeBSD || diff --git a/llvm/include/llvm/Analysis/TargetLibraryInfo.def b/llvm/include/llvm/Analysis/TargetLibraryInfo.def index f73c69e..2e92d1d 100644 --- a/llvm/include/llvm/Analysis/TargetLibraryInfo.def +++ b/llvm/include/llvm/Analysis/TargetLibraryInfo.def @@ -372,6 +372,15 @@ TLI_DEFINE_STRING_INTERNAL("__sinpi") /// 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") diff --git a/llvm/lib/Analysis/TargetLibraryInfo.cpp b/llvm/lib/Analysis/TargetLibraryInfo.cpp index 50a05a8..b74e1ce 100644 --- a/llvm/lib/Analysis/TargetLibraryInfo.cpp +++ b/llvm/lib/Analysis/TargetLibraryInfo.cpp @@ -165,13 +165,21 @@ static void initialize(TargetLibraryInfoImpl &TLI, const Triple &T, 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 Emscripten. + if (T.getArch() != Triple::xcore && T.getArch() != Triple::tce && + T.getOS() != Triple::Emscripten) { TLI.setUnavailable(LibFunc_iprintf); TLI.setUnavailable(LibFunc_siprintf); TLI.setUnavailable(LibFunc_fiprintf); } + // __small_printf and friends are only available on Emscripten. + if (T.getOS() != Triple::Emscripten) { + TLI.setUnavailable(LibFunc_small_printf); + TLI.setUnavailable(LibFunc_small_sprintf); + TLI.setUnavailable(LibFunc_small_fprintf); + } + if (T.isOSWindows() && !T.isOSCygMing()) { // XXX: The earliest documentation available at the moment is for VS2015/VC19: // https://docs.microsoft.com/en-us/cpp/c-runtime-library/floating-point-support?view=vs-2015 @@ -771,6 +779,7 @@ bool TargetLibraryInfoImpl::isValidProtoForLibFunc(const FunctionType &FTy, 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() && @@ -868,6 +877,7 @@ bool TargetLibraryInfoImpl::isValidProtoForLibFunc(const FunctionType &FTy, case LibFunc_getenv: case LibFunc_getpwnam: case LibFunc_iprintf: + case LibFunc_small_printf: case LibFunc_pclose: case LibFunc_perror: case LibFunc_printf: @@ -947,6 +957,7 @@ bool TargetLibraryInfoImpl::isValidProtoForLibFunc(const FunctionType &FTy, 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() && diff --git a/llvm/lib/Support/Triple.cpp b/llvm/lib/Support/Triple.cpp index 83ce4f0..a5a25d2 100644 --- a/llvm/lib/Support/Triple.cpp +++ b/llvm/lib/Support/Triple.cpp @@ -208,6 +208,7 @@ StringRef Triple::getOSTypeName(OSType Kind) { case HermitCore: return "hermit"; case Hurd: return "hurd"; case WASI: return "wasi"; + case Emscripten: return "emscripten"; } llvm_unreachable("Invalid OSType"); @@ -506,6 +507,7 @@ static Triple::OSType parseOS(StringRef OSName) { .StartsWith("hermit", Triple::HermitCore) .StartsWith("hurd", Triple::Hurd) .StartsWith("wasi", Triple::WASI) + .StartsWith("emscripten", Triple::Emscripten) .Default(Triple::UnknownOS); } diff --git a/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp b/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp index 3920736..0af79f4 100644 --- a/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp +++ b/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp @@ -104,6 +104,12 @@ static bool callHasFloatingPointArgument(const CallInst *CI) { }); } +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 @@ -2051,6 +2057,20 @@ Value *LibCallSimplifier::optimizePrintF(CallInst *CI, IRBuilder<> &B) { 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; } @@ -2131,6 +2151,20 @@ Value *LibCallSimplifier::optimizeSPrintF(CallInst *CI, IRBuilder<> &B) { 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; } @@ -2288,6 +2322,20 @@ Value *LibCallSimplifier::optimizeFPrintF(CallInst *CI, IRBuilder<> &B) { 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; } -- 2.7.4