X-Git-Url: http://plrg.eecs.uci.edu/git/?p=oota-llvm.git;a=blobdiff_plain;f=lib%2FAnalysis%2FTargetLibraryInfo.cpp;h=845ca05a74fc254949122bd8cdfbfecff7e15cbf;hp=417f570bb6f68e294e47c6fc67cbfddb71f392fc;hb=36ee8db6826c69e3bfec4b80758ad3e83108156c;hpb=e2ffd02ad3f08a8b9f22ee24e68ffde0615d41d5 diff --git a/lib/Analysis/TargetLibraryInfo.cpp b/lib/Analysis/TargetLibraryInfo.cpp index 417f570bb6f..845ca05a74f 100644 --- a/lib/Analysis/TargetLibraryInfo.cpp +++ b/lib/Analysis/TargetLibraryInfo.cpp @@ -13,341 +13,22 @@ #include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/ADT/Triple.h" +#include "llvm/Support/CommandLine.h" using namespace llvm; -const char* TargetLibraryInfo::StandardNames[LibFunc::NumLibFuncs] = - { - "_IO_getc", - "_IO_putc", - "_ZdaPv", - "_ZdaPvRKSt9nothrow_t", - "_ZdaPvj", - "_ZdaPvm", - "_ZdlPv", - "_ZdlPvRKSt9nothrow_t", - "_ZdlPvj", - "_ZdlPvm", - "_Znaj", - "_ZnajRKSt9nothrow_t", - "_Znam", - "_ZnamRKSt9nothrow_t", - "_Znwj", - "_ZnwjRKSt9nothrow_t", - "_Znwm", - "_ZnwmRKSt9nothrow_t", - "__cospi", - "__cospif", - "__cxa_atexit", - "__cxa_guard_abort", - "__cxa_guard_acquire", - "__cxa_guard_release", - "__isoc99_scanf", - "__isoc99_sscanf", - "__memcpy_chk", - "__memmove_chk", - "__memset_chk", - "__sincospi_stret", - "__sincospif_stret", - "__sinpi", - "__sinpif", - "__sqrt_finite", - "__sqrtf_finite", - "__sqrtl_finite", - "__stpcpy_chk", - "__stpncpy_chk", - "__strcpy_chk", - "__strdup", - "__strncpy_chk", - "__strndup", - "__strtok_r", - "abs", - "access", - "acos", - "acosf", - "acosh", - "acoshf", - "acoshl", - "acosl", - "asin", - "asinf", - "asinh", - "asinhf", - "asinhl", - "asinl", - "atan", - "atan2", - "atan2f", - "atan2l", - "atanf", - "atanh", - "atanhf", - "atanhl", - "atanl", - "atof", - "atoi", - "atol", - "atoll", - "bcmp", - "bcopy", - "bzero", - "calloc", - "cbrt", - "cbrtf", - "cbrtl", - "ceil", - "ceilf", - "ceill", - "chmod", - "chown", - "clearerr", - "closedir", - "copysign", - "copysignf", - "copysignl", - "cos", - "cosf", - "cosh", - "coshf", - "coshl", - "cosl", - "ctermid", - "exp", - "exp10", - "exp10f", - "exp10l", - "exp2", - "exp2f", - "exp2l", - "expf", - "expl", - "expm1", - "expm1f", - "expm1l", - "fabs", - "fabsf", - "fabsl", - "fclose", - "fdopen", - "feof", - "ferror", - "fflush", - "ffs", - "ffsl", - "ffsll", - "fgetc", - "fgetpos", - "fgets", - "fileno", - "fiprintf", - "flockfile", - "floor", - "floorf", - "floorl", - "fmax", - "fmaxf", - "fmaxl", - "fmin", - "fminf", - "fminl", - "fmod", - "fmodf", - "fmodl", - "fopen", - "fopen64", - "fprintf", - "fputc", - "fputs", - "fread", - "free", - "frexp", - "frexpf", - "frexpl", - "fscanf", - "fseek", - "fseeko", - "fseeko64", - "fsetpos", - "fstat", - "fstat64", - "fstatvfs", - "fstatvfs64", - "ftell", - "ftello", - "ftello64", - "ftrylockfile", - "funlockfile", - "fwrite", - "getc", - "getc_unlocked", - "getchar", - "getenv", - "getitimer", - "getlogin_r", - "getpwnam", - "gets", - "gettimeofday", - "htonl", - "htons", - "iprintf", - "isascii", - "isdigit", - "labs", - "lchown", - "ldexp", - "ldexpf", - "ldexpl", - "llabs", - "log", - "log10", - "log10f", - "log10l", - "log1p", - "log1pf", - "log1pl", - "log2", - "log2f", - "log2l", - "logb", - "logbf", - "logbl", - "logf", - "logl", - "lstat", - "lstat64", - "malloc", - "memalign", - "memccpy", - "memchr", - "memcmp", - "memcpy", - "memmove", - "memrchr", - "memset", - "memset_pattern16", - "mkdir", - "mktime", - "modf", - "modff", - "modfl", - "nearbyint", - "nearbyintf", - "nearbyintl", - "ntohl", - "ntohs", - "open", - "open64", - "opendir", - "pclose", - "perror", - "popen", - "posix_memalign", - "pow", - "powf", - "powl", - "pread", - "printf", - "putc", - "putchar", - "puts", - "pwrite", - "qsort", - "read", - "readlink", - "realloc", - "reallocf", - "realpath", - "remove", - "rename", - "rewind", - "rint", - "rintf", - "rintl", - "rmdir", - "round", - "roundf", - "roundl", - "scanf", - "setbuf", - "setitimer", - "setvbuf", - "sin", - "sinf", - "sinh", - "sinhf", - "sinhl", - "sinl", - "siprintf", - "snprintf", - "sprintf", - "sqrt", - "sqrtf", - "sqrtl", - "sscanf", - "stat", - "stat64", - "statvfs", - "statvfs64", - "stpcpy", - "stpncpy", - "strcasecmp", - "strcat", - "strchr", - "strcmp", - "strcoll", - "strcpy", - "strcspn", - "strdup", - "strlen", - "strncasecmp", - "strncat", - "strncmp", - "strncpy", - "strndup", - "strnlen", - "strpbrk", - "strrchr", - "strspn", - "strstr", - "strtod", - "strtof", - "strtok", - "strtok_r", - "strtol", - "strtold", - "strtoll", - "strtoul", - "strtoull", - "strxfrm", - "system", - "tan", - "tanf", - "tanh", - "tanhf", - "tanhl", - "tanl", - "times", - "tmpfile", - "tmpfile64", - "toascii", - "trunc", - "truncf", - "truncl", - "uname", - "ungetc", - "unlink", - "unsetenv", - "utime", - "utimes", - "valloc", - "vfprintf", - "vfscanf", - "vprintf", - "vscanf", - "vsnprintf", - "vsprintf", - "vsscanf", - "write" - }; +static cl::opt ClVectorLibrary( + "vector-library", cl::Hidden, cl::desc("Vector functions library"), + cl::init(TargetLibraryInfoImpl::NoLibrary), + cl::values(clEnumValN(TargetLibraryInfoImpl::NoLibrary, "none", + "No vector functions library"), + clEnumValN(TargetLibraryInfoImpl::Accelerate, "Accelerate", + "Accelerate framework"), + clEnumValEnd)); + +const char *const TargetLibraryInfoImpl::StandardNames[LibFunc::NumLibFuncs] = { +#define TLI_DEFINE_STRING +#include "llvm/Analysis/TargetLibraryInfo.def" +}; static bool hasSinCosPiStret(const Triple &T) { // Only Darwin variants have _stret versions of combined trig functions. @@ -370,20 +51,22 @@ static bool hasSinCosPiStret(const Triple &T) { /// initialize - Initialize the set of available library functions based on the /// specified target triple. This should be carefully written so that a missing /// target triple gets a sane set of defaults. -static void initialize(TargetLibraryInfo &TLI, const Triple &T, - const char **StandardNames) { +static void initialize(TargetLibraryInfoImpl &TLI, const Triple &T, + const char *const *StandardNames) { #ifndef NDEBUG // Verify that the StandardNames array is in alphabetical order. for (unsigned F = 1; F < LibFunc::NumLibFuncs; ++F) { if (strcmp(StandardNames[F-1], StandardNames[F]) >= 0) - llvm_unreachable("TargetLibraryInfo function names must be sorted"); + llvm_unreachable("TargetLibraryInfoImpl function names must be sorted"); } #endif // !NDEBUG // There are no library implementations of mempcy and memset for AMD gpus and // these can be difficult to lower in the backend. if (T.getArch() == Triple::r600 || - T.getArch() == Triple::amdgcn) { + T.getArch() == Triple::amdgcn || + T.getArch() == Triple::wasm32 || + T.getArch() == Triple::wasm64) { TLI.setUnavailable(LibFunc::memcpy); TLI.setUnavailable(LibFunc::memset); TLI.setUnavailable(LibFunc::memset_pattern16); @@ -391,13 +74,14 @@ static void initialize(TargetLibraryInfo &TLI, const Triple &T, } // memset_pattern16 is only available on iOS 3.0 and Mac OS X 10.5 and later. + // All versions of watchOS support it. if (T.isMacOSX()) { if (T.isMacOSXVersionLT(10, 5)) TLI.setUnavailable(LibFunc::memset_pattern16); } else if (T.isiOS()) { if (T.isOSVersionLT(3, 0)) TLI.setUnavailable(LibFunc::memset_pattern16); - } else { + } else if (!T.isWatchOS()) { TLI.setUnavailable(LibFunc::memset_pattern16); } @@ -605,8 +289,13 @@ static void initialize(TargetLibraryInfo &TLI, const Triple &T, } break; case Triple::IOS: + case Triple::TvOS: + case Triple::WatchOS: TLI.setUnavailable(LibFunc::exp10l); - if (T.isOSVersionLT(7, 0)) { + if (!T.isWatchOS() && (T.isOSVersionLT(7, 0) || + (T.isOSVersionLT(9, 0) && + (T.getArch() == Triple::x86 || + T.getArch() == Triple::x86_64)))) { TLI.setUnavailable(LibFunc::exp10); TLI.setUnavailable(LibFunc::exp10f); } else { @@ -630,12 +319,14 @@ static void initialize(TargetLibraryInfo &TLI, const Triple &T, // ffsl is available on at least Darwin, Mac OS X, iOS, FreeBSD, and // Linux (GLIBC): // http://developer.apple.com/library/mac/#documentation/Darwin/Reference/ManPages/man3/ffsl.3.html - // http://svn.freebsd.org/base/user/eri/pf45/head/lib/libc/string/ffsl.c + // http://svn.freebsd.org/base/head/lib/libc/string/ffsl.c // http://www.gnu.org/software/gnulib/manual/html_node/ffsl.html switch (T.getOS()) { case Triple::Darwin: case Triple::MacOSX: case Triple::IOS: + case Triple::TvOS: + case Triple::WatchOS: case Triple::FreeBSD: case Triple::Linux: break; @@ -644,9 +335,14 @@ static void initialize(TargetLibraryInfo &TLI, const Triple &T, } // ffsll is available on at least FreeBSD and Linux (GLIBC): - // http://svn.freebsd.org/base/user/eri/pf45/head/lib/libc/string/ffsll.c + // http://svn.freebsd.org/base/head/lib/libc/string/ffsll.c // http://www.gnu.org/software/gnulib/manual/html_node/ffsll.html switch (T.getOS()) { + case Triple::Darwin: + case Triple::MacOSX: + case Triple::IOS: + case Triple::TvOS: + case Triple::WatchOS: case Triple::FreeBSD: case Triple::Linux: break; @@ -654,6 +350,16 @@ static void initialize(TargetLibraryInfo &TLI, const Triple &T, TLI.setUnavailable(LibFunc::ffsll); } + // The following functions are available on at least FreeBSD: + // http://svn.freebsd.org/base/head/lib/libc/string/fls.c + // http://svn.freebsd.org/base/head/lib/libc/string/flsl.c + // http://svn.freebsd.org/base/head/lib/libc/string/flsll.c + if (!T.isOSFreeBSD()) { + TLI.setUnavailable(LibFunc::fls); + TLI.setUnavailable(LibFunc::flsl); + TLI.setUnavailable(LibFunc::flsll); + } + // The following functions are available on at least Linux: if (!T.isOSLinux()) { TLI.setUnavailable(LibFunc::dunder_strdup); @@ -674,80 +380,76 @@ static void initialize(TargetLibraryInfo &TLI, const Triple &T, TLI.setUnavailable(LibFunc::statvfs64); TLI.setUnavailable(LibFunc::tmpfile64); } + + TLI.addVectorizableFunctionsFromVecLib(ClVectorLibrary); } -TargetLibraryInfo::TargetLibraryInfo() { +TargetLibraryInfoImpl::TargetLibraryInfoImpl() { // Default to everything being available. memset(AvailableArray, -1, sizeof(AvailableArray)); initialize(*this, Triple(), StandardNames); } -TargetLibraryInfo::TargetLibraryInfo(const Triple &T) { +TargetLibraryInfoImpl::TargetLibraryInfoImpl(const Triple &T) { // Default to everything being available. memset(AvailableArray, -1, sizeof(AvailableArray)); initialize(*this, T, StandardNames); } -TargetLibraryInfo::TargetLibraryInfo(const TargetLibraryInfo &TLI) +TargetLibraryInfoImpl::TargetLibraryInfoImpl(const TargetLibraryInfoImpl &TLI) : CustomNames(TLI.CustomNames) { memcpy(AvailableArray, TLI.AvailableArray, sizeof(AvailableArray)); + VectorDescs = TLI.VectorDescs; + ScalarDescs = TLI.ScalarDescs; } -TargetLibraryInfo::TargetLibraryInfo(TargetLibraryInfo &&TLI) +TargetLibraryInfoImpl::TargetLibraryInfoImpl(TargetLibraryInfoImpl &&TLI) : CustomNames(std::move(TLI.CustomNames)) { std::move(std::begin(TLI.AvailableArray), std::end(TLI.AvailableArray), AvailableArray); + VectorDescs = TLI.VectorDescs; + ScalarDescs = TLI.ScalarDescs; } -TargetLibraryInfo &TargetLibraryInfo::operator=(const TargetLibraryInfo &TLI) { +TargetLibraryInfoImpl &TargetLibraryInfoImpl::operator=(const TargetLibraryInfoImpl &TLI) { CustomNames = TLI.CustomNames; memcpy(AvailableArray, TLI.AvailableArray, sizeof(AvailableArray)); return *this; } -TargetLibraryInfo &TargetLibraryInfo::operator=(TargetLibraryInfo &&TLI) { +TargetLibraryInfoImpl &TargetLibraryInfoImpl::operator=(TargetLibraryInfoImpl &&TLI) { CustomNames = std::move(TLI.CustomNames); std::move(std::begin(TLI.AvailableArray), std::end(TLI.AvailableArray), AvailableArray); return *this; } -namespace { -struct StringComparator { - /// Compare two strings and return true if LHS is lexicographically less than - /// RHS. Requires that RHS doesn't contain any zero bytes. - bool operator()(const char *LHS, StringRef RHS) const { - // Compare prefixes with strncmp. If prefixes match we know that LHS is - // greater or equal to RHS as RHS can't contain any '\0'. - return std::strncmp(LHS, RHS.data(), RHS.size()) < 0; - } +static StringRef sanitizeFunctionName(StringRef funcName) { + // Filter out empty names and names containing null bytes, those can't be in + // our table. + if (funcName.empty() || funcName.find('\0') != StringRef::npos) + return StringRef(); - // Provided for compatibility with MSVC's debug mode. - bool operator()(StringRef LHS, const char *RHS) const { return LHS < RHS; } - bool operator()(StringRef LHS, StringRef RHS) const { return LHS < RHS; } - bool operator()(const char *LHS, const char *RHS) const { - return std::strcmp(LHS, RHS) < 0; - } -}; + // Check for \01 prefix that is used to mangle __asm declarations and + // strip it if present. + return GlobalValue::getRealLinkageName(funcName); } -bool TargetLibraryInfo::getLibFunc(StringRef funcName, +bool TargetLibraryInfoImpl::getLibFunc(StringRef funcName, LibFunc::Func &F) const { - const char **Start = &StandardNames[0]; - const char **End = &StandardNames[LibFunc::NumLibFuncs]; + const char *const *Start = &StandardNames[0]; + const char *const *End = &StandardNames[LibFunc::NumLibFuncs]; - // Filter out empty names and names containing null bytes, those can't be in - // our table. - if (funcName.empty() || funcName.find('\0') != StringRef::npos) + funcName = sanitizeFunctionName(funcName); + if (funcName.empty()) return false; - // Check for \01 prefix that is used to mangle __asm declarations and - // strip it if present. - if (funcName.front() == '\01') - funcName = funcName.substr(1); - const char **I = std::lower_bound(Start, End, funcName, StringComparator()); + const char *const *I = std::lower_bound( + Start, End, funcName, [](const char *LHS, StringRef RHS) { + return std::strncmp(LHS, RHS.data(), RHS.size()) < 0; + }); if (I != End && *I == funcName) { F = (LibFunc::Func)(I - Start); return true; @@ -755,23 +457,164 @@ bool TargetLibraryInfo::getLibFunc(StringRef funcName, return false; } -void TargetLibraryInfo::disableAllFunctions() { +void TargetLibraryInfoImpl::disableAllFunctions() { memset(AvailableArray, 0, sizeof(AvailableArray)); } +static bool compareByScalarFnName(const VecDesc &LHS, const VecDesc &RHS) { + return std::strncmp(LHS.ScalarFnName, RHS.ScalarFnName, + std::strlen(RHS.ScalarFnName)) < 0; +} + +static bool compareByVectorFnName(const VecDesc &LHS, const VecDesc &RHS) { + return std::strncmp(LHS.VectorFnName, RHS.VectorFnName, + std::strlen(RHS.VectorFnName)) < 0; +} + +static bool compareWithScalarFnName(const VecDesc &LHS, StringRef S) { + return std::strncmp(LHS.ScalarFnName, S.data(), S.size()) < 0; +} + +static bool compareWithVectorFnName(const VecDesc &LHS, StringRef S) { + return std::strncmp(LHS.VectorFnName, S.data(), S.size()) < 0; +} + +void TargetLibraryInfoImpl::addVectorizableFunctions(ArrayRef Fns) { + VectorDescs.insert(VectorDescs.end(), Fns.begin(), Fns.end()); + std::sort(VectorDescs.begin(), VectorDescs.end(), compareByScalarFnName); + + ScalarDescs.insert(ScalarDescs.end(), Fns.begin(), Fns.end()); + std::sort(ScalarDescs.begin(), ScalarDescs.end(), compareByVectorFnName); +} + +void TargetLibraryInfoImpl::addVectorizableFunctionsFromVecLib( + enum VectorLibrary VecLib) { + switch (VecLib) { + case Accelerate: { + const VecDesc VecFuncs[] = { + // Floating-Point Arithmetic and Auxiliary Functions + {"ceilf", "vceilf", 4}, + {"fabsf", "vfabsf", 4}, + {"llvm.fabs.f32", "vfabsf", 4}, + {"floorf", "vfloorf", 4}, + {"sqrtf", "vsqrtf", 4}, + {"llvm.sqrt.f32", "vsqrtf", 4}, + + // Exponential and Logarithmic Functions + {"expf", "vexpf", 4}, + {"llvm.exp.f32", "vexpf", 4}, + {"expm1f", "vexpm1f", 4}, + {"logf", "vlogf", 4}, + {"llvm.log.f32", "vlogf", 4}, + {"log1pf", "vlog1pf", 4}, + {"log10f", "vlog10f", 4}, + {"llvm.log10.f32", "vlog10f", 4}, + {"logbf", "vlogbf", 4}, + + // Trigonometric Functions + {"sinf", "vsinf", 4}, + {"llvm.sin.f32", "vsinf", 4}, + {"cosf", "vcosf", 4}, + {"llvm.cos.f32", "vcosf", 4}, + {"tanf", "vtanf", 4}, + {"asinf", "vasinf", 4}, + {"acosf", "vacosf", 4}, + {"atanf", "vatanf", 4}, + + // Hyperbolic Functions + {"sinhf", "vsinhf", 4}, + {"coshf", "vcoshf", 4}, + {"tanhf", "vtanhf", 4}, + {"asinhf", "vasinhf", 4}, + {"acoshf", "vacoshf", 4}, + {"atanhf", "vatanhf", 4}, + }; + addVectorizableFunctions(VecFuncs); + break; + } + case NoLibrary: + break; + } +} + +bool TargetLibraryInfoImpl::isFunctionVectorizable(StringRef funcName) const { + funcName = sanitizeFunctionName(funcName); + if (funcName.empty()) + return false; + + std::vector::const_iterator I = std::lower_bound( + VectorDescs.begin(), VectorDescs.end(), funcName, + compareWithScalarFnName); + return I != VectorDescs.end() && StringRef(I->ScalarFnName) == funcName; +} + +StringRef TargetLibraryInfoImpl::getVectorizedFunction(StringRef F, + unsigned VF) const { + F = sanitizeFunctionName(F); + if (F.empty()) + return F; + std::vector::const_iterator I = std::lower_bound( + VectorDescs.begin(), VectorDescs.end(), F, compareWithScalarFnName); + while (I != VectorDescs.end() && StringRef(I->ScalarFnName) == F) { + if (I->VectorizationFactor == VF) + return I->VectorFnName; + ++I; + } + return StringRef(); +} + +StringRef TargetLibraryInfoImpl::getScalarizedFunction(StringRef F, + unsigned &VF) const { + F = sanitizeFunctionName(F); + if (F.empty()) + return F; + + std::vector::const_iterator I = std::lower_bound( + ScalarDescs.begin(), ScalarDescs.end(), F, compareWithVectorFnName); + if (I == VectorDescs.end() || StringRef(I->VectorFnName) != F) + return StringRef(); + VF = I->VectorizationFactor; + return I->ScalarFnName; +} + +TargetLibraryInfo TargetLibraryAnalysis::run(Module &M) { + if (PresetInfoImpl) + return TargetLibraryInfo(*PresetInfoImpl); + + return TargetLibraryInfo(lookupInfoImpl(Triple(M.getTargetTriple()))); +} + +TargetLibraryInfo TargetLibraryAnalysis::run(Function &F) { + if (PresetInfoImpl) + return TargetLibraryInfo(*PresetInfoImpl); + + return TargetLibraryInfo( + lookupInfoImpl(Triple(F.getParent()->getTargetTriple()))); +} + +TargetLibraryInfoImpl &TargetLibraryAnalysis::lookupInfoImpl(Triple T) { + std::unique_ptr &Impl = + Impls[T.normalize()]; + if (!Impl) + Impl.reset(new TargetLibraryInfoImpl(T)); + + return *Impl; +} + + TargetLibraryInfoWrapperPass::TargetLibraryInfoWrapperPass() - : ImmutablePass(ID), TLI() { + : ImmutablePass(ID), TLIImpl(), TLI(TLIImpl) { initializeTargetLibraryInfoWrapperPassPass(*PassRegistry::getPassRegistry()); } TargetLibraryInfoWrapperPass::TargetLibraryInfoWrapperPass(const Triple &T) - : ImmutablePass(ID), TLI(T) { + : ImmutablePass(ID), TLIImpl(T), TLI(TLIImpl) { initializeTargetLibraryInfoWrapperPassPass(*PassRegistry::getPassRegistry()); } TargetLibraryInfoWrapperPass::TargetLibraryInfoWrapperPass( - const TargetLibraryInfo &TLI) - : ImmutablePass(ID), TLI(TLI) { + const TargetLibraryInfoImpl &TLIImpl) + : ImmutablePass(ID), TLIImpl(TLIImpl), TLI(this->TLIImpl) { initializeTargetLibraryInfoWrapperPassPass(*PassRegistry::getPassRegistry()); }