xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/AMDGPU/AMDGPUAsmPrinter.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1480093f4SDimitry Andric //===-- AMDGPUAsmPrinter.cpp - AMDGPU assembly printer --------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric /// \file
100b57cec5SDimitry Andric ///
110b57cec5SDimitry Andric /// The AMDGPUAsmPrinter is used to print both assembly string and also binary
120b57cec5SDimitry Andric /// code.  When passed an MCAsmStreamer it prints assembly and when passed
130b57cec5SDimitry Andric /// an MCObjectStreamer it outputs binary code.
140b57cec5SDimitry Andric //
150b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
160b57cec5SDimitry Andric //
170b57cec5SDimitry Andric 
180b57cec5SDimitry Andric #include "AMDGPUAsmPrinter.h"
190b57cec5SDimitry Andric #include "AMDGPU.h"
20e8d8bef9SDimitry Andric #include "AMDGPUHSAMetadataStreamer.h"
21fe6060f1SDimitry Andric #include "AMDGPUResourceUsageAnalysis.h"
22e8d8bef9SDimitry Andric #include "GCNSubtarget.h"
230b57cec5SDimitry Andric #include "MCTargetDesc/AMDGPUInstPrinter.h"
24*0fca6ea1SDimitry Andric #include "MCTargetDesc/AMDGPUMCExpr.h"
25*0fca6ea1SDimitry Andric #include "MCTargetDesc/AMDGPUMCKernelDescriptor.h"
260b57cec5SDimitry Andric #include "MCTargetDesc/AMDGPUTargetStreamer.h"
270b57cec5SDimitry Andric #include "R600AsmPrinter.h"
280b57cec5SDimitry Andric #include "SIMachineFunctionInfo.h"
290b57cec5SDimitry Andric #include "TargetInfo/AMDGPUTargetInfo.h"
300b57cec5SDimitry Andric #include "Utils/AMDGPUBaseInfo.h"
31*0fca6ea1SDimitry Andric #include "Utils/AMDKernelCodeTUtils.h"
32*0fca6ea1SDimitry Andric #include "Utils/SIDefinesUtils.h"
33fcaf7f86SDimitry Andric #include "llvm/Analysis/OptimizationRemarkEmitter.h"
3481ad6265SDimitry Andric #include "llvm/BinaryFormat/ELF.h"
3581ad6265SDimitry Andric #include "llvm/CodeGen/MachineFrameInfo.h"
36fcaf7f86SDimitry Andric #include "llvm/CodeGen/MachineOptimizationRemarkEmitter.h"
370b57cec5SDimitry Andric #include "llvm/IR/DiagnosticInfo.h"
380b57cec5SDimitry Andric #include "llvm/MC/MCAssembler.h"
390b57cec5SDimitry Andric #include "llvm/MC/MCContext.h"
400b57cec5SDimitry Andric #include "llvm/MC/MCSectionELF.h"
410b57cec5SDimitry Andric #include "llvm/MC/MCStreamer.h"
42349cc55cSDimitry Andric #include "llvm/MC/TargetRegistry.h"
43e8d8bef9SDimitry Andric #include "llvm/Support/AMDHSAKernelDescriptor.h"
440b57cec5SDimitry Andric #include "llvm/Target/TargetLoweringObjectFile.h"
45e8d8bef9SDimitry Andric #include "llvm/Target/TargetMachine.h"
4606c3fb27SDimitry Andric #include "llvm/TargetParser/TargetParser.h"
470b57cec5SDimitry Andric 
480b57cec5SDimitry Andric using namespace llvm;
490b57cec5SDimitry Andric using namespace llvm::AMDGPU;
500b57cec5SDimitry Andric 
515ffd83dbSDimitry Andric // This should get the default rounding mode from the kernel. We just set the
525ffd83dbSDimitry Andric // default here, but this could change if the OpenCL rounding mode pragmas are
535ffd83dbSDimitry Andric // used.
540b57cec5SDimitry Andric //
550b57cec5SDimitry Andric // The denormal mode here should match what is reported by the OpenCL runtime
560b57cec5SDimitry Andric // for the CL_FP_DENORM bit from CL_DEVICE_{HALF|SINGLE|DOUBLE}_FP_CONFIG, but
570b57cec5SDimitry Andric // can also be override to flush with the -cl-denorms-are-zero compiler flag.
580b57cec5SDimitry Andric //
590b57cec5SDimitry Andric // AMD OpenCL only sets flush none and reports CL_FP_DENORM for double
600b57cec5SDimitry Andric // precision, and leaves single precision to flush all and does not report
610b57cec5SDimitry Andric // CL_FP_DENORM for CL_DEVICE_SINGLE_FP_CONFIG. Mesa's OpenCL currently reports
620b57cec5SDimitry Andric // CL_FP_DENORM for both.
630b57cec5SDimitry Andric //
640b57cec5SDimitry Andric // FIXME: It seems some instructions do not support single precision denormals
650b57cec5SDimitry Andric // regardless of the mode (exp_*_f32, rcp_*_f32, rsq_*_f32, rsq_*f32, sqrt_f32,
660b57cec5SDimitry Andric // and sin_f32, cos_f32 on most parts).
670b57cec5SDimitry Andric 
680b57cec5SDimitry Andric // We want to use these instructions, and using fp32 denormals also causes
690b57cec5SDimitry Andric // instructions to run at the double precision rate for the device so it's
700b57cec5SDimitry Andric // probably best to just report no single precision denormals.
7106c3fb27SDimitry Andric static uint32_t getFPMode(SIModeRegisterDefaults Mode) {
720b57cec5SDimitry Andric   return FP_ROUND_MODE_SP(FP_ROUND_ROUND_TO_NEAREST) |
730b57cec5SDimitry Andric          FP_ROUND_MODE_DP(FP_ROUND_ROUND_TO_NEAREST) |
745ffd83dbSDimitry Andric          FP_DENORM_MODE_SP(Mode.fpDenormModeSPValue()) |
755ffd83dbSDimitry Andric          FP_DENORM_MODE_DP(Mode.fpDenormModeDPValue());
760b57cec5SDimitry Andric }
770b57cec5SDimitry Andric 
780b57cec5SDimitry Andric static AsmPrinter *
790b57cec5SDimitry Andric createAMDGPUAsmPrinterPass(TargetMachine &tm,
800b57cec5SDimitry Andric                            std::unique_ptr<MCStreamer> &&Streamer) {
810b57cec5SDimitry Andric   return new AMDGPUAsmPrinter(tm, std::move(Streamer));
820b57cec5SDimitry Andric }
830b57cec5SDimitry Andric 
8406c3fb27SDimitry Andric extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeAMDGPUAsmPrinter() {
8506c3fb27SDimitry Andric   TargetRegistry::RegisterAsmPrinter(getTheR600Target(),
860b57cec5SDimitry Andric                                      llvm::createR600AsmPrinterPass);
870b57cec5SDimitry Andric   TargetRegistry::RegisterAsmPrinter(getTheGCNTarget(),
880b57cec5SDimitry Andric                                      createAMDGPUAsmPrinterPass);
890b57cec5SDimitry Andric }
900b57cec5SDimitry Andric 
910b57cec5SDimitry Andric AMDGPUAsmPrinter::AMDGPUAsmPrinter(TargetMachine &TM,
920b57cec5SDimitry Andric                                    std::unique_ptr<MCStreamer> Streamer)
930b57cec5SDimitry Andric     : AsmPrinter(TM, std::move(Streamer)) {
94bdd1243dSDimitry Andric   assert(OutStreamer && "AsmPrinter constructed without streamer");
950b57cec5SDimitry Andric }
960b57cec5SDimitry Andric 
970b57cec5SDimitry Andric StringRef AMDGPUAsmPrinter::getPassName() const {
980b57cec5SDimitry Andric   return "AMDGPU Assembly Printer";
990b57cec5SDimitry Andric }
1000b57cec5SDimitry Andric 
1010b57cec5SDimitry Andric const MCSubtargetInfo *AMDGPUAsmPrinter::getGlobalSTI() const {
1020b57cec5SDimitry Andric   return TM.getMCSubtargetInfo();
1030b57cec5SDimitry Andric }
1040b57cec5SDimitry Andric 
1050b57cec5SDimitry Andric AMDGPUTargetStreamer* AMDGPUAsmPrinter::getTargetStreamer() const {
1060b57cec5SDimitry Andric   if (!OutStreamer)
1070b57cec5SDimitry Andric     return nullptr;
1080b57cec5SDimitry Andric   return static_cast<AMDGPUTargetStreamer*>(OutStreamer->getTargetStreamer());
1090b57cec5SDimitry Andric }
1100b57cec5SDimitry Andric 
1115ffd83dbSDimitry Andric void AMDGPUAsmPrinter::emitStartOfAsmFile(Module &M) {
11281ad6265SDimitry Andric   IsTargetStreamerInitialized = false;
11381ad6265SDimitry Andric }
11481ad6265SDimitry Andric 
11581ad6265SDimitry Andric void AMDGPUAsmPrinter::initTargetStreamer(Module &M) {
11681ad6265SDimitry Andric   IsTargetStreamerInitialized = true;
11781ad6265SDimitry Andric 
118fe6060f1SDimitry Andric   // TODO: Which one is called first, emitStartOfAsmFile or
119fe6060f1SDimitry Andric   // emitFunctionBodyStart?
120fe6060f1SDimitry Andric   if (getTargetStreamer() && !getTargetStreamer()->getTargetID())
121fe6060f1SDimitry Andric     initializeTargetID(M);
1220b57cec5SDimitry Andric 
1230b57cec5SDimitry Andric   if (TM.getTargetTriple().getOS() != Triple::AMDHSA &&
1240b57cec5SDimitry Andric       TM.getTargetTriple().getOS() != Triple::AMDPAL)
1250b57cec5SDimitry Andric     return;
1260b57cec5SDimitry Andric 
127fe6060f1SDimitry Andric   getTargetStreamer()->EmitDirectiveAMDGCNTarget();
128fe6060f1SDimitry Andric 
1297a6dacacSDimitry Andric   if (TM.getTargetTriple().getOS() == Triple::AMDHSA) {
1307a6dacacSDimitry Andric     getTargetStreamer()->EmitDirectiveAMDHSACodeObjectVersion(
1317a6dacacSDimitry Andric         CodeObjectVersion);
132fe6060f1SDimitry Andric     HSAMetadataStream->begin(M, *getTargetStreamer()->getTargetID());
1337a6dacacSDimitry Andric   }
1340b57cec5SDimitry Andric 
1350b57cec5SDimitry Andric   if (TM.getTargetTriple().getOS() == Triple::AMDPAL)
1360b57cec5SDimitry Andric     getTargetStreamer()->getPALMetadata()->readFromIR(M);
1370b57cec5SDimitry Andric }
1380b57cec5SDimitry Andric 
1395ffd83dbSDimitry Andric void AMDGPUAsmPrinter::emitEndOfAsmFile(Module &M) {
14081ad6265SDimitry Andric   // Init target streamer if it has not yet happened
14181ad6265SDimitry Andric   if (!IsTargetStreamerInitialized)
14281ad6265SDimitry Andric     initTargetStreamer(M);
14381ad6265SDimitry Andric 
1445f757f3fSDimitry Andric   if (TM.getTargetTriple().getOS() != Triple::AMDHSA)
145fe6060f1SDimitry Andric     getTargetStreamer()->EmitISAVersion();
1460b57cec5SDimitry Andric 
1470b57cec5SDimitry Andric   // Emit HSA Metadata (NT_AMD_AMDGPU_HSA_METADATA).
148fe6060f1SDimitry Andric   // Emit HSA Metadata (NT_AMD_HSA_METADATA).
1490b57cec5SDimitry Andric   if (TM.getTargetTriple().getOS() == Triple::AMDHSA) {
1500b57cec5SDimitry Andric     HSAMetadataStream->end();
1510b57cec5SDimitry Andric     bool Success = HSAMetadataStream->emitTo(*getTargetStreamer());
1520b57cec5SDimitry Andric     (void)Success;
1530b57cec5SDimitry Andric     assert(Success && "Malformed HSA Metadata");
1540b57cec5SDimitry Andric   }
1550b57cec5SDimitry Andric }
1560b57cec5SDimitry Andric 
1575ffd83dbSDimitry Andric void AMDGPUAsmPrinter::emitFunctionBodyStart() {
1580b57cec5SDimitry Andric   const SIMachineFunctionInfo &MFI = *MF->getInfo<SIMachineFunctionInfo>();
159fe6060f1SDimitry Andric   const GCNSubtarget &STM = MF->getSubtarget<GCNSubtarget>();
160fe6060f1SDimitry Andric   const Function &F = MF->getFunction();
161fe6060f1SDimitry Andric 
162*0fca6ea1SDimitry Andric   // TODO: We're checking this late, would be nice to check it earlier.
163*0fca6ea1SDimitry Andric   if (STM.requiresCodeObjectV6() && CodeObjectVersion < AMDGPU::AMDHSA_COV6) {
164*0fca6ea1SDimitry Andric     report_fatal_error(
165*0fca6ea1SDimitry Andric         STM.getCPU() + " is only available on code object version 6 or better",
166*0fca6ea1SDimitry Andric         /*gen_crash_diag*/ false);
167*0fca6ea1SDimitry Andric   }
168*0fca6ea1SDimitry Andric 
169fe6060f1SDimitry Andric   // TODO: Which one is called first, emitStartOfAsmFile or
170fe6060f1SDimitry Andric   // emitFunctionBodyStart?
171bdd1243dSDimitry Andric   if (!getTargetStreamer()->getTargetID())
172fe6060f1SDimitry Andric     initializeTargetID(*F.getParent());
173fe6060f1SDimitry Andric 
174fe6060f1SDimitry Andric   const auto &FunctionTargetID = STM.getTargetID();
175fe6060f1SDimitry Andric   // Make sure function's xnack settings are compatible with module's
176fe6060f1SDimitry Andric   // xnack settings.
177fe6060f1SDimitry Andric   if (FunctionTargetID.isXnackSupported() &&
178fe6060f1SDimitry Andric       FunctionTargetID.getXnackSetting() != IsaInfo::TargetIDSetting::Any &&
179fe6060f1SDimitry Andric       FunctionTargetID.getXnackSetting() != getTargetStreamer()->getTargetID()->getXnackSetting()) {
180fe6060f1SDimitry Andric     OutContext.reportError({}, "xnack setting of '" + Twine(MF->getName()) +
181fe6060f1SDimitry Andric                            "' function does not match module xnack setting");
182fe6060f1SDimitry Andric     return;
183fe6060f1SDimitry Andric   }
184fe6060f1SDimitry Andric   // Make sure function's sramecc settings are compatible with module's
185fe6060f1SDimitry Andric   // sramecc settings.
186fe6060f1SDimitry Andric   if (FunctionTargetID.isSramEccSupported() &&
187fe6060f1SDimitry Andric       FunctionTargetID.getSramEccSetting() != IsaInfo::TargetIDSetting::Any &&
188fe6060f1SDimitry Andric       FunctionTargetID.getSramEccSetting() != getTargetStreamer()->getTargetID()->getSramEccSetting()) {
189fe6060f1SDimitry Andric     OutContext.reportError({}, "sramecc setting of '" + Twine(MF->getName()) +
190fe6060f1SDimitry Andric                            "' function does not match module sramecc setting");
191fe6060f1SDimitry Andric     return;
192fe6060f1SDimitry Andric   }
193fe6060f1SDimitry Andric 
1940b57cec5SDimitry Andric   if (!MFI.isEntryFunction())
1950b57cec5SDimitry Andric     return;
1960b57cec5SDimitry Andric 
1975f757f3fSDimitry Andric   if (STM.isMesaKernel(F) &&
1980b57cec5SDimitry Andric       (F.getCallingConv() == CallingConv::AMDGPU_KERNEL ||
1990b57cec5SDimitry Andric        F.getCallingConv() == CallingConv::SPIR_KERNEL)) {
200*0fca6ea1SDimitry Andric     AMDGPUMCKernelCodeT KernelCode;
2010b57cec5SDimitry Andric     getAmdKernelCode(KernelCode, CurrentProgramInfo, *MF);
202*0fca6ea1SDimitry Andric     KernelCode.validate(&STM, MF->getContext());
2030b57cec5SDimitry Andric     getTargetStreamer()->EmitAMDKernelCodeT(KernelCode);
2040b57cec5SDimitry Andric   }
2050b57cec5SDimitry Andric 
2060b57cec5SDimitry Andric   if (STM.isAmdHsaOS())
2070b57cec5SDimitry Andric     HSAMetadataStream->emitKernel(*MF, CurrentProgramInfo);
2085f757f3fSDimitry Andric 
2095f757f3fSDimitry Andric   if (MFI.getNumKernargPreloadedSGPRs() > 0) {
2105f757f3fSDimitry Andric     assert(AMDGPU::hasKernargPreload(STM));
211*0fca6ea1SDimitry Andric     getTargetStreamer()->EmitKernargPreloadHeader(*getGlobalSTI(),
212*0fca6ea1SDimitry Andric                                                   STM.isAmdHsaOS());
2135f757f3fSDimitry Andric   }
2140b57cec5SDimitry Andric }
2150b57cec5SDimitry Andric 
2165ffd83dbSDimitry Andric void AMDGPUAsmPrinter::emitFunctionBodyEnd() {
2170b57cec5SDimitry Andric   const SIMachineFunctionInfo &MFI = *MF->getInfo<SIMachineFunctionInfo>();
2180b57cec5SDimitry Andric   if (!MFI.isEntryFunction())
2190b57cec5SDimitry Andric     return;
2200b57cec5SDimitry Andric 
2215f757f3fSDimitry Andric   if (TM.getTargetTriple().getOS() != Triple::AMDHSA)
2220b57cec5SDimitry Andric     return;
2230b57cec5SDimitry Andric 
2240b57cec5SDimitry Andric   auto &Streamer = getTargetStreamer()->getStreamer();
2250b57cec5SDimitry Andric   auto &Context = Streamer.getContext();
2260b57cec5SDimitry Andric   auto &ObjectFileInfo = *Context.getObjectFileInfo();
2270b57cec5SDimitry Andric   auto &ReadOnlySection = *ObjectFileInfo.getReadOnlySection();
2280b57cec5SDimitry Andric 
22981ad6265SDimitry Andric   Streamer.pushSection();
23081ad6265SDimitry Andric   Streamer.switchSection(&ReadOnlySection);
2310b57cec5SDimitry Andric 
2320b57cec5SDimitry Andric   // CP microcode requires the kernel descriptor to be allocated on 64 byte
2330b57cec5SDimitry Andric   // alignment.
234bdd1243dSDimitry Andric   Streamer.emitValueToAlignment(Align(64), 0, 1, 0);
235bdd1243dSDimitry Andric   ReadOnlySection.ensureMinAlignment(Align(64));
2360b57cec5SDimitry Andric 
237fe6060f1SDimitry Andric   const GCNSubtarget &STM = MF->getSubtarget<GCNSubtarget>();
2380b57cec5SDimitry Andric 
2390b57cec5SDimitry Andric   SmallString<128> KernelName;
2400b57cec5SDimitry Andric   getNameWithPrefix(KernelName, &MF->getFunction());
2410b57cec5SDimitry Andric   getTargetStreamer()->EmitAmdhsaKernelDescriptor(
242fe6060f1SDimitry Andric       STM, KernelName, getAmdhsaKernelDescriptor(*MF, CurrentProgramInfo),
2430b57cec5SDimitry Andric       CurrentProgramInfo.NumVGPRsForWavesPerEU,
244*0fca6ea1SDimitry Andric       MCBinaryExpr::createSub(
245*0fca6ea1SDimitry Andric           CurrentProgramInfo.NumSGPRsForWavesPerEU,
246*0fca6ea1SDimitry Andric           AMDGPUMCExpr::createExtraSGPRs(
247*0fca6ea1SDimitry Andric               CurrentProgramInfo.VCCUsed, CurrentProgramInfo.FlatUsed,
248*0fca6ea1SDimitry Andric               getTargetStreamer()->getTargetID()->isXnackOnOrAny(), Context),
249*0fca6ea1SDimitry Andric           Context),
2507a6dacacSDimitry Andric       CurrentProgramInfo.VCCUsed, CurrentProgramInfo.FlatUsed);
2510b57cec5SDimitry Andric 
25281ad6265SDimitry Andric   Streamer.popSection();
2530b57cec5SDimitry Andric }
2540b57cec5SDimitry Andric 
2555f757f3fSDimitry Andric void AMDGPUAsmPrinter::emitImplicitDef(const MachineInstr *MI) const {
2565f757f3fSDimitry Andric   Register RegNo = MI->getOperand(0).getReg();
2575f757f3fSDimitry Andric 
2585f757f3fSDimitry Andric   SmallString<128> Str;
2595f757f3fSDimitry Andric   raw_svector_ostream OS(Str);
2605f757f3fSDimitry Andric   OS << "implicit-def: "
2615f757f3fSDimitry Andric      << printReg(RegNo, MF->getSubtarget().getRegisterInfo());
2625f757f3fSDimitry Andric 
2635f757f3fSDimitry Andric   if (MI->getAsmPrinterFlags() & AMDGPU::SGPR_SPILL)
2645f757f3fSDimitry Andric     OS << " : SGPR spill to VGPR lane";
2655f757f3fSDimitry Andric 
2665f757f3fSDimitry Andric   OutStreamer->AddComment(OS.str());
2675f757f3fSDimitry Andric   OutStreamer->addBlankLine();
2685f757f3fSDimitry Andric }
2695f757f3fSDimitry Andric 
2705ffd83dbSDimitry Andric void AMDGPUAsmPrinter::emitFunctionEntryLabel() {
2715f757f3fSDimitry Andric   if (TM.getTargetTriple().getOS() == Triple::AMDHSA) {
2725ffd83dbSDimitry Andric     AsmPrinter::emitFunctionEntryLabel();
2730b57cec5SDimitry Andric     return;
2740b57cec5SDimitry Andric   }
2750b57cec5SDimitry Andric 
2760b57cec5SDimitry Andric   const SIMachineFunctionInfo *MFI = MF->getInfo<SIMachineFunctionInfo>();
2770b57cec5SDimitry Andric   const GCNSubtarget &STM = MF->getSubtarget<GCNSubtarget>();
2780b57cec5SDimitry Andric   if (MFI->isEntryFunction() && STM.isAmdHsaOrMesa(MF->getFunction())) {
2790b57cec5SDimitry Andric     SmallString<128> SymbolName;
2800b57cec5SDimitry Andric     getNameWithPrefix(SymbolName, &MF->getFunction()),
2810b57cec5SDimitry Andric     getTargetStreamer()->EmitAMDGPUSymbolType(
2820b57cec5SDimitry Andric         SymbolName, ELF::STT_AMDGPU_HSA_KERNEL);
2830b57cec5SDimitry Andric   }
2840b57cec5SDimitry Andric   if (DumpCodeInstEmitter) {
2850b57cec5SDimitry Andric     // Disassemble function name label to text.
2860b57cec5SDimitry Andric     DisasmLines.push_back(MF->getName().str() + ":");
2870b57cec5SDimitry Andric     DisasmLineMaxLen = std::max(DisasmLineMaxLen, DisasmLines.back().size());
288*0fca6ea1SDimitry Andric     HexLines.emplace_back("");
2890b57cec5SDimitry Andric   }
2900b57cec5SDimitry Andric 
2915ffd83dbSDimitry Andric   AsmPrinter::emitFunctionEntryLabel();
2920b57cec5SDimitry Andric }
2930b57cec5SDimitry Andric 
2945ffd83dbSDimitry Andric void AMDGPUAsmPrinter::emitBasicBlockStart(const MachineBasicBlock &MBB) {
2950b57cec5SDimitry Andric   if (DumpCodeInstEmitter && !isBlockOnlyReachableByFallthrough(&MBB)) {
2960b57cec5SDimitry Andric     // Write a line for the basic block label if it is not only fallthrough.
2970b57cec5SDimitry Andric     DisasmLines.push_back(
2980b57cec5SDimitry Andric         (Twine("BB") + Twine(getFunctionNumber())
2990b57cec5SDimitry Andric          + "_" + Twine(MBB.getNumber()) + ":").str());
3000b57cec5SDimitry Andric     DisasmLineMaxLen = std::max(DisasmLineMaxLen, DisasmLines.back().size());
301*0fca6ea1SDimitry Andric     HexLines.emplace_back("");
3020b57cec5SDimitry Andric   }
3035ffd83dbSDimitry Andric   AsmPrinter::emitBasicBlockStart(MBB);
3040b57cec5SDimitry Andric }
3050b57cec5SDimitry Andric 
3065ffd83dbSDimitry Andric void AMDGPUAsmPrinter::emitGlobalVariable(const GlobalVariable *GV) {
3070b57cec5SDimitry Andric   if (GV->getAddressSpace() == AMDGPUAS::LOCAL_ADDRESS) {
3080b57cec5SDimitry Andric     if (GV->hasInitializer() && !isa<UndefValue>(GV->getInitializer())) {
3090b57cec5SDimitry Andric       OutContext.reportError({},
3100b57cec5SDimitry Andric                              Twine(GV->getName()) +
3110b57cec5SDimitry Andric                                  ": unsupported initializer for address space");
3120b57cec5SDimitry Andric       return;
3130b57cec5SDimitry Andric     }
3140b57cec5SDimitry Andric 
3150b57cec5SDimitry Andric     // LDS variables aren't emitted in HSA or PAL yet.
3160b57cec5SDimitry Andric     const Triple::OSType OS = TM.getTargetTriple().getOS();
3170b57cec5SDimitry Andric     if (OS == Triple::AMDHSA || OS == Triple::AMDPAL)
3180b57cec5SDimitry Andric       return;
3190b57cec5SDimitry Andric 
3200b57cec5SDimitry Andric     MCSymbol *GVSym = getSymbol(GV);
3210b57cec5SDimitry Andric 
3220b57cec5SDimitry Andric     GVSym->redefineIfPossible();
3230b57cec5SDimitry Andric     if (GVSym->isDefined() || GVSym->isVariable())
3240b57cec5SDimitry Andric       report_fatal_error("symbol '" + Twine(GVSym->getName()) +
3250b57cec5SDimitry Andric                          "' is already defined");
3260b57cec5SDimitry Andric 
327*0fca6ea1SDimitry Andric     const DataLayout &DL = GV->getDataLayout();
3280b57cec5SDimitry Andric     uint64_t Size = DL.getTypeAllocSize(GV->getValueType());
32981ad6265SDimitry Andric     Align Alignment = GV->getAlign().value_or(Align(4));
3300b57cec5SDimitry Andric 
3315ffd83dbSDimitry Andric     emitVisibility(GVSym, GV->getVisibility(), !GV->isDeclaration());
3325ffd83dbSDimitry Andric     emitLinkage(GV, GVSym);
333bdd1243dSDimitry Andric     auto TS = getTargetStreamer();
3345ffd83dbSDimitry Andric     TS->emitAMDGPULDS(GVSym, Size, Alignment);
3350b57cec5SDimitry Andric     return;
3360b57cec5SDimitry Andric   }
3370b57cec5SDimitry Andric 
3385ffd83dbSDimitry Andric   AsmPrinter::emitGlobalVariable(GV);
3390b57cec5SDimitry Andric }
3400b57cec5SDimitry Andric 
34106c3fb27SDimitry Andric bool AMDGPUAsmPrinter::doInitialization(Module &M) {
3427a6dacacSDimitry Andric   CodeObjectVersion = AMDGPU::getAMDHSACodeObjectVersion(M);
34306c3fb27SDimitry Andric 
34406c3fb27SDimitry Andric   if (TM.getTargetTriple().getOS() == Triple::AMDHSA) {
34506c3fb27SDimitry Andric     switch (CodeObjectVersion) {
34606c3fb27SDimitry Andric     case AMDGPU::AMDHSA_COV4:
347*0fca6ea1SDimitry Andric       HSAMetadataStream = std::make_unique<HSAMD::MetadataStreamerMsgPackV4>();
34806c3fb27SDimitry Andric       break;
34906c3fb27SDimitry Andric     case AMDGPU::AMDHSA_COV5:
350*0fca6ea1SDimitry Andric       HSAMetadataStream = std::make_unique<HSAMD::MetadataStreamerMsgPackV5>();
351*0fca6ea1SDimitry Andric       break;
352*0fca6ea1SDimitry Andric     case AMDGPU::AMDHSA_COV6:
353*0fca6ea1SDimitry Andric       HSAMetadataStream = std::make_unique<HSAMD::MetadataStreamerMsgPackV6>();
35406c3fb27SDimitry Andric       break;
35506c3fb27SDimitry Andric     default:
35606c3fb27SDimitry Andric       report_fatal_error("Unexpected code object version");
35706c3fb27SDimitry Andric     }
35806c3fb27SDimitry Andric   }
35906c3fb27SDimitry Andric   return AsmPrinter::doInitialization(M);
36006c3fb27SDimitry Andric }
36106c3fb27SDimitry Andric 
3620b57cec5SDimitry Andric bool AMDGPUAsmPrinter::doFinalization(Module &M) {
3630b57cec5SDimitry Andric   // Pad with s_code_end to help tools and guard against instruction prefetch
3640b57cec5SDimitry Andric   // causing stale data in caches. Arguably this should be done by the linker,
3650b57cec5SDimitry Andric   // which is why this isn't done for Mesa.
3660b57cec5SDimitry Andric   const MCSubtargetInfo &STI = *getGlobalSTI();
367fe6060f1SDimitry Andric   if ((AMDGPU::isGFX10Plus(STI) || AMDGPU::isGFX90A(STI)) &&
3680b57cec5SDimitry Andric       (STI.getTargetTriple().getOS() == Triple::AMDHSA ||
3690b57cec5SDimitry Andric        STI.getTargetTriple().getOS() == Triple::AMDPAL)) {
37081ad6265SDimitry Andric     OutStreamer->switchSection(getObjFileLowering().getTextSection());
371fe6060f1SDimitry Andric     getTargetStreamer()->EmitCodeEnd(STI);
3720b57cec5SDimitry Andric   }
3730b57cec5SDimitry Andric 
3740b57cec5SDimitry Andric   return AsmPrinter::doFinalization(M);
3750b57cec5SDimitry Andric }
3760b57cec5SDimitry Andric 
3770b57cec5SDimitry Andric // Print comments that apply to both callable functions and entry points.
3780b57cec5SDimitry Andric void AMDGPUAsmPrinter::emitCommonFunctionComments(
379bdd1243dSDimitry Andric     uint32_t NumVGPR, std::optional<uint32_t> NumAGPR, uint32_t TotalNumVGPR,
380bdd1243dSDimitry Andric     uint32_t NumSGPR, uint64_t ScratchSize, uint64_t CodeSize,
3810b57cec5SDimitry Andric     const AMDGPUMachineFunction *MFI) {
3820b57cec5SDimitry Andric   OutStreamer->emitRawComment(" codeLenInByte = " + Twine(CodeSize), false);
3830b57cec5SDimitry Andric   OutStreamer->emitRawComment(" NumSgprs: " + Twine(NumSGPR), false);
3840b57cec5SDimitry Andric   OutStreamer->emitRawComment(" NumVgprs: " + Twine(NumVGPR), false);
3858bcb0991SDimitry Andric   if (NumAGPR) {
3868bcb0991SDimitry Andric     OutStreamer->emitRawComment(" NumAgprs: " + Twine(*NumAGPR), false);
3878bcb0991SDimitry Andric     OutStreamer->emitRawComment(" TotalNumVgprs: " + Twine(TotalNumVGPR),
3888bcb0991SDimitry Andric                                 false);
3898bcb0991SDimitry Andric   }
3900b57cec5SDimitry Andric   OutStreamer->emitRawComment(" ScratchSize: " + Twine(ScratchSize), false);
3910b57cec5SDimitry Andric   OutStreamer->emitRawComment(" MemoryBound: " + Twine(MFI->isMemoryBound()),
3920b57cec5SDimitry Andric                               false);
3930b57cec5SDimitry Andric }
3940b57cec5SDimitry Andric 
395*0fca6ea1SDimitry Andric SmallString<128> AMDGPUAsmPrinter::getMCExprStr(const MCExpr *Value) {
396*0fca6ea1SDimitry Andric   SmallString<128> Str;
397*0fca6ea1SDimitry Andric   raw_svector_ostream OSS(Str);
398*0fca6ea1SDimitry Andric   int64_t IVal;
399*0fca6ea1SDimitry Andric   if (Value->evaluateAsAbsolute(IVal)) {
400*0fca6ea1SDimitry Andric     OSS << static_cast<uint64_t>(IVal);
401*0fca6ea1SDimitry Andric   } else {
402*0fca6ea1SDimitry Andric     Value->print(OSS, MAI);
403*0fca6ea1SDimitry Andric   }
404*0fca6ea1SDimitry Andric   return Str;
405*0fca6ea1SDimitry Andric }
406*0fca6ea1SDimitry Andric 
407*0fca6ea1SDimitry Andric void AMDGPUAsmPrinter::emitCommonFunctionComments(
408*0fca6ea1SDimitry Andric     const MCExpr *NumVGPR, const MCExpr *NumAGPR, const MCExpr *TotalNumVGPR,
409*0fca6ea1SDimitry Andric     const MCExpr *NumSGPR, const MCExpr *ScratchSize, uint64_t CodeSize,
410*0fca6ea1SDimitry Andric     const AMDGPUMachineFunction *MFI) {
411*0fca6ea1SDimitry Andric   OutStreamer->emitRawComment(" codeLenInByte = " + Twine(CodeSize), false);
412*0fca6ea1SDimitry Andric   OutStreamer->emitRawComment(" NumSgprs: " + getMCExprStr(NumSGPR), false);
413*0fca6ea1SDimitry Andric   OutStreamer->emitRawComment(" NumVgprs: " + getMCExprStr(NumVGPR), false);
414*0fca6ea1SDimitry Andric   if (NumAGPR && TotalNumVGPR) {
415*0fca6ea1SDimitry Andric     OutStreamer->emitRawComment(" NumAgprs: " + getMCExprStr(NumAGPR), false);
416*0fca6ea1SDimitry Andric     OutStreamer->emitRawComment(" TotalNumVgprs: " + getMCExprStr(TotalNumVGPR),
417*0fca6ea1SDimitry Andric                                 false);
418*0fca6ea1SDimitry Andric   }
419*0fca6ea1SDimitry Andric   OutStreamer->emitRawComment(" ScratchSize: " + getMCExprStr(ScratchSize),
420*0fca6ea1SDimitry Andric                               false);
421*0fca6ea1SDimitry Andric   OutStreamer->emitRawComment(" MemoryBound: " + Twine(MFI->isMemoryBound()),
422*0fca6ea1SDimitry Andric                               false);
423*0fca6ea1SDimitry Andric }
424*0fca6ea1SDimitry Andric 
425*0fca6ea1SDimitry Andric const MCExpr *AMDGPUAsmPrinter::getAmdhsaKernelCodeProperties(
4260b57cec5SDimitry Andric     const MachineFunction &MF) const {
4270b57cec5SDimitry Andric   const SIMachineFunctionInfo &MFI = *MF.getInfo<SIMachineFunctionInfo>();
428*0fca6ea1SDimitry Andric   MCContext &Ctx = MF.getContext();
4290b57cec5SDimitry Andric   uint16_t KernelCodeProperties = 0;
4305f757f3fSDimitry Andric   const GCNUserSGPRUsageInfo &UserSGPRInfo = MFI.getUserSGPRInfo();
4310b57cec5SDimitry Andric 
4325f757f3fSDimitry Andric   if (UserSGPRInfo.hasPrivateSegmentBuffer()) {
4330b57cec5SDimitry Andric     KernelCodeProperties |=
4340b57cec5SDimitry Andric         amdhsa::KERNEL_CODE_PROPERTY_ENABLE_SGPR_PRIVATE_SEGMENT_BUFFER;
4350b57cec5SDimitry Andric   }
4365f757f3fSDimitry Andric   if (UserSGPRInfo.hasDispatchPtr()) {
4370b57cec5SDimitry Andric     KernelCodeProperties |=
4380b57cec5SDimitry Andric         amdhsa::KERNEL_CODE_PROPERTY_ENABLE_SGPR_DISPATCH_PTR;
4390b57cec5SDimitry Andric   }
4405f757f3fSDimitry Andric   if (UserSGPRInfo.hasQueuePtr() && CodeObjectVersion < AMDGPU::AMDHSA_COV5) {
4410b57cec5SDimitry Andric     KernelCodeProperties |=
4420b57cec5SDimitry Andric         amdhsa::KERNEL_CODE_PROPERTY_ENABLE_SGPR_QUEUE_PTR;
4430b57cec5SDimitry Andric   }
4445f757f3fSDimitry Andric   if (UserSGPRInfo.hasKernargSegmentPtr()) {
4450b57cec5SDimitry Andric     KernelCodeProperties |=
4460b57cec5SDimitry Andric         amdhsa::KERNEL_CODE_PROPERTY_ENABLE_SGPR_KERNARG_SEGMENT_PTR;
4470b57cec5SDimitry Andric   }
4485f757f3fSDimitry Andric   if (UserSGPRInfo.hasDispatchID()) {
4490b57cec5SDimitry Andric     KernelCodeProperties |=
4500b57cec5SDimitry Andric         amdhsa::KERNEL_CODE_PROPERTY_ENABLE_SGPR_DISPATCH_ID;
4510b57cec5SDimitry Andric   }
4525f757f3fSDimitry Andric   if (UserSGPRInfo.hasFlatScratchInit()) {
4530b57cec5SDimitry Andric     KernelCodeProperties |=
4540b57cec5SDimitry Andric         amdhsa::KERNEL_CODE_PROPERTY_ENABLE_SGPR_FLAT_SCRATCH_INIT;
4550b57cec5SDimitry Andric   }
456*0fca6ea1SDimitry Andric   if (UserSGPRInfo.hasPrivateSegmentSize()) {
457*0fca6ea1SDimitry Andric     KernelCodeProperties |=
458*0fca6ea1SDimitry Andric         amdhsa::KERNEL_CODE_PROPERTY_ENABLE_SGPR_PRIVATE_SEGMENT_SIZE;
459*0fca6ea1SDimitry Andric   }
4600b57cec5SDimitry Andric   if (MF.getSubtarget<GCNSubtarget>().isWave32()) {
4610b57cec5SDimitry Andric     KernelCodeProperties |=
4620b57cec5SDimitry Andric         amdhsa::KERNEL_CODE_PROPERTY_ENABLE_WAVEFRONT_SIZE32;
4630b57cec5SDimitry Andric   }
4640b57cec5SDimitry Andric 
465*0fca6ea1SDimitry Andric   // CurrentProgramInfo.DynamicCallStack is a MCExpr and could be
466*0fca6ea1SDimitry Andric   // un-evaluatable at this point so it cannot be conditionally checked here.
467*0fca6ea1SDimitry Andric   // Instead, we'll directly shift the possibly unknown MCExpr into its place
468*0fca6ea1SDimitry Andric   // and bitwise-or it into KernelCodeProperties.
469*0fca6ea1SDimitry Andric   const MCExpr *KernelCodePropExpr =
470*0fca6ea1SDimitry Andric       MCConstantExpr::create(KernelCodeProperties, Ctx);
471*0fca6ea1SDimitry Andric   const MCExpr *OrValue = MCConstantExpr::create(
472*0fca6ea1SDimitry Andric       amdhsa::KERNEL_CODE_PROPERTY_USES_DYNAMIC_STACK_SHIFT, Ctx);
473*0fca6ea1SDimitry Andric   OrValue = MCBinaryExpr::createShl(CurrentProgramInfo.DynamicCallStack,
474*0fca6ea1SDimitry Andric                                     OrValue, Ctx);
475*0fca6ea1SDimitry Andric   KernelCodePropExpr = MCBinaryExpr::createOr(KernelCodePropExpr, OrValue, Ctx);
476fcaf7f86SDimitry Andric 
477*0fca6ea1SDimitry Andric   return KernelCodePropExpr;
4780b57cec5SDimitry Andric }
4790b57cec5SDimitry Andric 
480*0fca6ea1SDimitry Andric MCKernelDescriptor
481*0fca6ea1SDimitry Andric AMDGPUAsmPrinter::getAmdhsaKernelDescriptor(const MachineFunction &MF,
4820b57cec5SDimitry Andric                                             const SIProgramInfo &PI) const {
483fe6060f1SDimitry Andric   const GCNSubtarget &STM = MF.getSubtarget<GCNSubtarget>();
484fe6060f1SDimitry Andric   const Function &F = MF.getFunction();
4855f757f3fSDimitry Andric   const SIMachineFunctionInfo *Info = MF.getInfo<SIMachineFunctionInfo>();
486*0fca6ea1SDimitry Andric   MCContext &Ctx = MF.getContext();
487fe6060f1SDimitry Andric 
488*0fca6ea1SDimitry Andric   MCKernelDescriptor KernelDescriptor;
4890b57cec5SDimitry Andric 
490*0fca6ea1SDimitry Andric   KernelDescriptor.group_segment_fixed_size =
491*0fca6ea1SDimitry Andric       MCConstantExpr::create(PI.LDSSize, Ctx);
4920b57cec5SDimitry Andric   KernelDescriptor.private_segment_fixed_size = PI.ScratchSize;
493fe6060f1SDimitry Andric 
494fe6060f1SDimitry Andric   Align MaxKernArgAlign;
495*0fca6ea1SDimitry Andric   KernelDescriptor.kernarg_size = MCConstantExpr::create(
496*0fca6ea1SDimitry Andric       STM.getKernArgSegmentSize(F, MaxKernArgAlign), Ctx);
497fe6060f1SDimitry Andric 
498*0fca6ea1SDimitry Andric   KernelDescriptor.compute_pgm_rsrc1 = PI.getComputePGMRSrc1(STM, Ctx);
499*0fca6ea1SDimitry Andric   KernelDescriptor.compute_pgm_rsrc2 = PI.getComputePGMRSrc2(Ctx);
5000b57cec5SDimitry Andric   KernelDescriptor.kernel_code_properties = getAmdhsaKernelCodeProperties(MF);
5010b57cec5SDimitry Andric 
502*0fca6ea1SDimitry Andric   int64_t PGRM_Rsrc3 = 1;
503*0fca6ea1SDimitry Andric   bool EvaluatableRsrc3 =
504*0fca6ea1SDimitry Andric       CurrentProgramInfo.ComputePGMRSrc3GFX90A->evaluateAsAbsolute(PGRM_Rsrc3);
505*0fca6ea1SDimitry Andric   (void)PGRM_Rsrc3;
506*0fca6ea1SDimitry Andric   (void)EvaluatableRsrc3;
507*0fca6ea1SDimitry Andric   assert(STM.hasGFX90AInsts() || !EvaluatableRsrc3 ||
508*0fca6ea1SDimitry Andric          static_cast<uint64_t>(PGRM_Rsrc3) == 0);
509*0fca6ea1SDimitry Andric   KernelDescriptor.compute_pgm_rsrc3 = CurrentProgramInfo.ComputePGMRSrc3GFX90A;
510fe6060f1SDimitry Andric 
511*0fca6ea1SDimitry Andric   KernelDescriptor.kernarg_preload = MCConstantExpr::create(
512*0fca6ea1SDimitry Andric       AMDGPU::hasKernargPreload(STM) ? Info->getNumKernargPreloadedSGPRs() : 0,
513*0fca6ea1SDimitry Andric       Ctx);
5145f757f3fSDimitry Andric 
5150b57cec5SDimitry Andric   return KernelDescriptor;
5160b57cec5SDimitry Andric }
5170b57cec5SDimitry Andric 
5180b57cec5SDimitry Andric bool AMDGPUAsmPrinter::runOnMachineFunction(MachineFunction &MF) {
51981ad6265SDimitry Andric   // Init target streamer lazily on the first function so that previous passes
52081ad6265SDimitry Andric   // can set metadata.
52181ad6265SDimitry Andric   if (!IsTargetStreamerInitialized)
52281ad6265SDimitry Andric     initTargetStreamer(*MF.getFunction().getParent());
52381ad6265SDimitry Andric 
524fe6060f1SDimitry Andric   ResourceUsage = &getAnalysis<AMDGPUResourceUsageAnalysis>();
525*0fca6ea1SDimitry Andric   CurrentProgramInfo.reset(MF);
5260b57cec5SDimitry Andric 
5270b57cec5SDimitry Andric   const AMDGPUMachineFunction *MFI = MF.getInfo<AMDGPUMachineFunction>();
528*0fca6ea1SDimitry Andric   MCContext &Ctx = MF.getContext();
5290b57cec5SDimitry Andric 
5300b57cec5SDimitry Andric   // The starting address of all shader programs must be 256 bytes aligned.
5310b57cec5SDimitry Andric   // Regular functions just need the basic required instruction alignment.
5328bcb0991SDimitry Andric   MF.setAlignment(MFI->isEntryFunction() ? Align(256) : Align(4));
5330b57cec5SDimitry Andric 
5340b57cec5SDimitry Andric   SetupMachineFunction(MF);
5350b57cec5SDimitry Andric 
5360b57cec5SDimitry Andric   const GCNSubtarget &STM = MF.getSubtarget<GCNSubtarget>();
5370b57cec5SDimitry Andric   MCContext &Context = getObjFileLowering().getContext();
5380b57cec5SDimitry Andric   // FIXME: This should be an explicit check for Mesa.
5390b57cec5SDimitry Andric   if (!STM.isAmdHsaOS() && !STM.isAmdPalOS()) {
5400b57cec5SDimitry Andric     MCSectionELF *ConfigSection =
5410b57cec5SDimitry Andric         Context.getELFSection(".AMDGPU.config", ELF::SHT_PROGBITS, 0);
54281ad6265SDimitry Andric     OutStreamer->switchSection(ConfigSection);
5430b57cec5SDimitry Andric   }
5440b57cec5SDimitry Andric 
545e8d8bef9SDimitry Andric   if (MFI->isModuleEntryFunction()) {
5460b57cec5SDimitry Andric     getSIProgramInfo(CurrentProgramInfo, MF);
5470b57cec5SDimitry Andric   }
5480b57cec5SDimitry Andric 
549e8d8bef9SDimitry Andric   if (STM.isAmdPalOS()) {
550e8d8bef9SDimitry Andric     if (MFI->isEntryFunction())
5510b57cec5SDimitry Andric       EmitPALMetadata(MF, CurrentProgramInfo);
552e8d8bef9SDimitry Andric     else if (MFI->isModuleEntryFunction())
553e8d8bef9SDimitry Andric       emitPALFunctionMetadata(MF);
554e8d8bef9SDimitry Andric   } else if (!STM.isAmdHsaOS()) {
5550b57cec5SDimitry Andric     EmitProgramInfoSI(MF, CurrentProgramInfo);
5560b57cec5SDimitry Andric   }
5570b57cec5SDimitry Andric 
5580b57cec5SDimitry Andric   DumpCodeInstEmitter = nullptr;
5590b57cec5SDimitry Andric   if (STM.dumpCode()) {
560*0fca6ea1SDimitry Andric     // For -dumpcode, get the assembler out of the streamer. This only works
561*0fca6ea1SDimitry Andric     // with -filetype=obj.
5620b57cec5SDimitry Andric     MCAssembler *Assembler = OutStreamer->getAssemblerPtr();
5630b57cec5SDimitry Andric     if (Assembler)
5640b57cec5SDimitry Andric       DumpCodeInstEmitter = Assembler->getEmitterPtr();
5650b57cec5SDimitry Andric   }
5660b57cec5SDimitry Andric 
5670b57cec5SDimitry Andric   DisasmLines.clear();
5680b57cec5SDimitry Andric   HexLines.clear();
5690b57cec5SDimitry Andric   DisasmLineMaxLen = 0;
5700b57cec5SDimitry Andric 
5715ffd83dbSDimitry Andric   emitFunctionBody();
5720b57cec5SDimitry Andric 
573fcaf7f86SDimitry Andric   emitResourceUsageRemarks(MF, CurrentProgramInfo, MFI->isModuleEntryFunction(),
574fcaf7f86SDimitry Andric                            STM.hasMAIInsts());
575fcaf7f86SDimitry Andric 
5760b57cec5SDimitry Andric   if (isVerbose()) {
5770b57cec5SDimitry Andric     MCSectionELF *CommentSection =
5780b57cec5SDimitry Andric         Context.getELFSection(".AMDGPU.csdata", ELF::SHT_PROGBITS, 0);
57981ad6265SDimitry Andric     OutStreamer->switchSection(CommentSection);
5800b57cec5SDimitry Andric 
5810b57cec5SDimitry Andric     if (!MFI->isEntryFunction()) {
5820b57cec5SDimitry Andric       OutStreamer->emitRawComment(" Function info:", false);
583fe6060f1SDimitry Andric       const AMDGPUResourceUsageAnalysis::SIFunctionResourceInfo &Info =
584fe6060f1SDimitry Andric           ResourceUsage->getResourceInfo(&MF.getFunction());
5850b57cec5SDimitry Andric       emitCommonFunctionComments(
5860b57cec5SDimitry Andric           Info.NumVGPR,
587bdd1243dSDimitry Andric           STM.hasMAIInsts() ? Info.NumAGPR : std::optional<uint32_t>(),
5888bcb0991SDimitry Andric           Info.getTotalNumVGPRs(STM),
5890b57cec5SDimitry Andric           Info.getTotalNumSGPRs(MF.getSubtarget<GCNSubtarget>()),
590bdd1243dSDimitry Andric           Info.PrivateSegmentSize, getFunctionCodeSize(MF), MFI);
5910b57cec5SDimitry Andric       return false;
5920b57cec5SDimitry Andric     }
5930b57cec5SDimitry Andric 
5940b57cec5SDimitry Andric     OutStreamer->emitRawComment(" Kernel info:", false);
595bdd1243dSDimitry Andric     emitCommonFunctionComments(
596bdd1243dSDimitry Andric         CurrentProgramInfo.NumArchVGPR,
597*0fca6ea1SDimitry Andric         STM.hasMAIInsts() ? CurrentProgramInfo.NumAccVGPR : nullptr,
598bdd1243dSDimitry Andric         CurrentProgramInfo.NumVGPR, CurrentProgramInfo.NumSGPR,
599bdd1243dSDimitry Andric         CurrentProgramInfo.ScratchSize, getFunctionCodeSize(MF), MFI);
6000b57cec5SDimitry Andric 
6010b57cec5SDimitry Andric     OutStreamer->emitRawComment(
6020b57cec5SDimitry Andric       " FloatMode: " + Twine(CurrentProgramInfo.FloatMode), false);
6030b57cec5SDimitry Andric     OutStreamer->emitRawComment(
6040b57cec5SDimitry Andric       " IeeeMode: " + Twine(CurrentProgramInfo.IEEEMode), false);
6050b57cec5SDimitry Andric     OutStreamer->emitRawComment(
6060b57cec5SDimitry Andric       " LDSByteSize: " + Twine(CurrentProgramInfo.LDSSize) +
6070b57cec5SDimitry Andric       " bytes/workgroup (compile time only)", false);
6080b57cec5SDimitry Andric 
6090b57cec5SDimitry Andric     OutStreamer->emitRawComment(
610*0fca6ea1SDimitry Andric         " SGPRBlocks: " + getMCExprStr(CurrentProgramInfo.SGPRBlocks), false);
611*0fca6ea1SDimitry Andric 
6120b57cec5SDimitry Andric     OutStreamer->emitRawComment(
613*0fca6ea1SDimitry Andric         " VGPRBlocks: " + getMCExprStr(CurrentProgramInfo.VGPRBlocks), false);
6140b57cec5SDimitry Andric 
6150b57cec5SDimitry Andric     OutStreamer->emitRawComment(
6160b57cec5SDimitry Andric         " NumSGPRsForWavesPerEU: " +
617*0fca6ea1SDimitry Andric             getMCExprStr(CurrentProgramInfo.NumSGPRsForWavesPerEU),
618*0fca6ea1SDimitry Andric         false);
6190b57cec5SDimitry Andric     OutStreamer->emitRawComment(
6200b57cec5SDimitry Andric         " NumVGPRsForWavesPerEU: " +
621*0fca6ea1SDimitry Andric             getMCExprStr(CurrentProgramInfo.NumVGPRsForWavesPerEU),
622*0fca6ea1SDimitry Andric         false);
6230b57cec5SDimitry Andric 
624*0fca6ea1SDimitry Andric     if (STM.hasGFX90AInsts()) {
625*0fca6ea1SDimitry Andric       const MCExpr *AdjustedAccum = MCBinaryExpr::createAdd(
626*0fca6ea1SDimitry Andric           CurrentProgramInfo.AccumOffset, MCConstantExpr::create(1, Ctx), Ctx);
627*0fca6ea1SDimitry Andric       AdjustedAccum = MCBinaryExpr::createMul(
628*0fca6ea1SDimitry Andric           AdjustedAccum, MCConstantExpr::create(4, Ctx), Ctx);
629fe6060f1SDimitry Andric       OutStreamer->emitRawComment(
630*0fca6ea1SDimitry Andric           " AccumOffset: " + getMCExprStr(AdjustedAccum), false);
631*0fca6ea1SDimitry Andric     }
632fe6060f1SDimitry Andric 
6330b57cec5SDimitry Andric     OutStreamer->emitRawComment(
634*0fca6ea1SDimitry Andric         " Occupancy: " + getMCExprStr(CurrentProgramInfo.Occupancy), false);
6358bcb0991SDimitry Andric 
6368bcb0991SDimitry Andric     OutStreamer->emitRawComment(
6370b57cec5SDimitry Andric       " WaveLimiterHint : " + Twine(MFI->needsWaveLimiter()), false);
6380b57cec5SDimitry Andric 
639*0fca6ea1SDimitry Andric     OutStreamer->emitRawComment(
640*0fca6ea1SDimitry Andric         " COMPUTE_PGM_RSRC2:SCRATCH_EN: " +
641*0fca6ea1SDimitry Andric             getMCExprStr(CurrentProgramInfo.ScratchEnable),
64206c3fb27SDimitry Andric         false);
64306c3fb27SDimitry Andric     OutStreamer->emitRawComment(" COMPUTE_PGM_RSRC2:USER_SGPR: " +
64406c3fb27SDimitry Andric                                     Twine(CurrentProgramInfo.UserSGPR),
64506c3fb27SDimitry Andric                                 false);
64606c3fb27SDimitry Andric     OutStreamer->emitRawComment(" COMPUTE_PGM_RSRC2:TRAP_HANDLER: " +
64706c3fb27SDimitry Andric                                     Twine(CurrentProgramInfo.TrapHandlerEnable),
64806c3fb27SDimitry Andric                                 false);
64906c3fb27SDimitry Andric     OutStreamer->emitRawComment(" COMPUTE_PGM_RSRC2:TGID_X_EN: " +
65006c3fb27SDimitry Andric                                     Twine(CurrentProgramInfo.TGIdXEnable),
65106c3fb27SDimitry Andric                                 false);
65206c3fb27SDimitry Andric     OutStreamer->emitRawComment(" COMPUTE_PGM_RSRC2:TGID_Y_EN: " +
65306c3fb27SDimitry Andric                                     Twine(CurrentProgramInfo.TGIdYEnable),
65406c3fb27SDimitry Andric                                 false);
65506c3fb27SDimitry Andric     OutStreamer->emitRawComment(" COMPUTE_PGM_RSRC2:TGID_Z_EN: " +
65606c3fb27SDimitry Andric                                     Twine(CurrentProgramInfo.TGIdZEnable),
65706c3fb27SDimitry Andric                                 false);
65806c3fb27SDimitry Andric     OutStreamer->emitRawComment(" COMPUTE_PGM_RSRC2:TIDIG_COMP_CNT: " +
65906c3fb27SDimitry Andric                                     Twine(CurrentProgramInfo.TIdIGCompCount),
6600b57cec5SDimitry Andric                                 false);
661fe6060f1SDimitry Andric 
662*0fca6ea1SDimitry Andric     [[maybe_unused]] int64_t PGMRSrc3;
663fe6060f1SDimitry Andric     assert(STM.hasGFX90AInsts() ||
664*0fca6ea1SDimitry Andric            (CurrentProgramInfo.ComputePGMRSrc3GFX90A->evaluateAsAbsolute(
665*0fca6ea1SDimitry Andric                 PGMRSrc3) &&
666*0fca6ea1SDimitry Andric             static_cast<uint64_t>(PGMRSrc3) == 0));
667fe6060f1SDimitry Andric     if (STM.hasGFX90AInsts()) {
668fe6060f1SDimitry Andric       OutStreamer->emitRawComment(
669fe6060f1SDimitry Andric           " COMPUTE_PGM_RSRC3_GFX90A:ACCUM_OFFSET: " +
670*0fca6ea1SDimitry Andric               getMCExprStr(MCKernelDescriptor::bits_get(
671*0fca6ea1SDimitry Andric                   CurrentProgramInfo.ComputePGMRSrc3GFX90A,
672*0fca6ea1SDimitry Andric                   amdhsa::COMPUTE_PGM_RSRC3_GFX90A_ACCUM_OFFSET_SHIFT,
673*0fca6ea1SDimitry Andric                   amdhsa::COMPUTE_PGM_RSRC3_GFX90A_ACCUM_OFFSET, Ctx)),
674fe6060f1SDimitry Andric           false);
675fe6060f1SDimitry Andric       OutStreamer->emitRawComment(
676fe6060f1SDimitry Andric           " COMPUTE_PGM_RSRC3_GFX90A:TG_SPLIT: " +
677*0fca6ea1SDimitry Andric               getMCExprStr(MCKernelDescriptor::bits_get(
678*0fca6ea1SDimitry Andric                   CurrentProgramInfo.ComputePGMRSrc3GFX90A,
679*0fca6ea1SDimitry Andric                   amdhsa::COMPUTE_PGM_RSRC3_GFX90A_TG_SPLIT_SHIFT,
680*0fca6ea1SDimitry Andric                   amdhsa::COMPUTE_PGM_RSRC3_GFX90A_TG_SPLIT, Ctx)),
681fe6060f1SDimitry Andric           false);
682fe6060f1SDimitry Andric     }
6830b57cec5SDimitry Andric   }
6840b57cec5SDimitry Andric 
6850b57cec5SDimitry Andric   if (DumpCodeInstEmitter) {
6860b57cec5SDimitry Andric 
68781ad6265SDimitry Andric     OutStreamer->switchSection(
6885ffd83dbSDimitry Andric         Context.getELFSection(".AMDGPU.disasm", ELF::SHT_PROGBITS, 0));
6890b57cec5SDimitry Andric 
6900b57cec5SDimitry Andric     for (size_t i = 0; i < DisasmLines.size(); ++i) {
6910b57cec5SDimitry Andric       std::string Comment = "\n";
6920b57cec5SDimitry Andric       if (!HexLines[i].empty()) {
6930b57cec5SDimitry Andric         Comment = std::string(DisasmLineMaxLen - DisasmLines[i].size(), ' ');
6940b57cec5SDimitry Andric         Comment += " ; " + HexLines[i] + "\n";
6950b57cec5SDimitry Andric       }
6960b57cec5SDimitry Andric 
6975ffd83dbSDimitry Andric       OutStreamer->emitBytes(StringRef(DisasmLines[i]));
6985ffd83dbSDimitry Andric       OutStreamer->emitBytes(StringRef(Comment));
6990b57cec5SDimitry Andric     }
7000b57cec5SDimitry Andric   }
7010b57cec5SDimitry Andric 
7020b57cec5SDimitry Andric   return false;
7030b57cec5SDimitry Andric }
7040b57cec5SDimitry Andric 
705fe6060f1SDimitry Andric // TODO: Fold this into emitFunctionBodyStart.
706fe6060f1SDimitry Andric void AMDGPUAsmPrinter::initializeTargetID(const Module &M) {
707fe6060f1SDimitry Andric   // In the beginning all features are either 'Any' or 'NotSupported',
708fe6060f1SDimitry Andric   // depending on global target features. This will cover empty modules.
7097a6dacacSDimitry Andric   getTargetStreamer()->initializeTargetID(*getGlobalSTI(),
7107a6dacacSDimitry Andric                                           getGlobalSTI()->getFeatureString());
711fe6060f1SDimitry Andric 
712fe6060f1SDimitry Andric   // If module is empty, we are done.
713fe6060f1SDimitry Andric   if (M.empty())
714fe6060f1SDimitry Andric     return;
715fe6060f1SDimitry Andric 
716fe6060f1SDimitry Andric   // If module is not empty, need to find first 'Off' or 'On' feature
717fe6060f1SDimitry Andric   // setting per feature from functions in module.
718fe6060f1SDimitry Andric   for (auto &F : M) {
719fe6060f1SDimitry Andric     auto &TSTargetID = getTargetStreamer()->getTargetID();
720fe6060f1SDimitry Andric     if ((!TSTargetID->isXnackSupported() || TSTargetID->isXnackOnOrOff()) &&
721fe6060f1SDimitry Andric         (!TSTargetID->isSramEccSupported() || TSTargetID->isSramEccOnOrOff()))
722fe6060f1SDimitry Andric       break;
723fe6060f1SDimitry Andric 
724fe6060f1SDimitry Andric     const GCNSubtarget &STM = TM.getSubtarget<GCNSubtarget>(F);
725fe6060f1SDimitry Andric     const IsaInfo::AMDGPUTargetID &STMTargetID = STM.getTargetID();
726fe6060f1SDimitry Andric     if (TSTargetID->isXnackSupported())
727fe6060f1SDimitry Andric       if (TSTargetID->getXnackSetting() == IsaInfo::TargetIDSetting::Any)
728fe6060f1SDimitry Andric         TSTargetID->setXnackSetting(STMTargetID.getXnackSetting());
729fe6060f1SDimitry Andric     if (TSTargetID->isSramEccSupported())
730fe6060f1SDimitry Andric       if (TSTargetID->getSramEccSetting() == IsaInfo::TargetIDSetting::Any)
731fe6060f1SDimitry Andric         TSTargetID->setSramEccSetting(STMTargetID.getSramEccSetting());
732fe6060f1SDimitry Andric   }
733fe6060f1SDimitry Andric }
734fe6060f1SDimitry Andric 
7350b57cec5SDimitry Andric uint64_t AMDGPUAsmPrinter::getFunctionCodeSize(const MachineFunction &MF) const {
7360b57cec5SDimitry Andric   const GCNSubtarget &STM = MF.getSubtarget<GCNSubtarget>();
7370b57cec5SDimitry Andric   const SIInstrInfo *TII = STM.getInstrInfo();
7380b57cec5SDimitry Andric 
7390b57cec5SDimitry Andric   uint64_t CodeSize = 0;
7400b57cec5SDimitry Andric 
7410b57cec5SDimitry Andric   for (const MachineBasicBlock &MBB : MF) {
7420b57cec5SDimitry Andric     for (const MachineInstr &MI : MBB) {
7430b57cec5SDimitry Andric       // TODO: CodeSize should account for multiple functions.
7440b57cec5SDimitry Andric 
7450b57cec5SDimitry Andric       // TODO: Should we count size of debug info?
7460b57cec5SDimitry Andric       if (MI.isDebugInstr())
7470b57cec5SDimitry Andric         continue;
7480b57cec5SDimitry Andric 
7490b57cec5SDimitry Andric       CodeSize += TII->getInstSizeInBytes(MI);
7500b57cec5SDimitry Andric     }
7510b57cec5SDimitry Andric   }
7520b57cec5SDimitry Andric 
7530b57cec5SDimitry Andric   return CodeSize;
7540b57cec5SDimitry Andric }
7550b57cec5SDimitry Andric 
7560b57cec5SDimitry Andric void AMDGPUAsmPrinter::getSIProgramInfo(SIProgramInfo &ProgInfo,
7570b57cec5SDimitry Andric                                         const MachineFunction &MF) {
758fe6060f1SDimitry Andric   const AMDGPUResourceUsageAnalysis::SIFunctionResourceInfo &Info =
759fe6060f1SDimitry Andric       ResourceUsage->getResourceInfo(&MF.getFunction());
7608bcb0991SDimitry Andric   const GCNSubtarget &STM = MF.getSubtarget<GCNSubtarget>();
761*0fca6ea1SDimitry Andric   MCContext &Ctx = MF.getContext();
7620b57cec5SDimitry Andric 
763*0fca6ea1SDimitry Andric   auto CreateExpr = [&Ctx](int64_t Value) {
764*0fca6ea1SDimitry Andric     return MCConstantExpr::create(Value, Ctx);
765*0fca6ea1SDimitry Andric   };
766*0fca6ea1SDimitry Andric 
767*0fca6ea1SDimitry Andric   auto TryGetMCExprValue = [](const MCExpr *Value, uint64_t &Res) -> bool {
768*0fca6ea1SDimitry Andric     int64_t Val;
769*0fca6ea1SDimitry Andric     if (Value->evaluateAsAbsolute(Val)) {
770*0fca6ea1SDimitry Andric       Res = Val;
771*0fca6ea1SDimitry Andric       return true;
772*0fca6ea1SDimitry Andric     }
773*0fca6ea1SDimitry Andric     return false;
774*0fca6ea1SDimitry Andric   };
775*0fca6ea1SDimitry Andric 
776*0fca6ea1SDimitry Andric   ProgInfo.NumArchVGPR = CreateExpr(Info.NumVGPR);
777*0fca6ea1SDimitry Andric   ProgInfo.NumAccVGPR = CreateExpr(Info.NumAGPR);
778*0fca6ea1SDimitry Andric   ProgInfo.NumVGPR = CreateExpr(Info.getTotalNumVGPRs(STM));
779*0fca6ea1SDimitry Andric   ProgInfo.AccumOffset =
780*0fca6ea1SDimitry Andric       CreateExpr(alignTo(std::max(1, Info.NumVGPR), 4) / 4 - 1);
781fe6060f1SDimitry Andric   ProgInfo.TgSplit = STM.isTgSplitEnabled();
782*0fca6ea1SDimitry Andric   ProgInfo.NumSGPR = CreateExpr(Info.NumExplicitSGPR);
783*0fca6ea1SDimitry Andric   ProgInfo.ScratchSize = CreateExpr(Info.PrivateSegmentSize);
784*0fca6ea1SDimitry Andric   ProgInfo.VCCUsed = CreateExpr(Info.UsesVCC);
785*0fca6ea1SDimitry Andric   ProgInfo.FlatUsed = CreateExpr(Info.UsesFlatScratch);
786*0fca6ea1SDimitry Andric   ProgInfo.DynamicCallStack =
787*0fca6ea1SDimitry Andric       CreateExpr(Info.HasDynamicallySizedStack || Info.HasRecursion);
7880b57cec5SDimitry Andric 
789e8d8bef9SDimitry Andric   const uint64_t MaxScratchPerWorkitem =
79081ad6265SDimitry Andric       STM.getMaxWaveScratchSize() / STM.getWavefrontSize();
791*0fca6ea1SDimitry Andric   uint64_t ScratchSize;
792*0fca6ea1SDimitry Andric   if (TryGetMCExprValue(ProgInfo.ScratchSize, ScratchSize) &&
793*0fca6ea1SDimitry Andric       ScratchSize > MaxScratchPerWorkitem) {
794*0fca6ea1SDimitry Andric     DiagnosticInfoStackSize DiagStackSize(MF.getFunction(), ScratchSize,
795349cc55cSDimitry Andric                                           MaxScratchPerWorkitem, DS_Error);
7960b57cec5SDimitry Andric     MF.getFunction().getContext().diagnose(DiagStackSize);
7970b57cec5SDimitry Andric   }
7980b57cec5SDimitry Andric 
7990b57cec5SDimitry Andric   const SIMachineFunctionInfo *MFI = MF.getInfo<SIMachineFunctionInfo>();
8000b57cec5SDimitry Andric 
801fe6060f1SDimitry Andric   // The calculations related to SGPR/VGPR blocks are
8020b57cec5SDimitry Andric   // duplicated in part in AMDGPUAsmParser::calculateGPRBlocks, and could be
8030b57cec5SDimitry Andric   // unified.
804*0fca6ea1SDimitry Andric   const MCExpr *ExtraSGPRs = AMDGPUMCExpr::createExtraSGPRs(
805*0fca6ea1SDimitry Andric       ProgInfo.VCCUsed, ProgInfo.FlatUsed,
806*0fca6ea1SDimitry Andric       getTargetStreamer()->getTargetID()->isXnackOnOrAny(), Ctx);
8070b57cec5SDimitry Andric 
8080b57cec5SDimitry Andric   // Check the addressable register limit before we add ExtraSGPRs.
8090b57cec5SDimitry Andric   if (STM.getGeneration() >= AMDGPUSubtarget::VOLCANIC_ISLANDS &&
8100b57cec5SDimitry Andric       !STM.hasSGPRInitBug()) {
8110b57cec5SDimitry Andric     unsigned MaxAddressableNumSGPRs = STM.getAddressableNumSGPRs();
812*0fca6ea1SDimitry Andric     uint64_t NumSgpr;
813*0fca6ea1SDimitry Andric     if (TryGetMCExprValue(ProgInfo.NumSGPR, NumSgpr) &&
814*0fca6ea1SDimitry Andric         NumSgpr > MaxAddressableNumSGPRs) {
8150b57cec5SDimitry Andric       // This can happen due to a compiler bug or when using inline asm.
8160b57cec5SDimitry Andric       LLVMContext &Ctx = MF.getFunction().getContext();
817349cc55cSDimitry Andric       DiagnosticInfoResourceLimit Diag(
818*0fca6ea1SDimitry Andric           MF.getFunction(), "addressable scalar registers", NumSgpr,
819349cc55cSDimitry Andric           MaxAddressableNumSGPRs, DS_Error, DK_ResourceLimit);
8200b57cec5SDimitry Andric       Ctx.diagnose(Diag);
821*0fca6ea1SDimitry Andric       ProgInfo.NumSGPR = CreateExpr(MaxAddressableNumSGPRs - 1);
8220b57cec5SDimitry Andric     }
8230b57cec5SDimitry Andric   }
8240b57cec5SDimitry Andric 
8250b57cec5SDimitry Andric   // Account for extra SGPRs and VGPRs reserved for debugger use.
826*0fca6ea1SDimitry Andric   ProgInfo.NumSGPR = MCBinaryExpr::createAdd(ProgInfo.NumSGPR, ExtraSGPRs, Ctx);
8270b57cec5SDimitry Andric 
828e8d8bef9SDimitry Andric   const Function &F = MF.getFunction();
829e8d8bef9SDimitry Andric 
8300b57cec5SDimitry Andric   // Ensure there are enough SGPRs and VGPRs for wave dispatch, where wave
8310b57cec5SDimitry Andric   // dispatch registers are function args.
8320b57cec5SDimitry Andric   unsigned WaveDispatchNumSGPR = 0, WaveDispatchNumVGPR = 0;
833e8d8bef9SDimitry Andric 
834e8d8bef9SDimitry Andric   if (isShader(F.getCallingConv())) {
835349cc55cSDimitry Andric     bool IsPixelShader =
836349cc55cSDimitry Andric         F.getCallingConv() == CallingConv::AMDGPU_PS && !STM.isAmdHsaOS();
837349cc55cSDimitry Andric 
838349cc55cSDimitry Andric     // Calculate the number of VGPR registers based on the SPI input registers
839349cc55cSDimitry Andric     uint32_t InputEna = 0;
840349cc55cSDimitry Andric     uint32_t InputAddr = 0;
841349cc55cSDimitry Andric     unsigned LastEna = 0;
842349cc55cSDimitry Andric 
843349cc55cSDimitry Andric     if (IsPixelShader) {
844349cc55cSDimitry Andric       // Note for IsPixelShader:
845349cc55cSDimitry Andric       // By this stage, all enabled inputs are tagged in InputAddr as well.
846349cc55cSDimitry Andric       // We will use InputAddr to determine whether the input counts against the
847349cc55cSDimitry Andric       // vgpr total and only use the InputEnable to determine the last input
848349cc55cSDimitry Andric       // that is relevant - if extra arguments are used, then we have to honour
849349cc55cSDimitry Andric       // the InputAddr for any intermediate non-enabled inputs.
850349cc55cSDimitry Andric       InputEna = MFI->getPSInputEnable();
851349cc55cSDimitry Andric       InputAddr = MFI->getPSInputAddr();
852349cc55cSDimitry Andric 
853349cc55cSDimitry Andric       // We only need to consider input args up to the last used arg.
854349cc55cSDimitry Andric       assert((InputEna || InputAddr) &&
855349cc55cSDimitry Andric              "PSInputAddr and PSInputEnable should "
856349cc55cSDimitry Andric              "never both be 0 for AMDGPU_PS shaders");
857349cc55cSDimitry Andric       // There are some rare circumstances where InputAddr is non-zero and
858349cc55cSDimitry Andric       // InputEna can be set to 0. In this case we default to setting LastEna
859349cc55cSDimitry Andric       // to 1.
86006c3fb27SDimitry Andric       LastEna = InputEna ? llvm::Log2_32(InputEna) + 1 : 1;
861349cc55cSDimitry Andric     }
862349cc55cSDimitry Andric 
863e8d8bef9SDimitry Andric     // FIXME: We should be using the number of registers determined during
864e8d8bef9SDimitry Andric     // calling convention lowering to legalize the types.
865*0fca6ea1SDimitry Andric     const DataLayout &DL = F.getDataLayout();
866349cc55cSDimitry Andric     unsigned PSArgCount = 0;
867349cc55cSDimitry Andric     unsigned IntermediateVGPR = 0;
868e8d8bef9SDimitry Andric     for (auto &Arg : F.args()) {
869e8d8bef9SDimitry Andric       unsigned NumRegs = (DL.getTypeSizeInBits(Arg.getType()) + 31) / 32;
870349cc55cSDimitry Andric       if (Arg.hasAttribute(Attribute::InReg)) {
8710b57cec5SDimitry Andric         WaveDispatchNumSGPR += NumRegs;
872349cc55cSDimitry Andric       } else {
873349cc55cSDimitry Andric         // If this is a PS shader and we're processing the PS Input args (first
874349cc55cSDimitry Andric         // 16 VGPR), use the InputEna and InputAddr bits to define how many
875349cc55cSDimitry Andric         // VGPRs are actually used.
876349cc55cSDimitry Andric         // Any extra VGPR arguments are handled as normal arguments (and
877349cc55cSDimitry Andric         // contribute to the VGPR count whether they're used or not).
878349cc55cSDimitry Andric         if (IsPixelShader && PSArgCount < 16) {
879349cc55cSDimitry Andric           if ((1 << PSArgCount) & InputAddr) {
880349cc55cSDimitry Andric             if (PSArgCount < LastEna)
881349cc55cSDimitry Andric               WaveDispatchNumVGPR += NumRegs;
8820b57cec5SDimitry Andric             else
883349cc55cSDimitry Andric               IntermediateVGPR += NumRegs;
884349cc55cSDimitry Andric           }
885349cc55cSDimitry Andric           PSArgCount++;
886349cc55cSDimitry Andric         } else {
887349cc55cSDimitry Andric           // If there are extra arguments we have to include the allocation for
888349cc55cSDimitry Andric           // the non-used (but enabled with InputAddr) input arguments
889349cc55cSDimitry Andric           if (IntermediateVGPR) {
890349cc55cSDimitry Andric             WaveDispatchNumVGPR += IntermediateVGPR;
891349cc55cSDimitry Andric             IntermediateVGPR = 0;
892349cc55cSDimitry Andric           }
8930b57cec5SDimitry Andric           WaveDispatchNumVGPR += NumRegs;
8940b57cec5SDimitry Andric         }
895349cc55cSDimitry Andric       }
896349cc55cSDimitry Andric     }
897*0fca6ea1SDimitry Andric     ProgInfo.NumSGPR = AMDGPUMCExpr::createMax(
898*0fca6ea1SDimitry Andric         {ProgInfo.NumSGPR, CreateExpr(WaveDispatchNumSGPR)}, Ctx);
899*0fca6ea1SDimitry Andric 
900*0fca6ea1SDimitry Andric     ProgInfo.NumArchVGPR = AMDGPUMCExpr::createMax(
901*0fca6ea1SDimitry Andric         {ProgInfo.NumVGPR, CreateExpr(WaveDispatchNumVGPR)}, Ctx);
902*0fca6ea1SDimitry Andric 
903*0fca6ea1SDimitry Andric     ProgInfo.NumVGPR = AMDGPUMCExpr::createTotalNumVGPR(
904*0fca6ea1SDimitry Andric         ProgInfo.NumAccVGPR, ProgInfo.NumArchVGPR, Ctx);
905e8d8bef9SDimitry Andric   }
9060b57cec5SDimitry Andric 
9070b57cec5SDimitry Andric   // Adjust number of registers used to meet default/requested minimum/maximum
9080b57cec5SDimitry Andric   // number of waves per execution unit request.
909*0fca6ea1SDimitry Andric   unsigned MaxWaves = MFI->getMaxWavesPerEU();
910*0fca6ea1SDimitry Andric   ProgInfo.NumSGPRsForWavesPerEU =
911*0fca6ea1SDimitry Andric       AMDGPUMCExpr::createMax({ProgInfo.NumSGPR, CreateExpr(1ul),
912*0fca6ea1SDimitry Andric                                CreateExpr(STM.getMinNumSGPRs(MaxWaves))},
913*0fca6ea1SDimitry Andric                               Ctx);
914*0fca6ea1SDimitry Andric   ProgInfo.NumVGPRsForWavesPerEU =
915*0fca6ea1SDimitry Andric       AMDGPUMCExpr::createMax({ProgInfo.NumVGPR, CreateExpr(1ul),
916*0fca6ea1SDimitry Andric                                CreateExpr(STM.getMinNumVGPRs(MaxWaves))},
917*0fca6ea1SDimitry Andric                               Ctx);
9180b57cec5SDimitry Andric 
9190b57cec5SDimitry Andric   if (STM.getGeneration() <= AMDGPUSubtarget::SEA_ISLANDS ||
9200b57cec5SDimitry Andric       STM.hasSGPRInitBug()) {
9210b57cec5SDimitry Andric     unsigned MaxAddressableNumSGPRs = STM.getAddressableNumSGPRs();
922*0fca6ea1SDimitry Andric     uint64_t NumSgpr;
923*0fca6ea1SDimitry Andric     if (TryGetMCExprValue(ProgInfo.NumSGPR, NumSgpr) &&
924*0fca6ea1SDimitry Andric         NumSgpr > MaxAddressableNumSGPRs) {
9250b57cec5SDimitry Andric       // This can happen due to a compiler bug or when using inline asm to use
9260b57cec5SDimitry Andric       // the registers which are usually reserved for vcc etc.
9270b57cec5SDimitry Andric       LLVMContext &Ctx = MF.getFunction().getContext();
928349cc55cSDimitry Andric       DiagnosticInfoResourceLimit Diag(MF.getFunction(), "scalar registers",
929*0fca6ea1SDimitry Andric                                        NumSgpr, MaxAddressableNumSGPRs,
930349cc55cSDimitry Andric                                        DS_Error, DK_ResourceLimit);
9310b57cec5SDimitry Andric       Ctx.diagnose(Diag);
932*0fca6ea1SDimitry Andric       ProgInfo.NumSGPR = CreateExpr(MaxAddressableNumSGPRs);
933*0fca6ea1SDimitry Andric       ProgInfo.NumSGPRsForWavesPerEU = CreateExpr(MaxAddressableNumSGPRs);
9340b57cec5SDimitry Andric     }
9350b57cec5SDimitry Andric   }
9360b57cec5SDimitry Andric 
9370b57cec5SDimitry Andric   if (STM.hasSGPRInitBug()) {
9380b57cec5SDimitry Andric     ProgInfo.NumSGPR =
939*0fca6ea1SDimitry Andric         CreateExpr(AMDGPU::IsaInfo::FIXED_NUM_SGPRS_FOR_INIT_BUG);
9400b57cec5SDimitry Andric     ProgInfo.NumSGPRsForWavesPerEU =
941*0fca6ea1SDimitry Andric         CreateExpr(AMDGPU::IsaInfo::FIXED_NUM_SGPRS_FOR_INIT_BUG);
9420b57cec5SDimitry Andric   }
9430b57cec5SDimitry Andric 
9440b57cec5SDimitry Andric   if (MFI->getNumUserSGPRs() > STM.getMaxNumUserSGPRs()) {
9450b57cec5SDimitry Andric     LLVMContext &Ctx = MF.getFunction().getContext();
9460b57cec5SDimitry Andric     DiagnosticInfoResourceLimit Diag(MF.getFunction(), "user SGPRs",
947349cc55cSDimitry Andric                                      MFI->getNumUserSGPRs(),
948349cc55cSDimitry Andric                                      STM.getMaxNumUserSGPRs(), DS_Error);
9490b57cec5SDimitry Andric     Ctx.diagnose(Diag);
9500b57cec5SDimitry Andric   }
9510b57cec5SDimitry Andric 
952bdd1243dSDimitry Andric   if (MFI->getLDSSize() >
953bdd1243dSDimitry Andric       static_cast<unsigned>(STM.getAddressableLocalMemorySize())) {
9540b57cec5SDimitry Andric     LLVMContext &Ctx = MF.getFunction().getContext();
955bdd1243dSDimitry Andric     DiagnosticInfoResourceLimit Diag(
956bdd1243dSDimitry Andric         MF.getFunction(), "local memory", MFI->getLDSSize(),
957bdd1243dSDimitry Andric         STM.getAddressableLocalMemorySize(), DS_Error);
9580b57cec5SDimitry Andric     Ctx.diagnose(Diag);
9590b57cec5SDimitry Andric   }
960*0fca6ea1SDimitry Andric   // The MCExpr equivalent of getNumSGPRBlocks/getNumVGPRBlocks:
961*0fca6ea1SDimitry Andric   // (alignTo(max(1u, NumGPR), GPREncodingGranule) / GPREncodingGranule) - 1
962*0fca6ea1SDimitry Andric   auto GetNumGPRBlocks = [&CreateExpr, &Ctx](const MCExpr *NumGPR,
963*0fca6ea1SDimitry Andric                                              unsigned Granule) {
964*0fca6ea1SDimitry Andric     const MCExpr *OneConst = CreateExpr(1ul);
965*0fca6ea1SDimitry Andric     const MCExpr *GranuleConst = CreateExpr(Granule);
966*0fca6ea1SDimitry Andric     const MCExpr *MaxNumGPR = AMDGPUMCExpr::createMax({NumGPR, OneConst}, Ctx);
967*0fca6ea1SDimitry Andric     const MCExpr *AlignToGPR =
968*0fca6ea1SDimitry Andric         AMDGPUMCExpr::createAlignTo(MaxNumGPR, GranuleConst, Ctx);
969*0fca6ea1SDimitry Andric     const MCExpr *DivGPR =
970*0fca6ea1SDimitry Andric         MCBinaryExpr::createDiv(AlignToGPR, GranuleConst, Ctx);
971*0fca6ea1SDimitry Andric     const MCExpr *SubGPR = MCBinaryExpr::createSub(DivGPR, OneConst, Ctx);
972*0fca6ea1SDimitry Andric     return SubGPR;
973*0fca6ea1SDimitry Andric   };
9740b57cec5SDimitry Andric 
975*0fca6ea1SDimitry Andric   ProgInfo.SGPRBlocks = GetNumGPRBlocks(ProgInfo.NumSGPRsForWavesPerEU,
976*0fca6ea1SDimitry Andric                                         IsaInfo::getSGPREncodingGranule(&STM));
977*0fca6ea1SDimitry Andric   ProgInfo.VGPRBlocks = GetNumGPRBlocks(ProgInfo.NumVGPRsForWavesPerEU,
978*0fca6ea1SDimitry Andric                                         IsaInfo::getVGPREncodingGranule(&STM));
9790b57cec5SDimitry Andric 
980480093f4SDimitry Andric   const SIModeRegisterDefaults Mode = MFI->getMode();
981480093f4SDimitry Andric 
9820b57cec5SDimitry Andric   // Set the value to initialize FP_ROUND and FP_DENORM parts of the mode
9830b57cec5SDimitry Andric   // register.
984480093f4SDimitry Andric   ProgInfo.FloatMode = getFPMode(Mode);
9850b57cec5SDimitry Andric 
9860b57cec5SDimitry Andric   ProgInfo.IEEEMode = Mode.IEEE;
9870b57cec5SDimitry Andric 
9880b57cec5SDimitry Andric   // Make clamp modifier on NaN input returns 0.
9890b57cec5SDimitry Andric   ProgInfo.DX10Clamp = Mode.DX10Clamp;
9900b57cec5SDimitry Andric 
9910b57cec5SDimitry Andric   unsigned LDSAlignShift;
9920b57cec5SDimitry Andric   if (STM.getGeneration() < AMDGPUSubtarget::SEA_ISLANDS) {
9930b57cec5SDimitry Andric     // LDS is allocated in 64 dword blocks.
9940b57cec5SDimitry Andric     LDSAlignShift = 8;
9950b57cec5SDimitry Andric   } else {
9960b57cec5SDimitry Andric     // LDS is allocated in 128 dword blocks.
9970b57cec5SDimitry Andric     LDSAlignShift = 9;
9980b57cec5SDimitry Andric   }
9990b57cec5SDimitry Andric 
1000fcaf7f86SDimitry Andric   ProgInfo.SGPRSpill = MFI->getNumSpilledSGPRs();
1001fcaf7f86SDimitry Andric   ProgInfo.VGPRSpill = MFI->getNumSpilledVGPRs();
1002fcaf7f86SDimitry Andric 
100381ad6265SDimitry Andric   ProgInfo.LDSSize = MFI->getLDSSize();
10040b57cec5SDimitry Andric   ProgInfo.LDSBlocks =
10050b57cec5SDimitry Andric       alignTo(ProgInfo.LDSSize, 1ULL << LDSAlignShift) >> LDSAlignShift;
10060b57cec5SDimitry Andric 
1007*0fca6ea1SDimitry Andric   // The MCExpr equivalent of divideCeil.
1008*0fca6ea1SDimitry Andric   auto DivideCeil = [&Ctx](const MCExpr *Numerator, const MCExpr *Denominator) {
1009*0fca6ea1SDimitry Andric     const MCExpr *Ceil =
1010*0fca6ea1SDimitry Andric         AMDGPUMCExpr::createAlignTo(Numerator, Denominator, Ctx);
1011*0fca6ea1SDimitry Andric     return MCBinaryExpr::createDiv(Ceil, Denominator, Ctx);
1012*0fca6ea1SDimitry Andric   };
1013*0fca6ea1SDimitry Andric 
101481ad6265SDimitry Andric   // Scratch is allocated in 64-dword or 256-dword blocks.
101581ad6265SDimitry Andric   unsigned ScratchAlignShift =
101681ad6265SDimitry Andric       STM.getGeneration() >= AMDGPUSubtarget::GFX11 ? 8 : 10;
10170b57cec5SDimitry Andric   // We need to program the hardware with the amount of scratch memory that
10180b57cec5SDimitry Andric   // is used by the entire wave.  ProgInfo.ScratchSize is the amount of
10190b57cec5SDimitry Andric   // scratch memory used per thread.
1020*0fca6ea1SDimitry Andric   ProgInfo.ScratchBlocks = DivideCeil(
1021*0fca6ea1SDimitry Andric       MCBinaryExpr::createMul(ProgInfo.ScratchSize,
1022*0fca6ea1SDimitry Andric                               CreateExpr(STM.getWavefrontSize()), Ctx),
1023*0fca6ea1SDimitry Andric       CreateExpr(1ULL << ScratchAlignShift));
10240b57cec5SDimitry Andric 
10250b57cec5SDimitry Andric   if (getIsaVersion(getGlobalSTI()->getCPU()).Major >= 10) {
10260b57cec5SDimitry Andric     ProgInfo.WgpMode = STM.isCuModeEnabled() ? 0 : 1;
10270b57cec5SDimitry Andric     ProgInfo.MemOrdered = 1;
10280b57cec5SDimitry Andric   }
10290b57cec5SDimitry Andric 
10300b57cec5SDimitry Andric   // 0 = X, 1 = XY, 2 = XYZ
10310b57cec5SDimitry Andric   unsigned TIDIGCompCnt = 0;
10320b57cec5SDimitry Andric   if (MFI->hasWorkItemIDZ())
10330b57cec5SDimitry Andric     TIDIGCompCnt = 2;
10340b57cec5SDimitry Andric   else if (MFI->hasWorkItemIDY())
10350b57cec5SDimitry Andric     TIDIGCompCnt = 1;
10360b57cec5SDimitry Andric 
103781ad6265SDimitry Andric   // The private segment wave byte offset is the last of the system SGPRs. We
103881ad6265SDimitry Andric   // initially assumed it was allocated, and may have used it. It shouldn't harm
103981ad6265SDimitry Andric   // anything to disable it if we know the stack isn't used here. We may still
104081ad6265SDimitry Andric   // have emitted code reading it to initialize scratch, but if that's unused
104181ad6265SDimitry Andric   // reading garbage should be OK.
1042*0fca6ea1SDimitry Andric   ProgInfo.ScratchEnable = MCBinaryExpr::createLOr(
1043*0fca6ea1SDimitry Andric       MCBinaryExpr::createGT(ProgInfo.ScratchBlocks,
1044*0fca6ea1SDimitry Andric                              MCConstantExpr::create(0, Ctx), Ctx),
1045*0fca6ea1SDimitry Andric       ProgInfo.DynamicCallStack, Ctx);
1046*0fca6ea1SDimitry Andric 
104706c3fb27SDimitry Andric   ProgInfo.UserSGPR = MFI->getNumUserSGPRs();
10480b57cec5SDimitry Andric   // For AMDHSA, TRAP_HANDLER must be zero, as it is populated by the CP.
104906c3fb27SDimitry Andric   ProgInfo.TrapHandlerEnable =
105006c3fb27SDimitry Andric       STM.isAmdHsaOS() ? 0 : STM.isTrapHandlerEnabled();
105106c3fb27SDimitry Andric   ProgInfo.TGIdXEnable = MFI->hasWorkGroupIDX();
105206c3fb27SDimitry Andric   ProgInfo.TGIdYEnable = MFI->hasWorkGroupIDY();
105306c3fb27SDimitry Andric   ProgInfo.TGIdZEnable = MFI->hasWorkGroupIDZ();
105406c3fb27SDimitry Andric   ProgInfo.TGSizeEnable = MFI->hasWorkGroupInfo();
105506c3fb27SDimitry Andric   ProgInfo.TIdIGCompCount = TIDIGCompCnt;
105606c3fb27SDimitry Andric   ProgInfo.EXCPEnMSB = 0;
10570b57cec5SDimitry Andric   // For AMDHSA, LDS_SIZE must be zero, as it is populated by the CP.
105806c3fb27SDimitry Andric   ProgInfo.LdsSize = STM.isAmdHsaOS() ? 0 : ProgInfo.LDSBlocks;
105906c3fb27SDimitry Andric   ProgInfo.EXCPEnable = 0;
10608bcb0991SDimitry Andric 
1061fe6060f1SDimitry Andric   if (STM.hasGFX90AInsts()) {
1062*0fca6ea1SDimitry Andric     // return ((Dst & ~Mask) | (Value << Shift))
1063*0fca6ea1SDimitry Andric     auto SetBits = [&Ctx](const MCExpr *Dst, const MCExpr *Value, uint32_t Mask,
1064*0fca6ea1SDimitry Andric                           uint32_t Shift) {
1065*0fca6ea1SDimitry Andric       auto Shft = MCConstantExpr::create(Shift, Ctx);
1066*0fca6ea1SDimitry Andric       auto Msk = MCConstantExpr::create(Mask, Ctx);
1067*0fca6ea1SDimitry Andric       Dst = MCBinaryExpr::createAnd(Dst, MCUnaryExpr::createNot(Msk, Ctx), Ctx);
1068*0fca6ea1SDimitry Andric       Dst = MCBinaryExpr::createOr(
1069*0fca6ea1SDimitry Andric           Dst, MCBinaryExpr::createShl(Value, Shft, Ctx), Ctx);
1070*0fca6ea1SDimitry Andric       return Dst;
1071*0fca6ea1SDimitry Andric     };
1072*0fca6ea1SDimitry Andric 
1073*0fca6ea1SDimitry Andric     ProgInfo.ComputePGMRSrc3GFX90A =
1074*0fca6ea1SDimitry Andric         SetBits(ProgInfo.ComputePGMRSrc3GFX90A, ProgInfo.AccumOffset,
1075fe6060f1SDimitry Andric                 amdhsa::COMPUTE_PGM_RSRC3_GFX90A_ACCUM_OFFSET,
1076*0fca6ea1SDimitry Andric                 amdhsa::COMPUTE_PGM_RSRC3_GFX90A_ACCUM_OFFSET_SHIFT);
1077*0fca6ea1SDimitry Andric     ProgInfo.ComputePGMRSrc3GFX90A =
1078*0fca6ea1SDimitry Andric         SetBits(ProgInfo.ComputePGMRSrc3GFX90A, CreateExpr(ProgInfo.TgSplit),
1079fe6060f1SDimitry Andric                 amdhsa::COMPUTE_PGM_RSRC3_GFX90A_TG_SPLIT,
1080*0fca6ea1SDimitry Andric                 amdhsa::COMPUTE_PGM_RSRC3_GFX90A_TG_SPLIT_SHIFT);
1081fe6060f1SDimitry Andric   }
1082fe6060f1SDimitry Andric 
1083*0fca6ea1SDimitry Andric   ProgInfo.Occupancy = AMDGPUMCExpr::createOccupancy(
1084*0fca6ea1SDimitry Andric       STM.computeOccupancy(F, ProgInfo.LDSSize), ProgInfo.NumSGPRsForWavesPerEU,
1085*0fca6ea1SDimitry Andric       ProgInfo.NumVGPRsForWavesPerEU, STM, Ctx);
1086*0fca6ea1SDimitry Andric 
10875f757f3fSDimitry Andric   const auto [MinWEU, MaxWEU] =
10885f757f3fSDimitry Andric       AMDGPU::getIntegerPairAttribute(F, "amdgpu-waves-per-eu", {0, 0}, true);
1089*0fca6ea1SDimitry Andric   uint64_t Occupancy;
1090*0fca6ea1SDimitry Andric   if (TryGetMCExprValue(ProgInfo.Occupancy, Occupancy) && Occupancy < MinWEU) {
10915f757f3fSDimitry Andric     DiagnosticInfoOptimizationFailure Diag(
10925f757f3fSDimitry Andric         F, F.getSubprogram(),
10935f757f3fSDimitry Andric         "failed to meet occupancy target given by 'amdgpu-waves-per-eu' in "
10945f757f3fSDimitry Andric         "'" +
10955f757f3fSDimitry Andric             F.getName() + "': desired occupancy was " + Twine(MinWEU) +
1096*0fca6ea1SDimitry Andric             ", final occupancy is " + Twine(Occupancy));
10975f757f3fSDimitry Andric     F.getContext().diagnose(Diag);
10985f757f3fSDimitry Andric   }
10990b57cec5SDimitry Andric }
11000b57cec5SDimitry Andric 
11010b57cec5SDimitry Andric static unsigned getRsrcReg(CallingConv::ID CallConv) {
11020b57cec5SDimitry Andric   switch (CallConv) {
1103bdd1243dSDimitry Andric   default: [[fallthrough]];
11040b57cec5SDimitry Andric   case CallingConv::AMDGPU_CS: return R_00B848_COMPUTE_PGM_RSRC1;
11050b57cec5SDimitry Andric   case CallingConv::AMDGPU_LS: return R_00B528_SPI_SHADER_PGM_RSRC1_LS;
11060b57cec5SDimitry Andric   case CallingConv::AMDGPU_HS: return R_00B428_SPI_SHADER_PGM_RSRC1_HS;
11070b57cec5SDimitry Andric   case CallingConv::AMDGPU_ES: return R_00B328_SPI_SHADER_PGM_RSRC1_ES;
11080b57cec5SDimitry Andric   case CallingConv::AMDGPU_GS: return R_00B228_SPI_SHADER_PGM_RSRC1_GS;
11090b57cec5SDimitry Andric   case CallingConv::AMDGPU_VS: return R_00B128_SPI_SHADER_PGM_RSRC1_VS;
11100b57cec5SDimitry Andric   case CallingConv::AMDGPU_PS: return R_00B028_SPI_SHADER_PGM_RSRC1_PS;
11110b57cec5SDimitry Andric   }
11120b57cec5SDimitry Andric }
11130b57cec5SDimitry Andric 
11140b57cec5SDimitry Andric void AMDGPUAsmPrinter::EmitProgramInfoSI(const MachineFunction &MF,
11150b57cec5SDimitry Andric                                          const SIProgramInfo &CurrentProgramInfo) {
11160b57cec5SDimitry Andric   const SIMachineFunctionInfo *MFI = MF.getInfo<SIMachineFunctionInfo>();
111781ad6265SDimitry Andric   const GCNSubtarget &STM = MF.getSubtarget<GCNSubtarget>();
11180b57cec5SDimitry Andric   unsigned RsrcReg = getRsrcReg(MF.getFunction().getCallingConv());
1119*0fca6ea1SDimitry Andric   MCContext &Ctx = MF.getContext();
1120*0fca6ea1SDimitry Andric 
1121*0fca6ea1SDimitry Andric   // (((Value) & Mask) << Shift)
1122*0fca6ea1SDimitry Andric   auto SetBits = [&Ctx](const MCExpr *Value, uint32_t Mask, uint32_t Shift) {
1123*0fca6ea1SDimitry Andric     const MCExpr *msk = MCConstantExpr::create(Mask, Ctx);
1124*0fca6ea1SDimitry Andric     const MCExpr *shft = MCConstantExpr::create(Shift, Ctx);
1125*0fca6ea1SDimitry Andric     return MCBinaryExpr::createShl(MCBinaryExpr::createAnd(Value, msk, Ctx),
1126*0fca6ea1SDimitry Andric                                    shft, Ctx);
1127*0fca6ea1SDimitry Andric   };
1128*0fca6ea1SDimitry Andric 
1129*0fca6ea1SDimitry Andric   auto EmitResolvedOrExpr = [this](const MCExpr *Value, unsigned Size) {
1130*0fca6ea1SDimitry Andric     int64_t Val;
1131*0fca6ea1SDimitry Andric     if (Value->evaluateAsAbsolute(Val))
1132*0fca6ea1SDimitry Andric       OutStreamer->emitIntValue(static_cast<uint64_t>(Val), Size);
1133*0fca6ea1SDimitry Andric     else
1134*0fca6ea1SDimitry Andric       OutStreamer->emitValue(Value, Size);
1135*0fca6ea1SDimitry Andric   };
11360b57cec5SDimitry Andric 
11370b57cec5SDimitry Andric   if (AMDGPU::isCompute(MF.getFunction().getCallingConv())) {
11385ffd83dbSDimitry Andric     OutStreamer->emitInt32(R_00B848_COMPUTE_PGM_RSRC1);
11390b57cec5SDimitry Andric 
1140*0fca6ea1SDimitry Andric     EmitResolvedOrExpr(CurrentProgramInfo.getComputePGMRSrc1(STM, Ctx),
1141*0fca6ea1SDimitry Andric                        /*Size=*/4);
11420b57cec5SDimitry Andric 
11435ffd83dbSDimitry Andric     OutStreamer->emitInt32(R_00B84C_COMPUTE_PGM_RSRC2);
1144*0fca6ea1SDimitry Andric     EmitResolvedOrExpr(CurrentProgramInfo.getComputePGMRSrc2(Ctx), /*Size=*/4);
11450b57cec5SDimitry Andric 
11465ffd83dbSDimitry Andric     OutStreamer->emitInt32(R_00B860_COMPUTE_TMPRING_SIZE);
1147*0fca6ea1SDimitry Andric 
1148*0fca6ea1SDimitry Andric     // Sets bits according to S_0286E8_WAVESIZE_* mask and shift values for the
1149*0fca6ea1SDimitry Andric     // appropriate generation.
1150*0fca6ea1SDimitry Andric     if (STM.getGeneration() >= AMDGPUSubtarget::GFX12) {
1151*0fca6ea1SDimitry Andric       EmitResolvedOrExpr(SetBits(CurrentProgramInfo.ScratchBlocks,
1152*0fca6ea1SDimitry Andric                                  /*Mask=*/0x3FFFF, /*Shift=*/12),
1153*0fca6ea1SDimitry Andric                          /*Size=*/4);
1154*0fca6ea1SDimitry Andric     } else if (STM.getGeneration() == AMDGPUSubtarget::GFX11) {
1155*0fca6ea1SDimitry Andric       EmitResolvedOrExpr(SetBits(CurrentProgramInfo.ScratchBlocks,
1156*0fca6ea1SDimitry Andric                                  /*Mask=*/0x7FFF, /*Shift=*/12),
1157*0fca6ea1SDimitry Andric                          /*Size=*/4);
1158*0fca6ea1SDimitry Andric     } else {
1159*0fca6ea1SDimitry Andric       EmitResolvedOrExpr(SetBits(CurrentProgramInfo.ScratchBlocks,
1160*0fca6ea1SDimitry Andric                                  /*Mask=*/0x1FFF, /*Shift=*/12),
1161*0fca6ea1SDimitry Andric                          /*Size=*/4);
1162*0fca6ea1SDimitry Andric     }
11630b57cec5SDimitry Andric 
11640b57cec5SDimitry Andric     // TODO: Should probably note flat usage somewhere. SC emits a "FlatPtr32 =
11650b57cec5SDimitry Andric     // 0" comment but I don't see a corresponding field in the register spec.
11660b57cec5SDimitry Andric   } else {
11675ffd83dbSDimitry Andric     OutStreamer->emitInt32(RsrcReg);
1168*0fca6ea1SDimitry Andric 
1169*0fca6ea1SDimitry Andric     const MCExpr *GPRBlocks = MCBinaryExpr::createOr(
1170*0fca6ea1SDimitry Andric         SetBits(CurrentProgramInfo.VGPRBlocks, /*Mask=*/0x3F, /*Shift=*/0),
1171*0fca6ea1SDimitry Andric         SetBits(CurrentProgramInfo.SGPRBlocks, /*Mask=*/0x0F, /*Shift=*/6),
1172*0fca6ea1SDimitry Andric         MF.getContext());
1173*0fca6ea1SDimitry Andric     EmitResolvedOrExpr(GPRBlocks, /*Size=*/4);
11745ffd83dbSDimitry Andric     OutStreamer->emitInt32(R_0286E8_SPI_TMPRING_SIZE);
1175*0fca6ea1SDimitry Andric 
1176*0fca6ea1SDimitry Andric     // Sets bits according to S_0286E8_WAVESIZE_* mask and shift values for the
1177*0fca6ea1SDimitry Andric     // appropriate generation.
1178*0fca6ea1SDimitry Andric     if (STM.getGeneration() >= AMDGPUSubtarget::GFX12) {
1179*0fca6ea1SDimitry Andric       EmitResolvedOrExpr(SetBits(CurrentProgramInfo.ScratchBlocks,
1180*0fca6ea1SDimitry Andric                                  /*Mask=*/0x3FFFF, /*Shift=*/12),
1181*0fca6ea1SDimitry Andric                          /*Size=*/4);
1182*0fca6ea1SDimitry Andric     } else if (STM.getGeneration() == AMDGPUSubtarget::GFX11) {
1183*0fca6ea1SDimitry Andric       EmitResolvedOrExpr(SetBits(CurrentProgramInfo.ScratchBlocks,
1184*0fca6ea1SDimitry Andric                                  /*Mask=*/0x7FFF, /*Shift=*/12),
1185*0fca6ea1SDimitry Andric                          /*Size=*/4);
1186*0fca6ea1SDimitry Andric     } else {
1187*0fca6ea1SDimitry Andric       EmitResolvedOrExpr(SetBits(CurrentProgramInfo.ScratchBlocks,
1188*0fca6ea1SDimitry Andric                                  /*Mask=*/0x1FFF, /*Shift=*/12),
1189*0fca6ea1SDimitry Andric                          /*Size=*/4);
1190*0fca6ea1SDimitry Andric     }
11910b57cec5SDimitry Andric   }
11920b57cec5SDimitry Andric 
11930b57cec5SDimitry Andric   if (MF.getFunction().getCallingConv() == CallingConv::AMDGPU_PS) {
11945ffd83dbSDimitry Andric     OutStreamer->emitInt32(R_00B02C_SPI_SHADER_PGM_RSRC2_PS);
119581ad6265SDimitry Andric     unsigned ExtraLDSSize = STM.getGeneration() >= AMDGPUSubtarget::GFX11
119681ad6265SDimitry Andric                                 ? divideCeil(CurrentProgramInfo.LDSBlocks, 2)
119781ad6265SDimitry Andric                                 : CurrentProgramInfo.LDSBlocks;
119881ad6265SDimitry Andric     OutStreamer->emitInt32(S_00B02C_EXTRA_LDS_SIZE(ExtraLDSSize));
11995ffd83dbSDimitry Andric     OutStreamer->emitInt32(R_0286CC_SPI_PS_INPUT_ENA);
12005ffd83dbSDimitry Andric     OutStreamer->emitInt32(MFI->getPSInputEnable());
12015ffd83dbSDimitry Andric     OutStreamer->emitInt32(R_0286D0_SPI_PS_INPUT_ADDR);
12025ffd83dbSDimitry Andric     OutStreamer->emitInt32(MFI->getPSInputAddr());
12030b57cec5SDimitry Andric   }
12040b57cec5SDimitry Andric 
12055ffd83dbSDimitry Andric   OutStreamer->emitInt32(R_SPILLED_SGPRS);
12065ffd83dbSDimitry Andric   OutStreamer->emitInt32(MFI->getNumSpilledSGPRs());
12075ffd83dbSDimitry Andric   OutStreamer->emitInt32(R_SPILLED_VGPRS);
12085ffd83dbSDimitry Andric   OutStreamer->emitInt32(MFI->getNumSpilledVGPRs());
12090b57cec5SDimitry Andric }
12100b57cec5SDimitry Andric 
1211*0fca6ea1SDimitry Andric // Helper function to add common PAL Metadata 3.0+
1212*0fca6ea1SDimitry Andric static void EmitPALMetadataCommon(AMDGPUPALMetadata *MD,
1213*0fca6ea1SDimitry Andric                                   const SIProgramInfo &CurrentProgramInfo,
1214*0fca6ea1SDimitry Andric                                   CallingConv::ID CC, const GCNSubtarget &ST) {
1215*0fca6ea1SDimitry Andric   if (ST.hasIEEEMode())
1216*0fca6ea1SDimitry Andric     MD->setHwStage(CC, ".ieee_mode", (bool)CurrentProgramInfo.IEEEMode);
1217*0fca6ea1SDimitry Andric 
1218*0fca6ea1SDimitry Andric   MD->setHwStage(CC, ".wgp_mode", (bool)CurrentProgramInfo.WgpMode);
1219*0fca6ea1SDimitry Andric   MD->setHwStage(CC, ".mem_ordered", (bool)CurrentProgramInfo.MemOrdered);
1220*0fca6ea1SDimitry Andric 
1221*0fca6ea1SDimitry Andric   if (AMDGPU::isCompute(CC)) {
1222*0fca6ea1SDimitry Andric     MD->setHwStage(CC, ".trap_present",
1223*0fca6ea1SDimitry Andric                    (bool)CurrentProgramInfo.TrapHandlerEnable);
1224*0fca6ea1SDimitry Andric     MD->setHwStage(CC, ".excp_en", CurrentProgramInfo.EXCPEnable);
1225*0fca6ea1SDimitry Andric   }
1226*0fca6ea1SDimitry Andric 
1227*0fca6ea1SDimitry Andric   MD->setHwStage(CC, ".lds_size",
1228*0fca6ea1SDimitry Andric                  (unsigned)(CurrentProgramInfo.LdsSize *
1229*0fca6ea1SDimitry Andric                             getLdsDwGranularity(ST) * sizeof(uint32_t)));
1230*0fca6ea1SDimitry Andric }
1231*0fca6ea1SDimitry Andric 
12320b57cec5SDimitry Andric // This is the equivalent of EmitProgramInfoSI above, but for when the OS type
12330b57cec5SDimitry Andric // is AMDPAL.  It stores each compute/SPI register setting and other PAL
12340b57cec5SDimitry Andric // metadata items into the PALMD::Metadata, combining with any provided by the
12350b57cec5SDimitry Andric // frontend as LLVM metadata. Once all functions are written, the PAL metadata
12360b57cec5SDimitry Andric // is then written as a single block in the .note section.
12370b57cec5SDimitry Andric void AMDGPUAsmPrinter::EmitPALMetadata(const MachineFunction &MF,
12380b57cec5SDimitry Andric        const SIProgramInfo &CurrentProgramInfo) {
12390b57cec5SDimitry Andric   const SIMachineFunctionInfo *MFI = MF.getInfo<SIMachineFunctionInfo>();
12400b57cec5SDimitry Andric   auto CC = MF.getFunction().getCallingConv();
12410b57cec5SDimitry Andric   auto MD = getTargetStreamer()->getPALMetadata();
1242*0fca6ea1SDimitry Andric   auto &Ctx = MF.getContext();
12430b57cec5SDimitry Andric 
12440b57cec5SDimitry Andric   MD->setEntryPoint(CC, MF.getFunction().getName());
1245*0fca6ea1SDimitry Andric   MD->setNumUsedVgprs(CC, CurrentProgramInfo.NumVGPRsForWavesPerEU, Ctx);
124681ad6265SDimitry Andric 
124781ad6265SDimitry Andric   // Only set AGPRs for supported devices
124881ad6265SDimitry Andric   const GCNSubtarget &STM = MF.getSubtarget<GCNSubtarget>();
124981ad6265SDimitry Andric   if (STM.hasMAIInsts()) {
125081ad6265SDimitry Andric     MD->setNumUsedAgprs(CC, CurrentProgramInfo.NumAccVGPR);
125181ad6265SDimitry Andric   }
125281ad6265SDimitry Andric 
1253*0fca6ea1SDimitry Andric   MD->setNumUsedSgprs(CC, CurrentProgramInfo.NumSGPRsForWavesPerEU, Ctx);
125406c3fb27SDimitry Andric   if (MD->getPALMajorVersion() < 3) {
1255*0fca6ea1SDimitry Andric     MD->setRsrc1(CC, CurrentProgramInfo.getPGMRSrc1(CC, STM, Ctx), Ctx);
1256e8d8bef9SDimitry Andric     if (AMDGPU::isCompute(CC)) {
1257*0fca6ea1SDimitry Andric       MD->setRsrc2(CC, CurrentProgramInfo.getComputePGMRSrc2(Ctx), Ctx);
12580b57cec5SDimitry Andric     } else {
1259*0fca6ea1SDimitry Andric       const MCExpr *HasScratchBlocks =
1260*0fca6ea1SDimitry Andric           MCBinaryExpr::createGT(CurrentProgramInfo.ScratchBlocks,
1261*0fca6ea1SDimitry Andric                                  MCConstantExpr::create(0, Ctx), Ctx);
1262*0fca6ea1SDimitry Andric       auto [Shift, Mask] = getShiftMask(C_00B84C_SCRATCH_EN);
1263*0fca6ea1SDimitry Andric       MD->setRsrc2(CC, maskShiftSet(HasScratchBlocks, Mask, Shift, Ctx), Ctx);
12640b57cec5SDimitry Andric     }
126506c3fb27SDimitry Andric   } else {
126606c3fb27SDimitry Andric     MD->setHwStage(CC, ".debug_mode", (bool)CurrentProgramInfo.DebugMode);
1267*0fca6ea1SDimitry Andric     MD->setHwStage(CC, ".scratch_en", msgpack::Type::Boolean,
1268*0fca6ea1SDimitry Andric                    CurrentProgramInfo.ScratchEnable);
1269*0fca6ea1SDimitry Andric     EmitPALMetadataCommon(MD, CurrentProgramInfo, CC, STM);
127006c3fb27SDimitry Andric   }
127106c3fb27SDimitry Andric 
12720b57cec5SDimitry Andric   // ScratchSize is in bytes, 16 aligned.
1273*0fca6ea1SDimitry Andric   MD->setScratchSize(
1274*0fca6ea1SDimitry Andric       CC,
1275*0fca6ea1SDimitry Andric       AMDGPUMCExpr::createAlignTo(CurrentProgramInfo.ScratchSize,
1276*0fca6ea1SDimitry Andric                                   MCConstantExpr::create(16, Ctx), Ctx),
1277*0fca6ea1SDimitry Andric       Ctx);
1278*0fca6ea1SDimitry Andric 
12790b57cec5SDimitry Andric   if (MF.getFunction().getCallingConv() == CallingConv::AMDGPU_PS) {
128081ad6265SDimitry Andric     unsigned ExtraLDSSize = STM.getGeneration() >= AMDGPUSubtarget::GFX11
128181ad6265SDimitry Andric                                 ? divideCeil(CurrentProgramInfo.LDSBlocks, 2)
128281ad6265SDimitry Andric                                 : CurrentProgramInfo.LDSBlocks;
128306c3fb27SDimitry Andric     if (MD->getPALMajorVersion() < 3) {
1284*0fca6ea1SDimitry Andric       MD->setRsrc2(
1285*0fca6ea1SDimitry Andric           CC,
1286*0fca6ea1SDimitry Andric           MCConstantExpr::create(S_00B02C_EXTRA_LDS_SIZE(ExtraLDSSize), Ctx),
1287*0fca6ea1SDimitry Andric           Ctx);
12880b57cec5SDimitry Andric       MD->setSpiPsInputEna(MFI->getPSInputEnable());
12890b57cec5SDimitry Andric       MD->setSpiPsInputAddr(MFI->getPSInputAddr());
129006c3fb27SDimitry Andric     } else {
129106c3fb27SDimitry Andric       // Graphics registers
129206c3fb27SDimitry Andric       const unsigned ExtraLdsDwGranularity =
129306c3fb27SDimitry Andric           STM.getGeneration() >= AMDGPUSubtarget::GFX11 ? 256 : 128;
129406c3fb27SDimitry Andric       MD->setGraphicsRegisters(
129506c3fb27SDimitry Andric           ".ps_extra_lds_size",
129606c3fb27SDimitry Andric           (unsigned)(ExtraLDSSize * ExtraLdsDwGranularity * sizeof(uint32_t)));
129706c3fb27SDimitry Andric 
129806c3fb27SDimitry Andric       // Set PsInputEna and PsInputAddr .spi_ps_input_ena and .spi_ps_input_addr
129906c3fb27SDimitry Andric       static StringLiteral const PsInputFields[] = {
130006c3fb27SDimitry Andric           ".persp_sample_ena",    ".persp_center_ena",
130106c3fb27SDimitry Andric           ".persp_centroid_ena",  ".persp_pull_model_ena",
130206c3fb27SDimitry Andric           ".linear_sample_ena",   ".linear_center_ena",
130306c3fb27SDimitry Andric           ".linear_centroid_ena", ".line_stipple_tex_ena",
130406c3fb27SDimitry Andric           ".pos_x_float_ena",     ".pos_y_float_ena",
130506c3fb27SDimitry Andric           ".pos_z_float_ena",     ".pos_w_float_ena",
130606c3fb27SDimitry Andric           ".front_face_ena",      ".ancillary_ena",
130706c3fb27SDimitry Andric           ".sample_coverage_ena", ".pos_fixed_pt_ena"};
130806c3fb27SDimitry Andric       unsigned PSInputEna = MFI->getPSInputEnable();
130906c3fb27SDimitry Andric       unsigned PSInputAddr = MFI->getPSInputAddr();
131006c3fb27SDimitry Andric       for (auto [Idx, Field] : enumerate(PsInputFields)) {
131106c3fb27SDimitry Andric         MD->setGraphicsRegisters(".spi_ps_input_ena", Field,
131206c3fb27SDimitry Andric                                  (bool)((PSInputEna >> Idx) & 1));
131306c3fb27SDimitry Andric         MD->setGraphicsRegisters(".spi_ps_input_addr", Field,
131406c3fb27SDimitry Andric                                  (bool)((PSInputAddr >> Idx) & 1));
131506c3fb27SDimitry Andric       }
131606c3fb27SDimitry Andric     }
13170b57cec5SDimitry Andric   }
13180b57cec5SDimitry Andric 
131906c3fb27SDimitry Andric   // For version 3 and above the wave front size is already set in the metadata
132006c3fb27SDimitry Andric   if (MD->getPALMajorVersion() < 3 && STM.isWave32())
13210b57cec5SDimitry Andric     MD->setWave32(MF.getFunction().getCallingConv());
13220b57cec5SDimitry Andric }
13230b57cec5SDimitry Andric 
1324e8d8bef9SDimitry Andric void AMDGPUAsmPrinter::emitPALFunctionMetadata(const MachineFunction &MF) {
1325e8d8bef9SDimitry Andric   auto *MD = getTargetStreamer()->getPALMetadata();
1326e8d8bef9SDimitry Andric   const MachineFrameInfo &MFI = MF.getFrameInfo();
13275f757f3fSDimitry Andric   StringRef FnName = MF.getFunction().getName();
13285f757f3fSDimitry Andric   MD->setFunctionScratchSize(FnName, MFI.getStackSize());
13295f757f3fSDimitry Andric   const GCNSubtarget &ST = MF.getSubtarget<GCNSubtarget>();
1330*0fca6ea1SDimitry Andric   MCContext &Ctx = MF.getContext();
1331fe6060f1SDimitry Andric 
1332*0fca6ea1SDimitry Andric   if (MD->getPALMajorVersion() < 3) {
1333e8d8bef9SDimitry Andric     // Set compute registers
1334*0fca6ea1SDimitry Andric     MD->setRsrc1(
1335*0fca6ea1SDimitry Andric         CallingConv::AMDGPU_CS,
1336*0fca6ea1SDimitry Andric         CurrentProgramInfo.getPGMRSrc1(CallingConv::AMDGPU_CS, ST, Ctx), Ctx);
1337*0fca6ea1SDimitry Andric     MD->setRsrc2(CallingConv::AMDGPU_CS,
1338*0fca6ea1SDimitry Andric                  CurrentProgramInfo.getComputePGMRSrc2(Ctx), Ctx);
1339*0fca6ea1SDimitry Andric   } else {
1340*0fca6ea1SDimitry Andric     EmitPALMetadataCommon(MD, CurrentProgramInfo, CallingConv::AMDGPU_CS, ST);
1341*0fca6ea1SDimitry Andric   }
1342fe6060f1SDimitry Andric 
1343fe6060f1SDimitry Andric   // Set optional info
13445f757f3fSDimitry Andric   MD->setFunctionLdsSize(FnName, CurrentProgramInfo.LDSSize);
13455f757f3fSDimitry Andric   MD->setFunctionNumUsedVgprs(FnName, CurrentProgramInfo.NumVGPRsForWavesPerEU);
13465f757f3fSDimitry Andric   MD->setFunctionNumUsedSgprs(FnName, CurrentProgramInfo.NumSGPRsForWavesPerEU);
1347e8d8bef9SDimitry Andric }
1348e8d8bef9SDimitry Andric 
13490b57cec5SDimitry Andric // This is supposed to be log2(Size)
13500b57cec5SDimitry Andric static amd_element_byte_size_t getElementByteSizeValue(unsigned Size) {
13510b57cec5SDimitry Andric   switch (Size) {
13520b57cec5SDimitry Andric   case 4:
13530b57cec5SDimitry Andric     return AMD_ELEMENT_4_BYTES;
13540b57cec5SDimitry Andric   case 8:
13550b57cec5SDimitry Andric     return AMD_ELEMENT_8_BYTES;
13560b57cec5SDimitry Andric   case 16:
13570b57cec5SDimitry Andric     return AMD_ELEMENT_16_BYTES;
13580b57cec5SDimitry Andric   default:
13590b57cec5SDimitry Andric     llvm_unreachable("invalid private_element_size");
13600b57cec5SDimitry Andric   }
13610b57cec5SDimitry Andric }
13620b57cec5SDimitry Andric 
1363*0fca6ea1SDimitry Andric void AMDGPUAsmPrinter::getAmdKernelCode(AMDGPUMCKernelCodeT &Out,
13640b57cec5SDimitry Andric                                         const SIProgramInfo &CurrentProgramInfo,
13650b57cec5SDimitry Andric                                         const MachineFunction &MF) const {
13660b57cec5SDimitry Andric   const Function &F = MF.getFunction();
13670b57cec5SDimitry Andric   assert(F.getCallingConv() == CallingConv::AMDGPU_KERNEL ||
13680b57cec5SDimitry Andric          F.getCallingConv() == CallingConv::SPIR_KERNEL);
13690b57cec5SDimitry Andric 
13700b57cec5SDimitry Andric   const SIMachineFunctionInfo *MFI = MF.getInfo<SIMachineFunctionInfo>();
13710b57cec5SDimitry Andric   const GCNSubtarget &STM = MF.getSubtarget<GCNSubtarget>();
1372*0fca6ea1SDimitry Andric   MCContext &Ctx = MF.getContext();
13730b57cec5SDimitry Andric 
1374*0fca6ea1SDimitry Andric   Out.initDefault(&STM, Ctx, /*InitMCExpr=*/false);
13750b57cec5SDimitry Andric 
1376*0fca6ea1SDimitry Andric   Out.compute_pgm_resource1_registers =
1377*0fca6ea1SDimitry Andric       CurrentProgramInfo.getComputePGMRSrc1(STM, Ctx);
1378*0fca6ea1SDimitry Andric   Out.compute_pgm_resource2_registers =
1379*0fca6ea1SDimitry Andric       CurrentProgramInfo.getComputePGMRSrc2(Ctx);
13800b57cec5SDimitry Andric   Out.code_properties |= AMD_CODE_PROPERTY_IS_PTR64;
13810b57cec5SDimitry Andric 
1382*0fca6ea1SDimitry Andric   Out.is_dynamic_callstack = CurrentProgramInfo.DynamicCallStack;
13830b57cec5SDimitry Andric 
1384*0fca6ea1SDimitry Andric   AMD_HSA_BITS_SET(Out.code_properties, AMD_CODE_PROPERTY_PRIVATE_ELEMENT_SIZE,
1385e8d8bef9SDimitry Andric                    getElementByteSizeValue(STM.getMaxPrivateElementSize(true)));
13860b57cec5SDimitry Andric 
13875f757f3fSDimitry Andric   const GCNUserSGPRUsageInfo &UserSGPRInfo = MFI->getUserSGPRInfo();
13885f757f3fSDimitry Andric   if (UserSGPRInfo.hasPrivateSegmentBuffer()) {
1389*0fca6ea1SDimitry Andric     Out.code_properties |= AMD_CODE_PROPERTY_ENABLE_SGPR_PRIVATE_SEGMENT_BUFFER;
13900b57cec5SDimitry Andric   }
13910b57cec5SDimitry Andric 
13925f757f3fSDimitry Andric   if (UserSGPRInfo.hasDispatchPtr())
13930b57cec5SDimitry Andric     Out.code_properties |= AMD_CODE_PROPERTY_ENABLE_SGPR_DISPATCH_PTR;
13940b57cec5SDimitry Andric 
13955f757f3fSDimitry Andric   if (UserSGPRInfo.hasQueuePtr() && CodeObjectVersion < AMDGPU::AMDHSA_COV5)
13960b57cec5SDimitry Andric     Out.code_properties |= AMD_CODE_PROPERTY_ENABLE_SGPR_QUEUE_PTR;
13970b57cec5SDimitry Andric 
13985f757f3fSDimitry Andric   if (UserSGPRInfo.hasKernargSegmentPtr())
13990b57cec5SDimitry Andric     Out.code_properties |= AMD_CODE_PROPERTY_ENABLE_SGPR_KERNARG_SEGMENT_PTR;
14000b57cec5SDimitry Andric 
14015f757f3fSDimitry Andric   if (UserSGPRInfo.hasDispatchID())
14020b57cec5SDimitry Andric     Out.code_properties |= AMD_CODE_PROPERTY_ENABLE_SGPR_DISPATCH_ID;
14030b57cec5SDimitry Andric 
14045f757f3fSDimitry Andric   if (UserSGPRInfo.hasFlatScratchInit())
14050b57cec5SDimitry Andric     Out.code_properties |= AMD_CODE_PROPERTY_ENABLE_SGPR_FLAT_SCRATCH_INIT;
14060b57cec5SDimitry Andric 
1407*0fca6ea1SDimitry Andric   if (UserSGPRInfo.hasPrivateSegmentSize())
1408*0fca6ea1SDimitry Andric     Out.code_properties |= AMD_CODE_PROPERTY_ENABLE_SGPR_PRIVATE_SEGMENT_SIZE;
1409*0fca6ea1SDimitry Andric 
14105f757f3fSDimitry Andric   if (UserSGPRInfo.hasDispatchPtr())
14110b57cec5SDimitry Andric     Out.code_properties |= AMD_CODE_PROPERTY_ENABLE_SGPR_DISPATCH_PTR;
14120b57cec5SDimitry Andric 
14130b57cec5SDimitry Andric   if (STM.isXNACKEnabled())
14140b57cec5SDimitry Andric     Out.code_properties |= AMD_CODE_PROPERTY_IS_XNACK_SUPPORTED;
14150b57cec5SDimitry Andric 
14168bcb0991SDimitry Andric   Align MaxKernArgAlign;
14170b57cec5SDimitry Andric   Out.kernarg_segment_byte_size = STM.getKernArgSegmentSize(F, MaxKernArgAlign);
14180b57cec5SDimitry Andric   Out.wavefront_sgpr_count = CurrentProgramInfo.NumSGPR;
14190b57cec5SDimitry Andric   Out.workitem_vgpr_count = CurrentProgramInfo.NumVGPR;
14200b57cec5SDimitry Andric   Out.workitem_private_segment_byte_size = CurrentProgramInfo.ScratchSize;
14210b57cec5SDimitry Andric   Out.workgroup_group_segment_byte_size = CurrentProgramInfo.LDSSize;
14220b57cec5SDimitry Andric 
14238bcb0991SDimitry Andric   // kernarg_segment_alignment is specified as log of the alignment.
14248bcb0991SDimitry Andric   // The minimum alignment is 16.
1425349cc55cSDimitry Andric   // FIXME: The metadata treats the minimum as 4?
14268bcb0991SDimitry Andric   Out.kernarg_segment_alignment = Log2(std::max(Align(16), MaxKernArgAlign));
14270b57cec5SDimitry Andric }
14280b57cec5SDimitry Andric 
14290b57cec5SDimitry Andric bool AMDGPUAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
14300b57cec5SDimitry Andric                                        const char *ExtraCode, raw_ostream &O) {
14310b57cec5SDimitry Andric   // First try the generic code, which knows about modifiers like 'c' and 'n'.
14320b57cec5SDimitry Andric   if (!AsmPrinter::PrintAsmOperand(MI, OpNo, ExtraCode, O))
14330b57cec5SDimitry Andric     return false;
14340b57cec5SDimitry Andric 
14350b57cec5SDimitry Andric   if (ExtraCode && ExtraCode[0]) {
14360b57cec5SDimitry Andric     if (ExtraCode[1] != 0)
14370b57cec5SDimitry Andric       return true; // Unknown modifier.
14380b57cec5SDimitry Andric 
14390b57cec5SDimitry Andric     switch (ExtraCode[0]) {
14400b57cec5SDimitry Andric     case 'r':
14410b57cec5SDimitry Andric       break;
14420b57cec5SDimitry Andric     default:
14430b57cec5SDimitry Andric       return true;
14440b57cec5SDimitry Andric     }
14450b57cec5SDimitry Andric   }
14460b57cec5SDimitry Andric 
14470b57cec5SDimitry Andric   // TODO: Should be able to support other operand types like globals.
14480b57cec5SDimitry Andric   const MachineOperand &MO = MI->getOperand(OpNo);
14490b57cec5SDimitry Andric   if (MO.isReg()) {
14500b57cec5SDimitry Andric     AMDGPUInstPrinter::printRegOperand(MO.getReg(), O,
14510b57cec5SDimitry Andric                                        *MF->getSubtarget().getRegisterInfo());
14520b57cec5SDimitry Andric     return false;
1453*0fca6ea1SDimitry Andric   }
1454*0fca6ea1SDimitry Andric   if (MO.isImm()) {
14555ffd83dbSDimitry Andric     int64_t Val = MO.getImm();
14565ffd83dbSDimitry Andric     if (AMDGPU::isInlinableIntLiteral(Val)) {
14575ffd83dbSDimitry Andric       O << Val;
14585ffd83dbSDimitry Andric     } else if (isUInt<16>(Val)) {
14595ffd83dbSDimitry Andric       O << format("0x%" PRIx16, static_cast<uint16_t>(Val));
14605ffd83dbSDimitry Andric     } else if (isUInt<32>(Val)) {
14615ffd83dbSDimitry Andric       O << format("0x%" PRIx32, static_cast<uint32_t>(Val));
14625ffd83dbSDimitry Andric     } else {
14635ffd83dbSDimitry Andric       O << format("0x%" PRIx64, static_cast<uint64_t>(Val));
14640b57cec5SDimitry Andric     }
14655ffd83dbSDimitry Andric     return false;
14665ffd83dbSDimitry Andric   }
14670b57cec5SDimitry Andric   return true;
14680b57cec5SDimitry Andric }
1469fe6060f1SDimitry Andric 
1470fe6060f1SDimitry Andric void AMDGPUAsmPrinter::getAnalysisUsage(AnalysisUsage &AU) const {
1471fe6060f1SDimitry Andric   AU.addRequired<AMDGPUResourceUsageAnalysis>();
1472fe6060f1SDimitry Andric   AU.addPreserved<AMDGPUResourceUsageAnalysis>();
1473fe6060f1SDimitry Andric   AsmPrinter::getAnalysisUsage(AU);
1474fe6060f1SDimitry Andric }
1475fcaf7f86SDimitry Andric 
1476fcaf7f86SDimitry Andric void AMDGPUAsmPrinter::emitResourceUsageRemarks(
1477fcaf7f86SDimitry Andric     const MachineFunction &MF, const SIProgramInfo &CurrentProgramInfo,
1478fcaf7f86SDimitry Andric     bool isModuleEntryFunction, bool hasMAIInsts) {
1479fcaf7f86SDimitry Andric   if (!ORE)
1480fcaf7f86SDimitry Andric     return;
1481fcaf7f86SDimitry Andric 
1482fcaf7f86SDimitry Andric   const char *Name = "kernel-resource-usage";
1483fcaf7f86SDimitry Andric   const char *Indent = "    ";
1484fcaf7f86SDimitry Andric 
1485fcaf7f86SDimitry Andric   // If the remark is not specifically enabled, do not output to yaml
1486fcaf7f86SDimitry Andric   LLVMContext &Ctx = MF.getFunction().getContext();
1487fcaf7f86SDimitry Andric   if (!Ctx.getDiagHandlerPtr()->isAnalysisRemarkEnabled(Name))
1488fcaf7f86SDimitry Andric     return;
1489fcaf7f86SDimitry Andric 
1490*0fca6ea1SDimitry Andric   // Currently non-kernel functions have no resources to emit.
1491*0fca6ea1SDimitry Andric   if (!isEntryFunctionCC(MF.getFunction().getCallingConv()))
1492*0fca6ea1SDimitry Andric     return;
1493*0fca6ea1SDimitry Andric 
1494fcaf7f86SDimitry Andric   auto EmitResourceUsageRemark = [&](StringRef RemarkName,
1495fcaf7f86SDimitry Andric                                      StringRef RemarkLabel, auto Argument) {
1496fcaf7f86SDimitry Andric     // Add an indent for every line besides the line with the kernel name. This
1497fcaf7f86SDimitry Andric     // makes it easier to tell which resource usage go with which kernel since
1498fcaf7f86SDimitry Andric     // the kernel name will always be displayed first.
1499fcaf7f86SDimitry Andric     std::string LabelStr = RemarkLabel.str() + ": ";
1500*0fca6ea1SDimitry Andric     if (RemarkName != "FunctionName")
1501fcaf7f86SDimitry Andric       LabelStr = Indent + LabelStr;
1502fcaf7f86SDimitry Andric 
1503fcaf7f86SDimitry Andric     ORE->emit([&]() {
1504fcaf7f86SDimitry Andric       return MachineOptimizationRemarkAnalysis(Name, RemarkName,
1505fcaf7f86SDimitry Andric                                                MF.getFunction().getSubprogram(),
1506fcaf7f86SDimitry Andric                                                &MF.front())
1507fcaf7f86SDimitry Andric              << LabelStr << ore::NV(RemarkName, Argument);
1508fcaf7f86SDimitry Andric     });
1509fcaf7f86SDimitry Andric   };
1510fcaf7f86SDimitry Andric 
1511fcaf7f86SDimitry Andric   // FIXME: Formatting here is pretty nasty because clang does not accept
1512fcaf7f86SDimitry Andric   // newlines from diagnostics. This forces us to emit multiple diagnostic
1513fcaf7f86SDimitry Andric   // remarks to simulate newlines. If and when clang does accept newlines, this
1514fcaf7f86SDimitry Andric   // formatting should be aggregated into one remark with newlines to avoid
1515fcaf7f86SDimitry Andric   // printing multiple diagnostic location and diag opts.
1516fcaf7f86SDimitry Andric   EmitResourceUsageRemark("FunctionName", "Function Name",
1517fcaf7f86SDimitry Andric                           MF.getFunction().getName());
1518*0fca6ea1SDimitry Andric   EmitResourceUsageRemark("NumSGPR", "SGPRs",
1519*0fca6ea1SDimitry Andric                           getMCExprStr(CurrentProgramInfo.NumSGPR));
1520*0fca6ea1SDimitry Andric   EmitResourceUsageRemark("NumVGPR", "VGPRs",
1521*0fca6ea1SDimitry Andric                           getMCExprStr(CurrentProgramInfo.NumArchVGPR));
1522*0fca6ea1SDimitry Andric   if (hasMAIInsts) {
1523*0fca6ea1SDimitry Andric     EmitResourceUsageRemark("NumAGPR", "AGPRs",
1524*0fca6ea1SDimitry Andric                             getMCExprStr(CurrentProgramInfo.NumAccVGPR));
1525*0fca6ea1SDimitry Andric   }
1526fcaf7f86SDimitry Andric   EmitResourceUsageRemark("ScratchSize", "ScratchSize [bytes/lane]",
1527*0fca6ea1SDimitry Andric                           getMCExprStr(CurrentProgramInfo.ScratchSize));
1528*0fca6ea1SDimitry Andric   int64_t DynStack;
1529*0fca6ea1SDimitry Andric   bool DynStackEvaluatable =
1530*0fca6ea1SDimitry Andric       CurrentProgramInfo.DynamicCallStack->evaluateAsAbsolute(DynStack);
15315f757f3fSDimitry Andric   StringRef DynamicStackStr =
1532*0fca6ea1SDimitry Andric       DynStackEvaluatable && DynStack ? "True" : "False";
15335f757f3fSDimitry Andric   EmitResourceUsageRemark("DynamicStack", "Dynamic Stack", DynamicStackStr);
1534fcaf7f86SDimitry Andric   EmitResourceUsageRemark("Occupancy", "Occupancy [waves/SIMD]",
1535*0fca6ea1SDimitry Andric                           getMCExprStr(CurrentProgramInfo.Occupancy));
1536fcaf7f86SDimitry Andric   EmitResourceUsageRemark("SGPRSpill", "SGPRs Spill",
1537fcaf7f86SDimitry Andric                           CurrentProgramInfo.SGPRSpill);
1538fcaf7f86SDimitry Andric   EmitResourceUsageRemark("VGPRSpill", "VGPRs Spill",
1539fcaf7f86SDimitry Andric                           CurrentProgramInfo.VGPRSpill);
1540fcaf7f86SDimitry Andric   if (isModuleEntryFunction)
1541fcaf7f86SDimitry Andric     EmitResourceUsageRemark("BytesLDS", "LDS Size [bytes/block]",
1542fcaf7f86SDimitry Andric                             CurrentProgramInfo.LDSSize);
1543fcaf7f86SDimitry Andric }
1544