| //===-- NVPTXUtilities - Utilities -----------------------------*- 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 |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This file contains declarations for PTX-specific utility functions. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef LLVM_LIB_TARGET_NVPTX_NVPTXUTILITIES_H |
| #define LLVM_LIB_TARGET_NVPTX_NVPTXUTILITIES_H |
| |
| #include "NVPTX.h" |
| #include "llvm/ADT/StringExtras.h" |
| #include "llvm/CodeGen/ValueTypes.h" |
| #include "llvm/IR/Function.h" |
| #include "llvm/IR/InstrTypes.h" |
| #include "llvm/IR/Value.h" |
| #include "llvm/Support/Alignment.h" |
| #include "llvm/Support/FormatVariadic.h" |
| #include <cstdarg> |
| #include <string> |
| |
| namespace llvm { |
| |
| class DataLayout; |
| class MemSDNode; |
| |
| Function *getMaybeBitcastedCallee(const CallBase *CB); |
| |
| /// The bit-width of a single element loaded by \p Mem, i.e. the width used for |
| /// the ".fromtype" part of the emitted PTX load. |
| unsigned getFromTypeWidthForLoad(const MemSDNode *Mem); |
| |
| /// ABI alignment of \p ArgTy in .param space, capped at the PTX maximum of 128. |
| Align getPTXParamTypeAlign(Type *ArgTy, const DataLayout &DL); |
| |
| /// The .param-space alignment for a byval parameter or call argument: the |
| /// (possibly promoted) parameter alignment, raised to the ptxas byval minimum. |
| Align getDeviceByValParamAlign(const Function *F, Type *ArgTy, unsigned AttrIdx, |
| const DataLayout &DL); |
| Align getDeviceByValParamAlign(const CallBase *CB, Type *ArgTy, |
| unsigned AttrIdx, const DataLayout &DL); |
| |
| /// Alignment for a function parameter or return value at AttributeList index |
| /// \p AttrIdx (FirstArgIndex + argNo, or ReturnIndex). Prefers an explicit |
| /// stackalign, else the ABI type alignment, folding in the byval `align`. |
| Align getPTXParamAlign(const Function *F, Type *Ty, unsigned AttrIdx, |
| const DataLayout &DL); |
| |
| /// Alignment for a call-site argument or return value. Prefers an explicit |
| /// stackalign on the call, else resolves the direct callee. |
| Align getPTXParamAlign(const CallBase *CB, Type *Ty, unsigned AttrIdx, |
| const DataLayout &DL); |
| |
| // PTX ABI requires all scalar argument/return values to have |
| // bit-size as a power of two of at least 32 bits. |
| inline unsigned promoteScalarArgumentSize(unsigned Size) { |
| assert(Size < 128 && "Size should be less than 128 (shouldPassAsArray)"); |
| return PowerOf2Ceil(std::max(Size, 32U)); |
| } |
| |
| inline unsigned promoteScalarKernelArgumentSize(unsigned Size) { |
| assert(Size < 128 && "Size should be less than 128 (shouldPassAsArray)"); |
| return PowerOf2Ceil(std::max(Size, 8U)); |
| } |
| |
| inline bool shouldPassAsArray(Type *Ty) { |
| return Ty->isAggregateType() || Ty->isVectorTy() || |
| Ty->getScalarSizeInBits() >= 128 || Ty->isHalfTy() || Ty->isBFloatTy(); |
| } |
| |
| namespace NVPTX { |
| // Returns a list of vector types that we prefer to fit into a single PTX |
| // register. NOTE: This must be kept in sync with the register classes |
| // defined in NVPTXRegisterInfo.td. |
| inline auto packed_types() { |
| static const auto PackedTypes = {MVT::v4i8, MVT::v2f16, MVT::v2bf16, |
| MVT::v2i16, MVT::v2f32, MVT::v2i32}; |
| return PackedTypes; |
| } |
| |
| // Checks if the type VT can fit into a single register. |
| inline bool isPackedVectorTy(EVT VT) { |
| return any_of(packed_types(), equal_to(VT)); |
| } |
| |
| // Checks if two or more of the type ET can fit into a single register. |
| inline bool isPackedElementTy(EVT ET) { |
| return any_of(packed_types(), |
| [ET](EVT OVT) { return OVT.getVectorElementType() == ET; }); |
| } |
| |
| inline std::string getValidPTXIdentifier(StringRef Name) { |
| std::string ValidName; |
| ValidName.reserve(Name.size() + 4); |
| for (char C : Name) |
| // While PTX also allows '%' at the start of identifiers, LLVM will throw a |
| // fatal error for '%' in symbol names in MCSymbol::print. Exclude for now. |
| if (isAlnum(C) || C == '_' || C == '$') |
| ValidName.push_back(C); |
| else |
| ValidName.append({'_', '$', '_'}); |
| |
| return ValidName; |
| } |
| |
| inline std::string OrderingToString(Ordering Order) { |
| switch (Order) { |
| case Ordering::NotAtomic: |
| return "NotAtomic"; |
| case Ordering::Relaxed: |
| return "Relaxed"; |
| case Ordering::Acquire: |
| return "Acquire"; |
| case Ordering::Release: |
| return "Release"; |
| case Ordering::AcquireRelease: |
| return "AcquireRelease"; |
| case Ordering::SequentiallyConsistent: |
| return "SequentiallyConsistent"; |
| case Ordering::Volatile: |
| return "Volatile"; |
| case Ordering::RelaxedMMIO: |
| return "RelaxedMMIO"; |
| } |
| report_fatal_error(formatv("Unknown NVPTX::Ordering \"{}\".", |
| static_cast<OrderingUnderlyingType>(Order))); |
| } |
| |
| inline raw_ostream &operator<<(raw_ostream &O, Ordering Order) { |
| O << OrderingToString(Order); |
| return O; |
| } |
| |
| inline std::string ScopeToString(Scope S) { |
| switch (S) { |
| case Scope::Thread: |
| return "Thread"; |
| case Scope::System: |
| return "System"; |
| case Scope::Block: |
| return "Block"; |
| case Scope::Cluster: |
| return "Cluster"; |
| case Scope::Device: |
| return "Device"; |
| case Scope::DefaultDevice: |
| return "DefaultDevice"; |
| } |
| report_fatal_error(formatv("Unknown NVPTX::Scope \"{}\".", |
| static_cast<ScopeUnderlyingType>(S))); |
| } |
| |
| inline raw_ostream &operator<<(raw_ostream &O, Scope S) { |
| O << ScopeToString(S); |
| return O; |
| } |
| |
| inline const char *addressSpaceToString(AddressSpace A, |
| bool UseParamSubqualifiers = false) { |
| switch (A) { |
| case AddressSpace::Generic: |
| return "generic"; |
| case AddressSpace::Global: |
| return "global"; |
| case AddressSpace::Const: |
| return "const"; |
| case AddressSpace::Shared: |
| return "shared"; |
| case AddressSpace::SharedCluster: |
| return "shared::cluster"; |
| case AddressSpace::EntryParam: |
| return UseParamSubqualifiers ? "param::entry" : "param"; |
| case AddressSpace::DeviceParam: |
| return UseParamSubqualifiers ? "param::func" : "param"; |
| case AddressSpace::Local: |
| return "local"; |
| } |
| report_fatal_error(formatv("Unknown NVPTX::AddressSpace \"{}\".", |
| static_cast<AddressSpaceUnderlyingType>(A))); |
| } |
| |
| inline raw_ostream &operator<<(raw_ostream &O, AddressSpace A) { |
| O << addressSpaceToString(A); |
| return O; |
| } |
| |
| } // namespace NVPTX |
| } // namespace llvm |
| |
| #endif |