Index: include/llvm/Analysis/TargetLibraryInfo.h =================================================================== --- include/llvm/Analysis/TargetLibraryInfo.h +++ include/llvm/Analysis/TargetLibraryInfo.h @@ -17,6 +17,7 @@ #include "llvm/IR/Module.h" #include "llvm/IR/PassManager.h" #include "llvm/Pass.h" +#include namespace llvm { template class ArrayRef; @@ -30,6 +31,12 @@ unsigned VectorizationFactor; }; +/// Describes a vector function, by Name and Signature. +struct VectorFnInfo { + std::string Name; + FunctionType * Signature; +}; + namespace LibFunc { enum Func { #define TLI_DEFINE_ENUM @@ -53,6 +60,10 @@ static StringRef const StandardNames[LibFunc::NumLibFuncs]; bool ShouldExtI32Param, ShouldExtI32Return, ShouldSignExtI32Param; + /// Holds the mapping between a scalar function and its available vector + /// versions. + std::multimap VectorFunctionInfo; + enum AvailabilityState { StandardName = 3, // (memset to all ones) CustomName = 1, @@ -160,12 +171,14 @@ /// Return the name of the equivalent of F, vectorized with factor VF. If no /// such mapping exists, return the empty string. - StringRef getVectorizedFunction(StringRef F, unsigned VF) const; + StringRef getVectorizedFunction(StringRef F, unsigned VF, + FunctionType * Sign = nullptr) const; /// Return true if the function F has a scalar equivalent, and set VF to be /// the vectorization factor. - bool isFunctionScalarizable(StringRef F, unsigned &VF) const { - return !getScalarizedFunction(F, VF).empty(); + bool isFunctionVectorizable(StringRef F, unsigned VF, + FunctionType * Sign) const { + return !getVectorizedFunction(F, VF, Sign).empty(); } /// Return the name of the equivalent of F, scalarized. If no such mapping @@ -193,6 +206,23 @@ void setShouldSignExtI32Param(bool Val) { ShouldSignExtI32Param = Val; } + /// Adds vector routines that are available as global external function + /// pointers in the module \param M. + void addOpenMPVectorFunctions(Module * M); + + /// Demangle a scalar/vector mangled name + static std::pair demangle(const StringRef In); + + /// Checks the validity of a mangled scalar/vector name. + static bool isMangledName(StringRef Name); + + /// Check the validity of \param Ty to be used as a vector function + /// signature. If so, it sets \param FTy to the vector function signature. + static bool isValidSignature(Type *Ty, FunctionType *&FTY); + + /// Mangles \param VecName and \param ScalarName using a prefix, a middlefix + /// and a suffix. + static StringRef mangle(const StringRef VecName, const StringRef ScalarName); }; /// Provides information about what library functions are available for @@ -237,14 +267,16 @@ bool has(LibFunc::Func F) const { return Impl->getState(F) != TargetLibraryInfoImpl::Unavailable; } - bool isFunctionVectorizable(StringRef F, unsigned VF) const { - return Impl->isFunctionVectorizable(F, VF); + bool isFunctionVectorizable(StringRef F, unsigned VF, + FunctionType * Sign) const { + return Impl->isFunctionVectorizable(F, VF, Sign); } bool isFunctionVectorizable(StringRef F) const { return Impl->isFunctionVectorizable(F); } - StringRef getVectorizedFunction(StringRef F, unsigned VF) const { - return Impl->getVectorizedFunction(F, VF); + StringRef getVectorizedFunction(StringRef F, unsigned VF, + FunctionType * Sign) const { + return Impl->getVectorizedFunction(F, VF, Sign); } /// Tests if the function is both available and a candidate for optimized code Index: lib/Analysis/TargetLibraryInfo.cpp =================================================================== --- lib/Analysis/TargetLibraryInfo.cpp +++ lib/Analysis/TargetLibraryInfo.cpp @@ -1190,11 +1190,16 @@ std::vector::const_iterator I = std::lower_bound( VectorDescs.begin(), VectorDescs.end(), funcName, compareWithScalarFnName); - return I != VectorDescs.end() && StringRef(I->ScalarFnName) == funcName; + // return I != VectorDescs.end() && StringRef(I->ScalarFnName) == funcName; + if ( I != VectorDescs.end()) + return StringRef(I->ScalarFnName) == funcName; + + return VectorFunctionInfo.find(funcName.str()) != VectorFunctionInfo.end(); } StringRef TargetLibraryInfoImpl::getVectorizedFunction(StringRef F, - unsigned VF) const { + unsigned VF, + FunctionType * Sign) const { F = sanitizeFunctionName(F); if (F.empty()) return F; @@ -1205,6 +1210,13 @@ return I->VectorFnName; ++I; } + + auto Range = llvm::make_range(VectorFunctionInfo.equal_range(F.str())); + for (auto VecInfo : Range) { + if (VecInfo.second.Signature == Sign) + return VecInfo.second.Name; + } + return StringRef(); } @@ -1273,3 +1285,80 @@ char TargetLibraryInfoWrapperPass::ID = 0; void TargetLibraryInfoWrapperPass::anchor() {} + +void TargetLibraryInfoImpl::addOpenMPVectorFunctions(Module * M) { + for (auto &GV : M->globals()) { + auto Name = GV.getName(); + //Skip invalid names + if (!isMangledName(Name)) + continue; + + const auto Ty = GV.getType(); + FunctionType * FTy; + // Skip invalid types + if (!isValidSignature(Ty, FTy)) + continue; + + const auto Names = demangle(Name); + const VectorFnInfo VecInfo = {Names.first, FTy}; + VectorFunctionInfo.emplace(Names.second, VecInfo); + } +} + +namespace { +bool checkTys(ArrayRef Params) { + for (auto &Ty : Params) { + if (Ty->isVectorTy()) + return true; + } + return false; +} + +const StringRef Prefix = "vec_prefix_"; +const StringRef Postfix = "_vec_postfix"; +const StringRef Midfix = "_vec_midfix_"; +} + +std::pair +TargetLibraryInfoImpl::demangle(const StringRef In) { + StringRef Out = In.drop_back(Postfix.size()); + StringRef Tmp = Out.drop_front(Prefix.size()); + return Tmp.split(Midfix); +} + +bool TargetLibraryInfoImpl::isMangledName(const StringRef Name) { + const bool HasPrefix = Name.startswith(Prefix); + const bool HasSuffix = Name.endswith(Postfix); + const bool HasMidfix = Name.contains(Midfix); + + if (HasPrefix && HasMidfix && HasSuffix) { + auto Split = demangle(Name); + return !Split.first.empty() && !Split.second.empty(); + } + + return false; +} + +bool TargetLibraryInfoImpl::isValidSignature(Type *Ty, FunctionType *&FTy) { + if (!Ty->isPointerTy()) + return false; + + FTy = dyn_cast(Ty->getPointerElementType()); + + if (!FTy) + return false; + + auto RetTy = FTy->getReturnType(); + + if (RetTy->isVectorTy()) + return true; + + return RetTy->isVoidTy() && checkTys(FTy->params()); +} + +StringRef TargetLibraryInfoImpl::mangle(const StringRef VecName, + const StringRef ScalarName) { + const std::string Ret = Prefix.str() + VecName.str() + Midfix.str() + + ScalarName.str() + Postfix.str(); + return Ret; +} Index: lib/Transforms/Vectorize/LoopVectorize.cpp =================================================================== --- lib/Transforms/Vectorize/LoopVectorize.cpp +++ lib/Transforms/Vectorize/LoopVectorize.cpp @@ -3645,7 +3645,11 @@ // If we can't emit a vector call for this function, then the currently found // cost is the cost we need to return. NeedToScalarize = true; - if (!TLI || !TLI->isFunctionVectorizable(FnName, VF) || CI->isNoBuiltin()) + if (!TLI || + !TLI->isFunctionVectorizable(FnName, VF, + FunctionType::get(RetTy, Tys, false)) || + CI->isNoBuiltin()) + // if (!TLI || !TLI->isFunctionVectorizable(FnName, VF) || CI->isNoBuiltin()) return Cost; // If the corresponding vector cost is cheaper, return its cost. @@ -4866,12 +4870,14 @@ VectorF = Intrinsic::getDeclaration(M, ID, TysForDecl); } else { // Use vector version of the library call. - StringRef VFnName = TLI->getVectorizedFunction(FnName, VF); + // StringRef VFnName = TLI->getVectorizedFunction(FnName, VF); + FunctionType *FTy = FunctionType::get(RetTy, Tys, false); + StringRef VFnName = TLI->getVectorizedFunction(FnName, VF, FTy); assert(!VFnName.empty() && "Vector function name is empty."); VectorF = M->getFunction(VFnName); if (!VectorF) { // Generate a declaration - FunctionType *FTy = FunctionType::get(RetTy, Tys, false); + // FunctionType *FTy = FunctionType::get(RetTy, Tys, false); VectorF = Function::Create(FTy, Function::ExternalLinkage, VFnName, M); VectorF->copyAttributesFrom(F); Index: unittests/Analysis/CMakeLists.txt =================================================================== --- unittests/Analysis/CMakeLists.txt +++ unittests/Analysis/CMakeLists.txt @@ -13,6 +13,7 @@ CGSCCPassManagerTest.cpp LazyCallGraphTest.cpp LoopPassManagerTest.cpp + OpenMP.cpp ScalarEvolutionTest.cpp TBAATest.cpp ValueTrackingTest.cpp Index: unittests/Analysis/OpenMP.cpp =================================================================== --- /dev/null +++ unittests/Analysis/OpenMP.cpp @@ -0,0 +1,114 @@ +#include "llvm/Support/SourceMgr.h" +#include "llvm/AsmParser/Parser.h" +#include "llvm/IR/Module.h" +#include "llvm/IRReader/IRReader.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/Analysis/TargetLibraryInfo.h" +#include "gtest/gtest.h" + +using namespace llvm; + +namespace { +const std::string Pre = "vec_prefix_"; +const std::string Post = "_vec_postfix"; +const std::string Mid = "_vec_midfix_"; +} + +TEST(OpenMP, isMangledName) { + using TLI = TargetLibraryInfoImpl; + + // valid names + EXPECT_TRUE(TLI::isMangledName("vec_prefix_vfoo_vec_midfix_foo_vec_postfix")); + EXPECT_TRUE(TLI::isMangledName("vec_prefix_v_vec_midfix_f_vec_postfix")); + + // wrong prefix/midfix/postfix + EXPECT_FALSE(TLI::isMangledName("vec_prefix_vfoo_vec_midfix_foo_ec_postfix")); + EXPECT_FALSE(TLI::isMangledName("ec_prefix_vfoo_vec_midfix_foo_vec_postfix")); + EXPECT_FALSE(TLI::isMangledName("vec_prefix_vfoo_ve_midfix_foo_vec_postfix")); + + // no function names + EXPECT_FALSE(TLI::isMangledName("vec_prefix__vec_midfix__vec_postfix")); + EXPECT_FALSE(TLI::isMangledName("vec_prefix__vec_midfix_xxxx_vec_postfix")); + EXPECT_FALSE(TLI::isMangledName("vec_prefix_xxxx_vec_midfix__vec_postfix")); +} + +TEST(OpenMPTest, GlobalValueSignatures) { + using TLI = TargetLibraryInfoImpl; + LLVMContext C; + FunctionType *DummyTy; + + // invalid: not pointers to functions + EXPECT_FALSE(TLI::isValidSignature(Type::getDoubleTy(C), DummyTy)); + EXPECT_FALSE(TLI::isValidSignature(Type::getDoublePtrTy(C), DummyTy)); + auto FTy = FunctionType::get(Type::getDoubleTy(C), false); + EXPECT_FALSE(TLI::isValidSignature(FTy, DummyTy)); + + // invalid function pointer: not a valid signature + EXPECT_FALSE(TLI::isValidSignature(FTy->getPointerTo(), DummyTy)); + + // invalid: a function returning void with not valid input parameters + const ArrayRef NoTys = {Type::getDoublePtrTy(C), Type::getInt64Ty(C)}; + auto VoidFTy = FunctionType::get(Type::getVoidTy(C), NoTys, false); + EXPECT_FALSE(TLI::isValidSignature(VoidFTy->getPointerTo(), DummyTy)); + + // valid: pointer to function returning vector + auto VFTy = + FunctionType::get(VectorType::get(Type::getDoubleTy(C), 4), false); + EXPECT_TRUE(TLI::isValidSignature(VFTy->getPointerTo(), DummyTy)); + + // valid: pointer to function returning void with at least one vector + // parameter + const ArrayRef Tys = {Type::getDoublePtrTy(C), + VectorType::get(Type::getDoubleTy(C), 4)}; + auto VoidVFTy = FunctionType::get(Type::getVoidTy(C), Tys, false); + EXPECT_TRUE(TLI::isValidSignature(VoidVFTy->getPointerTo(), DummyTy)); +} + +TEST(OpenMP, Mangle) { + const StringRef VF("vfoo"); + const StringRef F("foo"); + const StringRef Out = TargetLibraryInfoImpl::mangle(VF, F); + + EXPECT_STREQ("vec_prefix_vfoo_vec_midfix_foo_vec_postfix", Out.data()); +} + +TEST(OpenMP, Demangle) { + StringRef In = "vec_prefix_vfoo_vec_midfix_foo_vec_postfix"; + + const std::pair Out = + TargetLibraryInfoImpl::demangle(In); + + const StringRef VF = "vfoo"; + const StringRef F = "foo"; + + EXPECT_EQ(VF, Out.first); + EXPECT_EQ(F, Out.second); +} + +TEST(OpenMPTest, NotValidGlobals) { + LLVMContext C; + std::unique_ptr M(new Module("Test", C)); + + const StringRef Mangled = TargetLibraryInfoImpl::mangle("vector", "scalar"); + const auto Ty = FunctionType::get(Type::getDoubleTy(C), false); + M->getOrInsertGlobal(Mangled, Ty); + + TargetLibraryInfoImpl TLII; + TargetLibraryInfo TLI(TLII); + TLII.addOpenMPVectorFunctions(M.get()); + EXPECT_FALSE(TLI.isFunctionVectorizable("scalar")); +} + +TEST(OpenMPTest, ValidGlobals) { + LLVMContext C; + std::unique_ptr M(new Module("Test", C)); + + const auto VFTy = + FunctionType::get(VectorType::get(Type::getDoubleTy(C), 4), false); + M->getOrInsertGlobal("vec_prefix_vector_vec_midfix_scalar_vec_postfix", VFTy); + + TargetLibraryInfoImpl TLII; + TargetLibraryInfo TLI(TLII); + TLII.addOpenMPVectorFunctions(M.get()); + EXPECT_TRUE(TLI.isFunctionVectorizable("scalar")); +}