Index: lib/Analysis/TargetLibraryInfo.cpp =================================================================== --- lib/Analysis/TargetLibraryInfo.cpp +++ lib/Analysis/TargetLibraryInfo.cpp @@ -638,6 +638,7 @@ case LibFunc::sscanf: case LibFunc::stat: case LibFunc::statvfs: + case LibFunc::siprintf: case LibFunc::sprintf: return (NumParams >= 2 && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(1)->isPointerTy()); @@ -697,6 +698,7 @@ case LibFunc::memalign: return (FTy.getReturnType()->isPointerTy()); case LibFunc::realloc: + case LibFunc::reallocf: return (NumParams == 2 && FTy.getParamType(0)->isPointerTy() && FTy.getReturnType()->isPointerTy()); case LibFunc::read: @@ -730,6 +732,7 @@ case LibFunc::ferror: case LibFunc::getenv: case LibFunc::getpwnam: + case LibFunc::iprintf: case LibFunc::pclose: case LibFunc::perror: case LibFunc::printf: @@ -740,6 +743,8 @@ case LibFunc::unsetenv: return (NumParams == 1 && FTy.getParamType(0)->isPointerTy()); + case LibFunc::ZdaPv: + case LibFunc::ZdlPv: case LibFunc::chmod: case LibFunc::chown: case LibFunc::clearerr: @@ -766,10 +771,28 @@ case LibFunc::getlogin_r: case LibFunc::mkdir: case LibFunc::mktime: + case LibFunc::msvc_delete_array_ptr32: + case LibFunc::msvc_delete_array_ptr64: + case LibFunc::msvc_delete_ptr32: + case LibFunc::msvc_delete_ptr64: case LibFunc::times: return (NumParams != 0 && FTy.getParamType(0)->isPointerTy()); + case LibFunc::ZdaPvRKSt9nothrow_t: + case LibFunc::ZdaPvj: + case LibFunc::ZdaPvm: + case LibFunc::ZdlPvRKSt9nothrow_t: + case LibFunc::ZdlPvj: + case LibFunc::ZdlPvm: case LibFunc::access: + case LibFunc::msvc_delete_array_ptr32_int: + case LibFunc::msvc_delete_array_ptr32_nothrow: + case LibFunc::msvc_delete_array_ptr64_longlong: + case LibFunc::msvc_delete_array_ptr64_nothrow: + case LibFunc::msvc_delete_ptr32_int: + case LibFunc::msvc_delete_ptr32_nothrow: + case LibFunc::msvc_delete_ptr64_longlong: + case LibFunc::msvc_delete_ptr64_nothrow: return (NumParams == 2 && FTy.getParamType(0)->isPointerTy()); case LibFunc::fopen: return (NumParams == 2 && FTy.getReturnType()->isPointerTy() && @@ -801,6 +824,7 @@ return (NumParams >= 2 && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(1)->isPointerTy()); case LibFunc::fscanf: + case LibFunc::fiprintf: case LibFunc::fprintf: return (NumParams >= 2 && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(1)->isPointerTy()); @@ -904,7 +928,17 @@ case LibFunc::msvc_new_longlong: // new(unsigned long long); case LibFunc::msvc_new_array_int: // new[](unsigned int); case LibFunc::msvc_new_array_longlong: // new[](unsigned long long); - return (NumParams == 1); + return (NumParams == 1 && isa(FTy.getReturnType())); + + case LibFunc::ZnwjRKSt9nothrow_t: + case LibFunc::ZnwmRKSt9nothrow_t: + case LibFunc::ZnajRKSt9nothrow_t: + case LibFunc::ZnamRKSt9nothrow_t: + case LibFunc::msvc_new_int_nothrow: + case LibFunc::msvc_new_longlong_nothrow: + case LibFunc::msvc_new_array_int_nothrow: + case LibFunc::msvc_new_array_longlong_nothrow: + return (NumParams == 2 && isa(FTy.getReturnType())); case LibFunc::memset_pattern16: return (!FTy.isVarArg() && NumParams == 3 && @@ -912,22 +946,57 @@ isa(FTy.getParamType(1)) && isa(FTy.getParamType(2))); - // int __nvvm_reflect(const char *); + case LibFunc::cxa_guard_abort: + case LibFunc::cxa_guard_acquire: + case LibFunc::cxa_guard_release: case LibFunc::nvvm_reflect: return (NumParams == 1 && isa(FTy.getParamType(0))); + case LibFunc::acos: + case LibFunc::acosf: + case LibFunc::acosh: + case LibFunc::acoshf: + case LibFunc::acoshl: + case LibFunc::acosl: + case LibFunc::asin: + case LibFunc::asinf: + case LibFunc::asinh: + case LibFunc::asinhf: + case LibFunc::asinhl: + case LibFunc::asinl: + case LibFunc::atan2: + case LibFunc::atan2f: + case LibFunc::atan2l: + case LibFunc::atan: + case LibFunc::atanf: + case LibFunc::atanh: + case LibFunc::atanhf: + case LibFunc::atanhl: + case LibFunc::atanl: + case LibFunc::cbrt: + case LibFunc::cbrtf: + case LibFunc::cbrtl: case LibFunc::ceil: case LibFunc::ceilf: case LibFunc::ceill: case LibFunc::cos: case LibFunc::cosf: + case LibFunc::cosh: + case LibFunc::coshf: + case LibFunc::coshl: case LibFunc::cosl: + case LibFunc::exp10: + case LibFunc::exp10f: + case LibFunc::exp10l: case LibFunc::exp2: case LibFunc::exp2f: case LibFunc::exp2l: case LibFunc::exp: case LibFunc::expf: case LibFunc::expl: + case LibFunc::expm1: + case LibFunc::expm1f: + case LibFunc::expm1l: case LibFunc::fabs: case LibFunc::fabsf: case LibFunc::fabsl: @@ -937,10 +1006,16 @@ case LibFunc::log10: case LibFunc::log10f: case LibFunc::log10l: + case LibFunc::log1p: + case LibFunc::log1pf: + case LibFunc::log1pl: case LibFunc::log2: case LibFunc::log2f: case LibFunc::log2l: case LibFunc::log: + case LibFunc::logb: + case LibFunc::logbf: + case LibFunc::logbl: case LibFunc::logf: case LibFunc::logl: case LibFunc::nearbyint: @@ -953,13 +1028,24 @@ case LibFunc::roundf: case LibFunc::roundl: case LibFunc::sin: + case LibFunc::sincospi_stret: + case LibFunc::sincospif_stret: case LibFunc::sinf: + case LibFunc::sinh: + case LibFunc::sinhf: + case LibFunc::sinhl: case LibFunc::sinl: case LibFunc::sqrt: + case LibFunc::sqrt_finite: case LibFunc::sqrtf: + case LibFunc::sqrtf_finite: case LibFunc::sqrtl: + case LibFunc::sqrtl_finite: case LibFunc::tan: case LibFunc::tanf: + case LibFunc::tanh: + case LibFunc::tanhf: + case LibFunc::tanhl: case LibFunc::tanl: case LibFunc::trunc: case LibFunc::truncf: @@ -973,6 +1059,9 @@ case LibFunc::fmax: case LibFunc::fmaxf: case LibFunc::fmaxl: + case LibFunc::fmod: + case LibFunc::fmodf: + case LibFunc::fmodl: case LibFunc::copysign: case LibFunc::copysignf: case LibFunc::copysignl: @@ -983,6 +1072,13 @@ FTy.getReturnType() == FTy.getParamType(0) && FTy.getReturnType() == FTy.getParamType(1)); + case LibFunc::ldexp: + case LibFunc::ldexpf: + case LibFunc::ldexpl: + return (NumParams == 2 && FTy.getReturnType()->isFloatingPointTy() && + FTy.getReturnType() == FTy.getParamType(0) && + FTy.getParamType(1)->isIntegerTy(32)); + case LibFunc::ffs: case LibFunc::ffsl: case LibFunc::ffsll: @@ -995,6 +1091,7 @@ case LibFunc::isdigit: case LibFunc::isascii: case LibFunc::toascii: + case LibFunc::putchar: return (NumParams == 1 && FTy.getReturnType()->isIntegerTy(32) && FTy.getReturnType() == FTy.getParamType(0)); @@ -1020,11 +1117,20 @@ return (NumParams == 1 && FTy.getReturnType()->isFloatTy() && FTy.getReturnType() == FTy.getParamType(0)); - default: - // Assume the other functions are correct. - // FIXME: It'd be really nice to cover them all. - return true; + case LibFunc::strnlen: + return (NumParams == 2 && FTy.getReturnType() == FTy.getParamType(1) && + FTy.getParamType(0) == PCharTy && + FTy.getParamType(1)->isIntegerTy()); + + case LibFunc::posix_memalign: + return (NumParams == 3 && FTy.getReturnType()->isIntegerTy() && + FTy.getParamType(0)->isPointerTy() && + FTy.getParamType(1) == SizeTTy && FTy.getParamType(2) == SizeTTy); + + case LibFunc::NumLibFuncs: + llvm_unreachable("Invalid sentinel libfunc value"); } + } bool TargetLibraryInfoImpl::getLibFunc(const Function &FDecl, Index: unittests/Analysis/CMakeLists.txt =================================================================== --- unittests/Analysis/CMakeLists.txt +++ unittests/Analysis/CMakeLists.txt @@ -16,6 +16,7 @@ LoopPassManagerTest.cpp ScalarEvolutionTest.cpp TBAATest.cpp + TargetLibraryInfoTest.cpp UnrollAnalyzer.cpp ValueTrackingTest.cpp ) Index: unittests/Analysis/TargetLibraryInfoTest.cpp =================================================================== --- /dev/null +++ unittests/Analysis/TargetLibraryInfoTest.cpp @@ -0,0 +1,66 @@ +//===--- TargetLibraryInfoTest.cpp - TLI/LibFunc unit tests ---------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Analysis/TargetLibraryInfo.h" +#include "llvm/AsmParser/Parser.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/LegacyPassManager.h" +#include "llvm/IR/Module.h" +#include "llvm/Support/SourceMgr.h" +#include "gtest/gtest.h" + +using namespace llvm; + +namespace { + +class TargetLibraryInfoTest : public testing::Test { +protected: + LLVMContext Context; + TargetLibraryInfoImpl TLII; + TargetLibraryInfo TLI; + + std::unique_ptr M; + + TargetLibraryInfoTest() : TLI(TLII) {} + + void parseAssembly(const char *Assembly) { + SMDiagnostic Error; + M = parseAssemblyString(Assembly, Error, Context); + + std::string errMsg; + raw_string_ostream os(errMsg); + Error.print("", os); + + if (!M) + report_fatal_error(os.str()); + } + + ::testing::AssertionResult isLibFunc(const Function &FDecl) { + LibFunc::Func F; + if (TLI.getLibFunc(FDecl, F)) + return ::testing::AssertionSuccess() << FDecl.getName() << " is LibFunc"; + return ::testing::AssertionFailure() << FDecl.getName() << " unknown"; + } +}; + +} // end anonymous namespace + +// Check that we don't accept egregiously incorrect prototypes. +TEST_F(TargetLibraryInfoTest, InvalidProto) { + parseAssembly("%foo = type { %foo }\n"); + + auto *StructTy = M->getTypeByName("foo"); + auto *InvalidFTy = FunctionType::get(StructTy, /*isVarArg=*/false); + + for (unsigned FI = 0; FI != LibFunc::NumLibFuncs; ++FI) { + auto &LF = cast( + *M->getOrInsertFunction(TLI.getName((LibFunc::Func)FI), InvalidFTy)); + EXPECT_FALSE(isLibFunc(LF)); + } +}