1 //===- Utility.h - Collection of geneirc offloading utilities -------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #ifndef LLVM_FRONTEND_OFFLOADING_UTILITY_H 10 #define LLVM_FRONTEND_OFFLOADING_UTILITY_H 11 12 #include <cstdint> 13 14 #include "llvm/ADT/StringMap.h" 15 #include "llvm/ADT/StringRef.h" 16 #include "llvm/IR/Module.h" 17 #include "llvm/Object/OffloadBinary.h" 18 #include "llvm/Support/Error.h" 19 #include "llvm/Support/MemoryBufferRef.h" 20 21 namespace llvm { 22 namespace offloading { 23 24 /// This is the record of an object that just be registered with the offloading 25 /// runtime. 26 struct EntryTy { 27 /// Reserved bytes used to detect an older version of the struct, always zero. 28 uint64_t Reserved = 0x0; 29 /// The current version of the struct for runtime forward compatibility. 30 uint16_t Version = 0x1; 31 /// The expected consumer of this entry, e.g. CUDA or OpenMP. 32 uint16_t Kind; 33 /// Flags associated with the global. 34 uint32_t Flags; 35 /// The address of the global to be registered by the runtime. 36 void *Address; 37 /// The name of the symbol in the device image. 38 char *SymbolName; 39 /// The number of bytes the symbol takes. 40 uint64_t Size; 41 /// Extra generic data used to register this entry. 42 uint64_t Data; 43 /// An extra pointer, usually null. 44 void *AuxAddr; 45 }; 46 47 /// Offloading entry flags for CUDA / HIP. The first three bits indicate the 48 /// type of entry while the others are a bit field for additional information. 49 enum OffloadEntryKindFlag : uint32_t { 50 /// Mark the entry as a global entry. This indicates the presense of a 51 /// kernel if the size size field is zero and a variable otherwise. 52 OffloadGlobalEntry = 0x0, 53 /// Mark the entry as a managed global variable. 54 OffloadGlobalManagedEntry = 0x1, 55 /// Mark the entry as a surface variable. 56 OffloadGlobalSurfaceEntry = 0x2, 57 /// Mark the entry as a texture variable. 58 OffloadGlobalTextureEntry = 0x3, 59 /// Mark the entry as being extern. 60 OffloadGlobalExtern = 0x1 << 3, 61 /// Mark the entry as being constant. 62 OffloadGlobalConstant = 0x1 << 4, 63 /// Mark the entry as being a normalized surface. 64 OffloadGlobalNormalized = 0x1 << 5, 65 }; 66 67 /// Returns the type of the offloading entry we use to store kernels and 68 /// globals that will be registered with the offloading runtime. 69 StructType *getEntryTy(Module &M); 70 71 /// Create an offloading section struct used to register this global at 72 /// runtime. 73 /// 74 /// \param M The module to be used 75 /// \param Addr The pointer to the global being registered. 76 /// \param Kind The offloading language expected to consume this. 77 /// \param Name The symbol name associated with the global. 78 /// \param Size The size in bytes of the global (0 for functions). 79 /// \param Flags Flags associated with the entry. 80 /// \param Data Extra data storage associated with the entry. 81 /// \param SectionName The section this entry will be placed at. 82 /// \param AuxAddr An extra pointer if needed. 83 void emitOffloadingEntry(Module &M, object::OffloadKind Kind, Constant *Addr, 84 StringRef Name, uint64_t Size, uint32_t Flags, 85 uint64_t Data, StringRef SectionName, 86 Constant *AuxAddr = nullptr); 87 88 /// Create a constant struct initializer used to register this global at 89 /// runtime. 90 /// \return the constant struct and the global variable holding the symbol name. 91 std::pair<Constant *, GlobalVariable *> 92 getOffloadingEntryInitializer(Module &M, object::OffloadKind Kind, 93 Constant *Addr, StringRef Name, uint64_t Size, 94 uint32_t Flags, uint64_t Data, Constant *AuxAddr); 95 96 /// Creates a pair of globals used to iterate the array of offloading entries by 97 /// accessing the section variables provided by the linker. 98 std::pair<GlobalVariable *, GlobalVariable *> 99 getOffloadEntryArray(Module &M, StringRef SectionName); 100 101 namespace amdgpu { 102 /// Check if an image is compatible with current system's environment. The 103 /// system environment is given as a 'target-id' which has the form: 104 /// 105 /// <target-id> := <processor> ( ":" <target-feature> ( "+" | "-" ) )* 106 /// 107 /// If a feature is not specific as '+' or '-' it is assumed to be in an 'any' 108 /// and is compatible with either '+' or '-'. The HSA runtime returns this 109 /// information using the target-id, while we use the ELF header to determine 110 /// these features. 111 bool isImageCompatibleWithEnv(StringRef ImageArch, uint32_t ImageFlags, 112 StringRef EnvTargetID); 113 114 /// Struct for holding metadata related to AMDGPU kernels, for more information 115 /// about the metadata and its meaning see: 116 /// https://llvm.org/docs/AMDGPUUsage.html#code-object-v3 117 struct AMDGPUKernelMetaData { 118 /// Constant indicating that a value is invalid. 119 static constexpr uint32_t KInvalidValue = 120 std::numeric_limits<uint32_t>::max(); 121 /// The amount of group segment memory required by a work-group in bytes. 122 uint32_t GroupSegmentList = KInvalidValue; 123 /// The amount of fixed private address space memory required for a work-item 124 /// in bytes. 125 uint32_t PrivateSegmentSize = KInvalidValue; 126 /// Number of scalar registers required by a wavefront. 127 uint32_t SGPRCount = KInvalidValue; 128 /// Number of vector registers required by each work-item. 129 uint32_t VGPRCount = KInvalidValue; 130 /// Number of stores from a scalar register to a register allocator created 131 /// spill location. 132 uint32_t SGPRSpillCount = KInvalidValue; 133 /// Number of stores from a vector register to a register allocator created 134 /// spill location. 135 uint32_t VGPRSpillCount = KInvalidValue; 136 /// Number of accumulator registers required by each work-item. 137 uint32_t AGPRCount = KInvalidValue; 138 /// Corresponds to the OpenCL reqd_work_group_size attribute. 139 uint32_t RequestedWorkgroupSize[3] = {KInvalidValue, KInvalidValue, 140 KInvalidValue}; 141 /// Corresponds to the OpenCL work_group_size_hint attribute. 142 uint32_t WorkgroupSizeHint[3] = {KInvalidValue, KInvalidValue, KInvalidValue}; 143 /// Wavefront size. 144 uint32_t WavefrontSize = KInvalidValue; 145 /// Maximum flat work-group size supported by the kernel in work-items. 146 uint32_t MaxFlatWorkgroupSize = KInvalidValue; 147 }; 148 149 /// Reads AMDGPU specific metadata from the ELF file and propagates the 150 /// KernelInfoMap. 151 Error getAMDGPUMetaDataFromImage(MemoryBufferRef MemBuffer, 152 StringMap<AMDGPUKernelMetaData> &KernelInfoMap, 153 uint16_t &ELFABIVersion); 154 } // namespace amdgpu 155 } // namespace offloading 156 } // namespace llvm 157 158 #endif // LLVM_FRONTEND_OFFLOADING_UTILITY_H 159