Tim Renouf | d737b55 | 2019-03-20 17:42:00 +0000 | [diff] [blame^] | 1 | //===-- AMDGPUPALMetadata.cpp - Accumulate and print AMDGPU PAL metadata -===// |
| 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 | /// \file |
| 10 | /// |
| 11 | /// This class has methods called by AMDGPUAsmPrinter to accumulate and print |
| 12 | /// the PAL metadata. |
| 13 | // |
| 14 | //===----------------------------------------------------------------------===// |
| 15 | // |
| 16 | |
| 17 | #include "AMDGPUPALMetadata.h" |
| 18 | #include "AMDGPU.h" |
| 19 | #include "AMDGPUAsmPrinter.h" |
| 20 | #include "MCTargetDesc/AMDGPUTargetStreamer.h" |
| 21 | #include "SIDefines.h" |
| 22 | #include "llvm/BinaryFormat/ELF.h" |
| 23 | #include "llvm/IR/CallingConv.h" |
| 24 | #include "llvm/Support/AMDGPUMetadata.h" |
| 25 | #include "llvm/Support/EndianStream.h" |
| 26 | |
| 27 | using namespace llvm; |
| 28 | using namespace llvm::AMDGPU; |
| 29 | |
| 30 | // Read the amdgpu.pal.metadata supplied by the |
| 31 | // frontend into our Registers, ready for per-function modification. It |
| 32 | // is a NamedMD containing an MDTuple containing a number of MDNodes each of |
| 33 | // which is an integer value, and each two integer values forms a key=value |
| 34 | // pair that we store as Registers[key]=value in the map. |
| 35 | void AMDGPUPALMetadata::readFromIR(Module &M) { |
| 36 | auto NamedMD = M.getNamedMetadata("amdgpu.pal.metadata"); |
| 37 | if (!NamedMD || !NamedMD->getNumOperands()) |
| 38 | return; |
| 39 | auto Tuple = dyn_cast<MDTuple>(NamedMD->getOperand(0)); |
| 40 | if (!Tuple) |
| 41 | return; |
| 42 | for (unsigned I = 0, E = Tuple->getNumOperands() & -2; I != E; I += 2) { |
| 43 | auto Key = mdconst::dyn_extract<ConstantInt>(Tuple->getOperand(I)); |
| 44 | auto Val = mdconst::dyn_extract<ConstantInt>(Tuple->getOperand(I + 1)); |
| 45 | if (!Key || !Val) |
| 46 | continue; |
| 47 | Registers[Key->getZExtValue()] = Val->getZExtValue(); |
| 48 | } |
| 49 | } |
| 50 | |
| 51 | // Set PAL metadata from a binary blob from the applicable .note record. |
| 52 | // Returns false if bad format. Blob must remain valid for the lifetime of the |
| 53 | // Metadata. |
| 54 | bool AMDGPUPALMetadata::setFromBlob(unsigned Type, StringRef Blob) { |
| 55 | assert(Type == ELF::NT_AMD_AMDGPU_PAL_METADATA); |
| 56 | auto Data = reinterpret_cast<const uint32_t *>(Blob.data()); |
| 57 | for (unsigned I = 0; I != Blob.size() / sizeof(uint32_t) / 2; ++I) |
| 58 | setRegister(Data[I * 2], Data[I * 2 + 1]); |
| 59 | return true; |
| 60 | } |
| 61 | |
| 62 | // Given the calling convention, calculate the register number for rsrc1. In |
| 63 | // principle the register number could change in future hardware, but we know |
| 64 | // it is the same for gfx6-9 (except that LS and ES don't exist on gfx9), so |
| 65 | // we can use fixed values. |
| 66 | static unsigned getRsrc1Reg(CallingConv::ID CC) { |
| 67 | switch (CC) { |
| 68 | default: |
| 69 | return PALMD::R_2E12_COMPUTE_PGM_RSRC1; |
| 70 | case CallingConv::AMDGPU_LS: |
| 71 | return PALMD::R_2D4A_SPI_SHADER_PGM_RSRC1_LS; |
| 72 | case CallingConv::AMDGPU_HS: |
| 73 | return PALMD::R_2D0A_SPI_SHADER_PGM_RSRC1_HS; |
| 74 | case CallingConv::AMDGPU_ES: |
| 75 | return PALMD::R_2CCA_SPI_SHADER_PGM_RSRC1_ES; |
| 76 | case CallingConv::AMDGPU_GS: |
| 77 | return PALMD::R_2C8A_SPI_SHADER_PGM_RSRC1_GS; |
| 78 | case CallingConv::AMDGPU_VS: |
| 79 | return PALMD::R_2C4A_SPI_SHADER_PGM_RSRC1_VS; |
| 80 | case CallingConv::AMDGPU_PS: |
| 81 | return PALMD::R_2C0A_SPI_SHADER_PGM_RSRC1_PS; |
| 82 | } |
| 83 | } |
| 84 | |
| 85 | // Calculate the PAL metadata key for *S_SCRATCH_SIZE. It can be used |
| 86 | // with a constant offset to access any non-register shader-specific PAL |
| 87 | // metadata key. |
| 88 | static unsigned getScratchSizeKey(CallingConv::ID CC) { |
| 89 | switch (CC) { |
| 90 | case CallingConv::AMDGPU_PS: |
| 91 | return PALMD::Key::PS_SCRATCH_SIZE; |
| 92 | case CallingConv::AMDGPU_VS: |
| 93 | return PALMD::Key::VS_SCRATCH_SIZE; |
| 94 | case CallingConv::AMDGPU_GS: |
| 95 | return PALMD::Key::GS_SCRATCH_SIZE; |
| 96 | case CallingConv::AMDGPU_ES: |
| 97 | return PALMD::Key::ES_SCRATCH_SIZE; |
| 98 | case CallingConv::AMDGPU_HS: |
| 99 | return PALMD::Key::HS_SCRATCH_SIZE; |
| 100 | case CallingConv::AMDGPU_LS: |
| 101 | return PALMD::Key::LS_SCRATCH_SIZE; |
| 102 | default: |
| 103 | return PALMD::Key::CS_SCRATCH_SIZE; |
| 104 | } |
| 105 | } |
| 106 | |
| 107 | // Set the rsrc1 register in the metadata for a particular shader stage. |
| 108 | // In fact this ORs the value into any previous setting of the register. |
| 109 | void AMDGPUPALMetadata::setRsrc1(CallingConv::ID CC, unsigned Val) { |
| 110 | setRegister(getRsrc1Reg(CC), Val); |
| 111 | } |
| 112 | |
| 113 | // Set the rsrc2 register in the metadata for a particular shader stage. |
| 114 | // In fact this ORs the value into any previous setting of the register. |
| 115 | void AMDGPUPALMetadata::setRsrc2(CallingConv::ID CC, unsigned Val) { |
| 116 | setRegister(getRsrc1Reg(CC) + 1, Val); |
| 117 | } |
| 118 | |
| 119 | // Set the SPI_PS_INPUT_ENA register in the metadata. |
| 120 | // In fact this ORs the value into any previous setting of the register. |
| 121 | void AMDGPUPALMetadata::setSpiPsInputEna(unsigned Val) { |
| 122 | setRegister(PALMD::R_A1B3_SPI_PS_INPUT_ENA, Val); |
| 123 | } |
| 124 | |
| 125 | // Set the SPI_PS_INPUT_ADDR register in the metadata. |
| 126 | // In fact this ORs the value into any previous setting of the register. |
| 127 | void AMDGPUPALMetadata::setSpiPsInputAddr(unsigned Val) { |
| 128 | setRegister(PALMD::R_A1B4_SPI_PS_INPUT_ADDR, Val); |
| 129 | } |
| 130 | |
| 131 | // Get a register from the metadata, or 0 if not currently set. |
| 132 | unsigned AMDGPUPALMetadata::getRegister(unsigned Reg) { return Registers[Reg]; } |
| 133 | |
| 134 | // Set a register in the metadata. |
| 135 | // In fact this ORs the value into any previous setting of the register. |
| 136 | void AMDGPUPALMetadata::setRegister(unsigned Reg, unsigned Val) { |
| 137 | Registers[Reg] |= Val; |
| 138 | } |
| 139 | |
| 140 | // Set the number of used vgprs in the metadata. This is an optional advisory |
| 141 | // record for logging etc; wave dispatch actually uses the rsrc1 register for |
| 142 | // the shader stage to determine the number of vgprs to allocate. |
| 143 | void AMDGPUPALMetadata::setNumUsedVgprs(CallingConv::ID CC, unsigned Val) { |
| 144 | unsigned NumUsedVgprsKey = getScratchSizeKey(CC) + |
| 145 | PALMD::Key::VS_NUM_USED_VGPRS - |
| 146 | PALMD::Key::VS_SCRATCH_SIZE; |
| 147 | Registers[NumUsedVgprsKey] = Val; |
| 148 | } |
| 149 | |
| 150 | // Set the number of used sgprs in the metadata. This is an optional advisory |
| 151 | // record for logging etc; wave dispatch actually uses the rsrc1 register for |
| 152 | // the shader stage to determine the number of sgprs to allocate. |
| 153 | void AMDGPUPALMetadata::setNumUsedSgprs(CallingConv::ID CC, unsigned Val) { |
| 154 | unsigned NumUsedSgprsKey = getScratchSizeKey(CC) + |
| 155 | PALMD::Key::VS_NUM_USED_SGPRS - |
| 156 | PALMD::Key::VS_SCRATCH_SIZE; |
| 157 | Registers[NumUsedSgprsKey] = Val; |
| 158 | } |
| 159 | |
| 160 | // Set the scratch size in the metadata. |
| 161 | void AMDGPUPALMetadata::setScratchSize(CallingConv::ID CC, unsigned Val) { |
| 162 | Registers[getScratchSizeKey(CC)] = Val; |
| 163 | } |
| 164 | |
| 165 | // Convert the accumulated PAL metadata into an asm directive. |
| 166 | void AMDGPUPALMetadata::toString(std::string &String) { |
| 167 | String.clear(); |
| 168 | if (Registers.empty()) |
| 169 | return; |
| 170 | raw_string_ostream Stream(String); |
| 171 | Stream << '\t' << AMDGPU::PALMD::AssemblerDirective << ' '; |
| 172 | for (auto I = Registers.begin(), E = Registers.end(); I != E; ++I) { |
| 173 | if (I != Registers.begin()) |
| 174 | Stream << ','; |
| 175 | Stream << "0x" << Twine::utohexstr(I->first) << ",0x" |
| 176 | << Twine::utohexstr(I->second); |
| 177 | } |
| 178 | Stream << '\n'; |
| 179 | } |
| 180 | |
| 181 | // Convert the accumulated PAL metadata into a binary blob for writing as |
| 182 | // a .note record of the specified AMD type. |
| 183 | void AMDGPUPALMetadata::toBlob(unsigned Type, std::string &Blob) { |
| 184 | Blob.clear(); |
| 185 | if (Type != ELF::NT_AMD_AMDGPU_PAL_METADATA) |
| 186 | return; |
| 187 | if (Registers.empty()) |
| 188 | return; |
| 189 | raw_string_ostream OS(Blob); |
| 190 | support::endian::Writer EW(OS, support::endianness::little); |
| 191 | for (auto I : Registers) { |
| 192 | EW.write(uint32_t(I.first)); |
| 193 | EW.write(uint32_t(I.second)); |
| 194 | } |
| 195 | } |
| 196 | |