123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597 |
- #pragma once
- #ifdef __GNUC__
- #pragma GCC diagnostic push
- #pragma GCC diagnostic ignored "-Wunused-parameter"
- #endif
- //===-- TargetLibraryInfo.h - Library information ---------------*- C++ -*-===//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- #ifndef LLVM_ANALYSIS_TARGETLIBRARYINFO_H
- #define LLVM_ANALYSIS_TARGETLIBRARYINFO_H
- #include "llvm/ADT/BitVector.h"
- #include "llvm/ADT/DenseMap.h"
- #include "llvm/ADT/Triple.h"
- #include "llvm/IR/InstrTypes.h"
- #include "llvm/IR/PassManager.h"
- #include "llvm/Pass.h"
- #include <optional>
- namespace llvm {
- template <typename T> class ArrayRef;
- class Function;
- class Module;
- class Triple;
- /// Describes a possible vectorization of a function.
- /// Function 'VectorFnName' is equivalent to 'ScalarFnName' vectorized
- /// by a factor 'VectorizationFactor'.
- struct VecDesc {
- StringRef ScalarFnName;
- StringRef VectorFnName;
- ElementCount VectorizationFactor;
- };
- enum LibFunc : unsigned {
- #define TLI_DEFINE_ENUM
- #include "llvm/Analysis/TargetLibraryInfo.def"
- NumLibFuncs,
- NotLibFunc
- };
- /// Implementation of the target library information.
- ///
- /// This class constructs tables that hold the target library information and
- /// make it available. However, it is somewhat expensive to compute and only
- /// depends on the triple. So users typically interact with the \c
- /// TargetLibraryInfo wrapper below.
- class TargetLibraryInfoImpl {
- friend class TargetLibraryInfo;
- unsigned char AvailableArray[(NumLibFuncs+3)/4];
- DenseMap<unsigned, std::string> CustomNames;
- static StringLiteral const StandardNames[NumLibFuncs];
- bool ShouldExtI32Param, ShouldExtI32Return, ShouldSignExtI32Param, ShouldSignExtI32Return;
- unsigned SizeOfInt;
- enum AvailabilityState {
- StandardName = 3, // (memset to all ones)
- CustomName = 1,
- Unavailable = 0 // (memset to all zeros)
- };
- void setState(LibFunc F, AvailabilityState State) {
- AvailableArray[F/4] &= ~(3 << 2*(F&3));
- AvailableArray[F/4] |= State << 2*(F&3);
- }
- AvailabilityState getState(LibFunc F) const {
- return static_cast<AvailabilityState>((AvailableArray[F/4] >> 2*(F&3)) & 3);
- }
- /// Vectorization descriptors - sorted by ScalarFnName.
- std::vector<VecDesc> VectorDescs;
- /// Scalarization descriptors - same content as VectorDescs but sorted based
- /// on VectorFnName rather than ScalarFnName.
- std::vector<VecDesc> ScalarDescs;
- /// Return true if the function type FTy is valid for the library function
- /// F, regardless of whether the function is available.
- bool isValidProtoForLibFunc(const FunctionType &FTy, LibFunc F,
- const Module &M) const;
- public:
- /// List of known vector-functions libraries.
- ///
- /// The vector-functions library defines, which functions are vectorizable
- /// and with which factor. The library can be specified by either frontend,
- /// or a commandline option, and then used by
- /// addVectorizableFunctionsFromVecLib for filling up the tables of
- /// vectorizable functions.
- enum VectorLibrary {
- NoLibrary, // Don't use any vector library.
- Accelerate, // Use Accelerate framework.
- DarwinLibSystemM, // Use Darwin's libsystem_m.
- LIBMVEC_X86, // GLIBC Vector Math library.
- MASSV, // IBM MASS vector library.
- SVML, // Intel short vector math library.
- SLEEFGNUABI // SLEEF - SIMD Library for Evaluating Elementary Functions.
- };
- TargetLibraryInfoImpl();
- explicit TargetLibraryInfoImpl(const Triple &T);
- // Provide value semantics.
- TargetLibraryInfoImpl(const TargetLibraryInfoImpl &TLI);
- TargetLibraryInfoImpl(TargetLibraryInfoImpl &&TLI);
- TargetLibraryInfoImpl &operator=(const TargetLibraryInfoImpl &TLI);
- TargetLibraryInfoImpl &operator=(TargetLibraryInfoImpl &&TLI);
- /// Searches for a particular function name.
- ///
- /// If it is one of the known library functions, return true and set F to the
- /// corresponding value.
- bool getLibFunc(StringRef funcName, LibFunc &F) const;
- /// Searches for a particular function name, also checking that its type is
- /// valid for the library function matching that name.
- ///
- /// If it is one of the known library functions, return true and set F to the
- /// corresponding value.
- ///
- /// FDecl is assumed to have a parent Module when using this function.
- bool getLibFunc(const Function &FDecl, LibFunc &F) const;
- /// Forces a function to be marked as unavailable.
- void setUnavailable(LibFunc F) {
- setState(F, Unavailable);
- }
- /// Forces a function to be marked as available.
- void setAvailable(LibFunc F) {
- setState(F, StandardName);
- }
- /// Forces a function to be marked as available and provide an alternate name
- /// that must be used.
- void setAvailableWithName(LibFunc F, StringRef Name) {
- if (StandardNames[F] != Name) {
- setState(F, CustomName);
- CustomNames[F] = std::string(Name);
- assert(CustomNames.find(F) != CustomNames.end());
- } else {
- setState(F, StandardName);
- }
- }
- /// Disables all builtins.
- ///
- /// This can be used for options like -fno-builtin.
- void disableAllFunctions();
- /// Add a set of scalar -> vector mappings, queryable via
- /// getVectorizedFunction and getScalarizedFunction.
- void addVectorizableFunctions(ArrayRef<VecDesc> Fns);
- /// Calls addVectorizableFunctions with a known preset of functions for the
- /// given vector library.
- void addVectorizableFunctionsFromVecLib(enum VectorLibrary VecLib,
- const llvm::Triple &TargetTriple);
- /// Return true if the function F has a vector equivalent with vectorization
- /// factor VF.
- bool isFunctionVectorizable(StringRef F, const ElementCount &VF) const {
- return !getVectorizedFunction(F, VF).empty();
- }
- /// Return true if the function F has a vector equivalent with any
- /// vectorization factor.
- bool isFunctionVectorizable(StringRef F) const;
- /// 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, const ElementCount &VF) const;
- /// Set to true iff i32 parameters to library functions should have signext
- /// or zeroext attributes if they correspond to C-level int or unsigned int,
- /// respectively.
- void setShouldExtI32Param(bool Val) {
- ShouldExtI32Param = Val;
- }
- /// Set to true iff i32 results from library functions should have signext
- /// or zeroext attributes if they correspond to C-level int or unsigned int,
- /// respectively.
- void setShouldExtI32Return(bool Val) {
- ShouldExtI32Return = Val;
- }
- /// Set to true iff i32 parameters to library functions should have signext
- /// attribute if they correspond to C-level int or unsigned int.
- void setShouldSignExtI32Param(bool Val) {
- ShouldSignExtI32Param = Val;
- }
- /// Set to true iff i32 results from library functions should have signext
- /// attribute if they correspond to C-level int or unsigned int.
- void setShouldSignExtI32Return(bool Val) {
- ShouldSignExtI32Return = Val;
- }
- /// Returns the size of the wchar_t type in bytes or 0 if the size is unknown.
- /// This queries the 'wchar_size' metadata.
- unsigned getWCharSize(const Module &M) const;
- /// Returns the size of the size_t type in bits.
- unsigned getSizeTSize(const Module &M) const;
- /// Get size of a C-level int or unsigned int, in bits.
- unsigned getIntSize() const {
- return SizeOfInt;
- }
- /// Initialize the C-level size of an integer.
- void setIntSize(unsigned Bits) {
- SizeOfInt = Bits;
- }
- /// Returns the largest vectorization factor used in the list of
- /// vector functions.
- void getWidestVF(StringRef ScalarF, ElementCount &FixedVF,
- ElementCount &Scalable) const;
- /// Returns true if call site / callee has cdecl-compatible calling
- /// conventions.
- static bool isCallingConvCCompatible(CallBase *CI);
- static bool isCallingConvCCompatible(Function *Callee);
- };
- /// Provides information about what library functions are available for
- /// the current target.
- ///
- /// This both allows optimizations to handle them specially and frontends to
- /// disable such optimizations through -fno-builtin etc.
- class TargetLibraryInfo {
- friend class TargetLibraryAnalysis;
- friend class TargetLibraryInfoWrapperPass;
- /// The global (module level) TLI info.
- const TargetLibraryInfoImpl *Impl;
- /// Support for -fno-builtin* options as function attributes, overrides
- /// information in global TargetLibraryInfoImpl.
- BitVector OverrideAsUnavailable;
- public:
- explicit TargetLibraryInfo(const TargetLibraryInfoImpl &Impl,
- std::optional<const Function *> F = std::nullopt)
- : Impl(&Impl), OverrideAsUnavailable(NumLibFuncs) {
- if (!F)
- return;
- if ((*F)->hasFnAttribute("no-builtins"))
- disableAllFunctions();
- else {
- // Disable individual libc/libm calls in TargetLibraryInfo.
- LibFunc LF;
- AttributeSet FnAttrs = (*F)->getAttributes().getFnAttrs();
- for (const Attribute &Attr : FnAttrs) {
- if (!Attr.isStringAttribute())
- continue;
- auto AttrStr = Attr.getKindAsString();
- if (!AttrStr.consume_front("no-builtin-"))
- continue;
- if (getLibFunc(AttrStr, LF))
- setUnavailable(LF);
- }
- }
- }
- // Provide value semantics.
- TargetLibraryInfo(const TargetLibraryInfo &TLI) = default;
- TargetLibraryInfo(TargetLibraryInfo &&TLI)
- : Impl(TLI.Impl), OverrideAsUnavailable(TLI.OverrideAsUnavailable) {}
- TargetLibraryInfo &operator=(const TargetLibraryInfo &TLI) = default;
- TargetLibraryInfo &operator=(TargetLibraryInfo &&TLI) {
- Impl = TLI.Impl;
- OverrideAsUnavailable = TLI.OverrideAsUnavailable;
- return *this;
- }
- /// Determine whether a callee with the given TLI can be inlined into
- /// caller with this TLI, based on 'nobuiltin' attributes. When requested,
- /// allow inlining into a caller with a superset of the callee's nobuiltin
- /// attributes, which is conservatively correct.
- bool areInlineCompatible(const TargetLibraryInfo &CalleeTLI,
- bool AllowCallerSuperset) const {
- if (!AllowCallerSuperset)
- return OverrideAsUnavailable == CalleeTLI.OverrideAsUnavailable;
- BitVector B = OverrideAsUnavailable;
- B |= CalleeTLI.OverrideAsUnavailable;
- // We can inline if the union of the caller and callee's nobuiltin
- // attributes is no stricter than the caller's nobuiltin attributes.
- return B == OverrideAsUnavailable;
- }
- /// Return true if the function type FTy is valid for the library function
- /// F, regardless of whether the function is available.
- bool isValidProtoForLibFunc(const FunctionType &FTy, LibFunc F,
- const Module &M) const {
- return Impl->isValidProtoForLibFunc(FTy, F, M);
- }
- /// Searches for a particular function name.
- ///
- /// If it is one of the known library functions, return true and set F to the
- /// corresponding value.
- bool getLibFunc(StringRef funcName, LibFunc &F) const {
- return Impl->getLibFunc(funcName, F);
- }
- bool getLibFunc(const Function &FDecl, LibFunc &F) const {
- return Impl->getLibFunc(FDecl, F);
- }
- /// If a callbase does not have the 'nobuiltin' attribute, return if the
- /// called function is a known library function and set F to that function.
- bool getLibFunc(const CallBase &CB, LibFunc &F) const {
- return !CB.isNoBuiltin() && CB.getCalledFunction() &&
- getLibFunc(*(CB.getCalledFunction()), F);
- }
- /// Disables all builtins.
- ///
- /// This can be used for options like -fno-builtin.
- void disableAllFunctions() LLVM_ATTRIBUTE_UNUSED {
- OverrideAsUnavailable.set();
- }
- /// Forces a function to be marked as unavailable.
- void setUnavailable(LibFunc F) LLVM_ATTRIBUTE_UNUSED {
- OverrideAsUnavailable.set(F);
- }
- TargetLibraryInfoImpl::AvailabilityState getState(LibFunc F) const {
- if (OverrideAsUnavailable[F])
- return TargetLibraryInfoImpl::Unavailable;
- return Impl->getState(F);
- }
- /// Tests whether a library function is available.
- bool has(LibFunc F) const {
- return getState(F) != TargetLibraryInfoImpl::Unavailable;
- }
- bool isFunctionVectorizable(StringRef F, const ElementCount &VF) const {
- return Impl->isFunctionVectorizable(F, VF);
- }
- bool isFunctionVectorizable(StringRef F) const {
- return Impl->isFunctionVectorizable(F);
- }
- StringRef getVectorizedFunction(StringRef F, const ElementCount &VF) const {
- return Impl->getVectorizedFunction(F, VF);
- }
- /// Tests if the function is both available and a candidate for optimized code
- /// generation.
- bool hasOptimizedCodeGen(LibFunc F) const {
- if (getState(F) == TargetLibraryInfoImpl::Unavailable)
- return false;
- switch (F) {
- default: break;
- case LibFunc_copysign: case LibFunc_copysignf: case LibFunc_copysignl:
- case LibFunc_fabs: case LibFunc_fabsf: case LibFunc_fabsl:
- case LibFunc_sin: case LibFunc_sinf: case LibFunc_sinl:
- case LibFunc_cos: case LibFunc_cosf: case LibFunc_cosl:
- case LibFunc_sqrt: case LibFunc_sqrtf: case LibFunc_sqrtl:
- case LibFunc_sqrt_finite: case LibFunc_sqrtf_finite:
- case LibFunc_sqrtl_finite:
- case LibFunc_fmax: case LibFunc_fmaxf: case LibFunc_fmaxl:
- case LibFunc_fmin: case LibFunc_fminf: case LibFunc_fminl:
- case LibFunc_floor: case LibFunc_floorf: case LibFunc_floorl:
- case LibFunc_nearbyint: case LibFunc_nearbyintf: case LibFunc_nearbyintl:
- case LibFunc_ceil: case LibFunc_ceilf: case LibFunc_ceill:
- case LibFunc_rint: case LibFunc_rintf: case LibFunc_rintl:
- case LibFunc_round: case LibFunc_roundf: case LibFunc_roundl:
- case LibFunc_trunc: case LibFunc_truncf: case LibFunc_truncl:
- case LibFunc_log2: case LibFunc_log2f: case LibFunc_log2l:
- case LibFunc_exp2: case LibFunc_exp2f: case LibFunc_exp2l:
- case LibFunc_memcpy: case LibFunc_memset: case LibFunc_memmove:
- case LibFunc_memcmp: case LibFunc_bcmp: case LibFunc_strcmp:
- case LibFunc_strcpy: case LibFunc_stpcpy: case LibFunc_strlen:
- case LibFunc_strnlen: case LibFunc_memchr: case LibFunc_mempcpy:
- return true;
- }
- return false;
- }
- StringRef getName(LibFunc F) const {
- auto State = getState(F);
- if (State == TargetLibraryInfoImpl::Unavailable)
- return StringRef();
- if (State == TargetLibraryInfoImpl::StandardName)
- return Impl->StandardNames[F];
- assert(State == TargetLibraryInfoImpl::CustomName);
- return Impl->CustomNames.find(F)->second;
- }
- static void initExtensionsForTriple(bool &ShouldExtI32Param,
- bool &ShouldExtI32Return,
- bool &ShouldSignExtI32Param,
- bool &ShouldSignExtI32Return,
- const Triple &T) {
- ShouldExtI32Param = ShouldExtI32Return = false;
- ShouldSignExtI32Param = ShouldSignExtI32Return = false;
- // PowerPC64, Sparc64, SystemZ need signext/zeroext on i32 parameters and
- // returns corresponding to C-level ints and unsigned ints.
- if (T.isPPC64() || T.getArch() == Triple::sparcv9 ||
- T.getArch() == Triple::systemz) {
- ShouldExtI32Param = true;
- ShouldExtI32Return = true;
- }
- // Mips and riscv64, on the other hand, needs signext on i32 parameters
- // corresponding to both signed and unsigned ints.
- if (T.isMIPS() || T.isRISCV64()) {
- ShouldSignExtI32Param = true;
- }
- // riscv64 needs signext on i32 returns corresponding to both signed and
- // unsigned ints.
- if (T.isRISCV64()) {
- ShouldSignExtI32Return = true;
- }
- }
- /// Returns extension attribute kind to be used for i32 parameters
- /// corresponding to C-level int or unsigned int. May be zeroext, signext,
- /// or none.
- private:
- static Attribute::AttrKind getExtAttrForI32Param(bool ShouldExtI32Param_,
- bool ShouldSignExtI32Param_,
- bool Signed = true) {
- if (ShouldExtI32Param_)
- return Signed ? Attribute::SExt : Attribute::ZExt;
- if (ShouldSignExtI32Param_)
- return Attribute::SExt;
- return Attribute::None;
- }
- public:
- static Attribute::AttrKind getExtAttrForI32Param(const Triple &T,
- bool Signed = true) {
- bool ShouldExtI32Param, ShouldExtI32Return;
- bool ShouldSignExtI32Param, ShouldSignExtI32Return;
- initExtensionsForTriple(ShouldExtI32Param, ShouldExtI32Return,
- ShouldSignExtI32Param, ShouldSignExtI32Return, T);
- return getExtAttrForI32Param(ShouldExtI32Param, ShouldSignExtI32Param,
- Signed);
- }
- Attribute::AttrKind getExtAttrForI32Param(bool Signed = true) const {
- return getExtAttrForI32Param(Impl->ShouldExtI32Param,
- Impl->ShouldSignExtI32Param, Signed);
- }
- /// Returns extension attribute kind to be used for i32 return values
- /// corresponding to C-level int or unsigned int. May be zeroext, signext,
- /// or none.
- private:
- static Attribute::AttrKind getExtAttrForI32Return(bool ShouldExtI32Return_,
- bool ShouldSignExtI32Return_,
- bool Signed) {
- if (ShouldExtI32Return_)
- return Signed ? Attribute::SExt : Attribute::ZExt;
- if (ShouldSignExtI32Return_)
- return Attribute::SExt;
- return Attribute::None;
- }
- public:
- static Attribute::AttrKind getExtAttrForI32Return(const Triple &T,
- bool Signed = true) {
- bool ShouldExtI32Param, ShouldExtI32Return;
- bool ShouldSignExtI32Param, ShouldSignExtI32Return;
- initExtensionsForTriple(ShouldExtI32Param, ShouldExtI32Return,
- ShouldSignExtI32Param, ShouldSignExtI32Return, T);
- return getExtAttrForI32Return(ShouldExtI32Return, ShouldSignExtI32Return,
- Signed);
- }
- Attribute::AttrKind getExtAttrForI32Return(bool Signed = true) const {
- return getExtAttrForI32Return(Impl->ShouldExtI32Return,
- Impl->ShouldSignExtI32Return, Signed);
- }
- // Helper to create an AttributeList for args (and ret val) which all have
- // the same signedness. Attributes in AL may be passed in to include them
- // as well in the returned AttributeList.
- AttributeList getAttrList(LLVMContext *C, ArrayRef<unsigned> ArgNos,
- bool Signed, bool Ret = false,
- AttributeList AL = AttributeList()) const {
- if (auto AK = getExtAttrForI32Param(Signed))
- for (auto ArgNo : ArgNos)
- AL = AL.addParamAttribute(*C, ArgNo, AK);
- if (Ret)
- if (auto AK = getExtAttrForI32Return(Signed))
- AL = AL.addRetAttribute(*C, AK);
- return AL;
- }
- /// \copydoc TargetLibraryInfoImpl::getWCharSize()
- unsigned getWCharSize(const Module &M) const {
- return Impl->getWCharSize(M);
- }
- /// \copydoc TargetLibraryInfoImpl::getSizeTSize()
- unsigned getSizeTSize(const Module &M) const { return Impl->getSizeTSize(M); }
- /// \copydoc TargetLibraryInfoImpl::getIntSize()
- unsigned getIntSize() const {
- return Impl->getIntSize();
- }
- /// Handle invalidation from the pass manager.
- ///
- /// If we try to invalidate this info, just return false. It cannot become
- /// invalid even if the module or function changes.
- bool invalidate(Module &, const PreservedAnalyses &,
- ModuleAnalysisManager::Invalidator &) {
- return false;
- }
- bool invalidate(Function &, const PreservedAnalyses &,
- FunctionAnalysisManager::Invalidator &) {
- return false;
- }
- /// Returns the largest vectorization factor used in the list of
- /// vector functions.
- void getWidestVF(StringRef ScalarF, ElementCount &FixedVF,
- ElementCount &ScalableVF) const {
- Impl->getWidestVF(ScalarF, FixedVF, ScalableVF);
- }
- /// Check if the function "F" is listed in a library known to LLVM.
- bool isKnownVectorFunctionInLibrary(StringRef F) const {
- return this->isFunctionVectorizable(F);
- }
- };
- /// Analysis pass providing the \c TargetLibraryInfo.
- ///
- /// Note that this pass's result cannot be invalidated, it is immutable for the
- /// life of the module.
- class TargetLibraryAnalysis : public AnalysisInfoMixin<TargetLibraryAnalysis> {
- public:
- typedef TargetLibraryInfo Result;
- /// Default construct the library analysis.
- ///
- /// This will use the module's triple to construct the library info for that
- /// module.
- TargetLibraryAnalysis() = default;
- /// Construct a library analysis with baseline Module-level info.
- ///
- /// This will be supplemented with Function-specific info in the Result.
- TargetLibraryAnalysis(TargetLibraryInfoImpl BaselineInfoImpl)
- : BaselineInfoImpl(std::move(BaselineInfoImpl)) {}
- TargetLibraryInfo run(const Function &F, FunctionAnalysisManager &);
- private:
- friend AnalysisInfoMixin<TargetLibraryAnalysis>;
- static AnalysisKey Key;
- std::optional<TargetLibraryInfoImpl> BaselineInfoImpl;
- };
- class TargetLibraryInfoWrapperPass : public ImmutablePass {
- TargetLibraryAnalysis TLA;
- std::optional<TargetLibraryInfo> TLI;
- virtual void anchor();
- public:
- static char ID;
- TargetLibraryInfoWrapperPass();
- explicit TargetLibraryInfoWrapperPass(const Triple &T);
- explicit TargetLibraryInfoWrapperPass(const TargetLibraryInfoImpl &TLI);
- TargetLibraryInfo &getTLI(const Function &F) {
- FunctionAnalysisManager DummyFAM;
- TLI = TLA.run(F, DummyFAM);
- return *TLI;
- }
- };
- } // end namespace llvm
- #endif
- #ifdef __GNUC__
- #pragma GCC diagnostic pop
- #endif
|