1*0b57cec5SDimitry Andric //===-- R600AsmPrinter.cpp - R600 Assebly printer ------------------------===// 2*0b57cec5SDimitry Andric // 3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*0b57cec5SDimitry Andric // 7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 8*0b57cec5SDimitry Andric // 9*0b57cec5SDimitry Andric /// \file 10*0b57cec5SDimitry Andric /// 11*0b57cec5SDimitry Andric /// The R600AsmPrinter is used to print both assembly string and also binary 12*0b57cec5SDimitry Andric /// code. When passed an MCAsmStreamer it prints assembly and when passed 13*0b57cec5SDimitry Andric /// an MCObjectStreamer it outputs binary code. 14*0b57cec5SDimitry Andric // 15*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 16*0b57cec5SDimitry Andric 17*0b57cec5SDimitry Andric #include "R600AsmPrinter.h" 18*0b57cec5SDimitry Andric #include "AMDGPUSubtarget.h" 19*0b57cec5SDimitry Andric #include "R600Defines.h" 20*0b57cec5SDimitry Andric #include "R600MachineFunctionInfo.h" 21*0b57cec5SDimitry Andric #include "MCTargetDesc/AMDGPUMCTargetDesc.h" 22*0b57cec5SDimitry Andric #include "llvm/BinaryFormat/ELF.h" 23*0b57cec5SDimitry Andric #include "llvm/MC/MCContext.h" 24*0b57cec5SDimitry Andric #include "llvm/MC/MCSectionELF.h" 25*0b57cec5SDimitry Andric #include "llvm/MC/MCStreamer.h" 26*0b57cec5SDimitry Andric #include "llvm/Target/TargetLoweringObjectFile.h" 27*0b57cec5SDimitry Andric 28*0b57cec5SDimitry Andric using namespace llvm; 29*0b57cec5SDimitry Andric 30*0b57cec5SDimitry Andric AsmPrinter * 31*0b57cec5SDimitry Andric llvm::createR600AsmPrinterPass(TargetMachine &TM, 32*0b57cec5SDimitry Andric std::unique_ptr<MCStreamer> &&Streamer) { 33*0b57cec5SDimitry Andric return new R600AsmPrinter(TM, std::move(Streamer)); 34*0b57cec5SDimitry Andric } 35*0b57cec5SDimitry Andric 36*0b57cec5SDimitry Andric R600AsmPrinter::R600AsmPrinter(TargetMachine &TM, 37*0b57cec5SDimitry Andric std::unique_ptr<MCStreamer> Streamer) 38*0b57cec5SDimitry Andric : AsmPrinter(TM, std::move(Streamer)) { } 39*0b57cec5SDimitry Andric 40*0b57cec5SDimitry Andric StringRef R600AsmPrinter::getPassName() const { 41*0b57cec5SDimitry Andric return "R600 Assembly Printer"; 42*0b57cec5SDimitry Andric } 43*0b57cec5SDimitry Andric 44*0b57cec5SDimitry Andric void R600AsmPrinter::EmitProgramInfoR600(const MachineFunction &MF) { 45*0b57cec5SDimitry Andric unsigned MaxGPR = 0; 46*0b57cec5SDimitry Andric bool killPixel = false; 47*0b57cec5SDimitry Andric const R600Subtarget &STM = MF.getSubtarget<R600Subtarget>(); 48*0b57cec5SDimitry Andric const R600RegisterInfo *RI = STM.getRegisterInfo(); 49*0b57cec5SDimitry Andric const R600MachineFunctionInfo *MFI = MF.getInfo<R600MachineFunctionInfo>(); 50*0b57cec5SDimitry Andric 51*0b57cec5SDimitry Andric for (const MachineBasicBlock &MBB : MF) { 52*0b57cec5SDimitry Andric for (const MachineInstr &MI : MBB) { 53*0b57cec5SDimitry Andric if (MI.getOpcode() == R600::KILLGT) 54*0b57cec5SDimitry Andric killPixel = true; 55*0b57cec5SDimitry Andric unsigned numOperands = MI.getNumOperands(); 56*0b57cec5SDimitry Andric for (unsigned op_idx = 0; op_idx < numOperands; op_idx++) { 57*0b57cec5SDimitry Andric const MachineOperand &MO = MI.getOperand(op_idx); 58*0b57cec5SDimitry Andric if (!MO.isReg()) 59*0b57cec5SDimitry Andric continue; 60*0b57cec5SDimitry Andric unsigned HWReg = RI->getHWRegIndex(MO.getReg()); 61*0b57cec5SDimitry Andric 62*0b57cec5SDimitry Andric // Register with value > 127 aren't GPR 63*0b57cec5SDimitry Andric if (HWReg > 127) 64*0b57cec5SDimitry Andric continue; 65*0b57cec5SDimitry Andric MaxGPR = std::max(MaxGPR, HWReg); 66*0b57cec5SDimitry Andric } 67*0b57cec5SDimitry Andric } 68*0b57cec5SDimitry Andric } 69*0b57cec5SDimitry Andric 70*0b57cec5SDimitry Andric unsigned RsrcReg; 71*0b57cec5SDimitry Andric if (STM.getGeneration() >= AMDGPUSubtarget::EVERGREEN) { 72*0b57cec5SDimitry Andric // Evergreen / Northern Islands 73*0b57cec5SDimitry Andric switch (MF.getFunction().getCallingConv()) { 74*0b57cec5SDimitry Andric default: LLVM_FALLTHROUGH; 75*0b57cec5SDimitry Andric case CallingConv::AMDGPU_CS: RsrcReg = R_0288D4_SQ_PGM_RESOURCES_LS; break; 76*0b57cec5SDimitry Andric case CallingConv::AMDGPU_GS: RsrcReg = R_028878_SQ_PGM_RESOURCES_GS; break; 77*0b57cec5SDimitry Andric case CallingConv::AMDGPU_PS: RsrcReg = R_028844_SQ_PGM_RESOURCES_PS; break; 78*0b57cec5SDimitry Andric case CallingConv::AMDGPU_VS: RsrcReg = R_028860_SQ_PGM_RESOURCES_VS; break; 79*0b57cec5SDimitry Andric } 80*0b57cec5SDimitry Andric } else { 81*0b57cec5SDimitry Andric // R600 / R700 82*0b57cec5SDimitry Andric switch (MF.getFunction().getCallingConv()) { 83*0b57cec5SDimitry Andric default: LLVM_FALLTHROUGH; 84*0b57cec5SDimitry Andric case CallingConv::AMDGPU_GS: LLVM_FALLTHROUGH; 85*0b57cec5SDimitry Andric case CallingConv::AMDGPU_CS: LLVM_FALLTHROUGH; 86*0b57cec5SDimitry Andric case CallingConv::AMDGPU_VS: RsrcReg = R_028868_SQ_PGM_RESOURCES_VS; break; 87*0b57cec5SDimitry Andric case CallingConv::AMDGPU_PS: RsrcReg = R_028850_SQ_PGM_RESOURCES_PS; break; 88*0b57cec5SDimitry Andric } 89*0b57cec5SDimitry Andric } 90*0b57cec5SDimitry Andric 91*0b57cec5SDimitry Andric OutStreamer->EmitIntValue(RsrcReg, 4); 92*0b57cec5SDimitry Andric OutStreamer->EmitIntValue(S_NUM_GPRS(MaxGPR + 1) | 93*0b57cec5SDimitry Andric S_STACK_SIZE(MFI->CFStackSize), 4); 94*0b57cec5SDimitry Andric OutStreamer->EmitIntValue(R_02880C_DB_SHADER_CONTROL, 4); 95*0b57cec5SDimitry Andric OutStreamer->EmitIntValue(S_02880C_KILL_ENABLE(killPixel), 4); 96*0b57cec5SDimitry Andric 97*0b57cec5SDimitry Andric if (AMDGPU::isCompute(MF.getFunction().getCallingConv())) { 98*0b57cec5SDimitry Andric OutStreamer->EmitIntValue(R_0288E8_SQ_LDS_ALLOC, 4); 99*0b57cec5SDimitry Andric OutStreamer->EmitIntValue(alignTo(MFI->getLDSSize(), 4) >> 2, 4); 100*0b57cec5SDimitry Andric } 101*0b57cec5SDimitry Andric } 102*0b57cec5SDimitry Andric 103*0b57cec5SDimitry Andric bool R600AsmPrinter::runOnMachineFunction(MachineFunction &MF) { 104*0b57cec5SDimitry Andric 105*0b57cec5SDimitry Andric 106*0b57cec5SDimitry Andric // Functions needs to be cacheline (256B) aligned. 107*0b57cec5SDimitry Andric MF.ensureAlignment(8); 108*0b57cec5SDimitry Andric 109*0b57cec5SDimitry Andric SetupMachineFunction(MF); 110*0b57cec5SDimitry Andric 111*0b57cec5SDimitry Andric MCContext &Context = getObjFileLowering().getContext(); 112*0b57cec5SDimitry Andric MCSectionELF *ConfigSection = 113*0b57cec5SDimitry Andric Context.getELFSection(".AMDGPU.config", ELF::SHT_PROGBITS, 0); 114*0b57cec5SDimitry Andric OutStreamer->SwitchSection(ConfigSection); 115*0b57cec5SDimitry Andric 116*0b57cec5SDimitry Andric EmitProgramInfoR600(MF); 117*0b57cec5SDimitry Andric 118*0b57cec5SDimitry Andric EmitFunctionBody(); 119*0b57cec5SDimitry Andric 120*0b57cec5SDimitry Andric if (isVerbose()) { 121*0b57cec5SDimitry Andric MCSectionELF *CommentSection = 122*0b57cec5SDimitry Andric Context.getELFSection(".AMDGPU.csdata", ELF::SHT_PROGBITS, 0); 123*0b57cec5SDimitry Andric OutStreamer->SwitchSection(CommentSection); 124*0b57cec5SDimitry Andric 125*0b57cec5SDimitry Andric R600MachineFunctionInfo *MFI = MF.getInfo<R600MachineFunctionInfo>(); 126*0b57cec5SDimitry Andric OutStreamer->emitRawComment( 127*0b57cec5SDimitry Andric Twine("SQ_PGM_RESOURCES:STACK_SIZE = " + Twine(MFI->CFStackSize))); 128*0b57cec5SDimitry Andric } 129*0b57cec5SDimitry Andric 130*0b57cec5SDimitry Andric return false; 131*0b57cec5SDimitry Andric } 132*0b57cec5SDimitry Andric 133