//===-- SIAssignInterpRegs.cpp - Assign interpolation registers -----------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // /// \file /// \brief This pass maps the pseudo interpolation registers to the correct physical /// registers. // /// Prior to executing a fragment shader, the GPU loads interpolation /// parameters into physical registers. The specific physical register that each /// interpolation parameter ends up in depends on the type of the interpolation /// parameter as well as how many interpolation parameters are used by the /// shader. // //===----------------------------------------------------------------------===// #include "AMDGPU.h" #include "AMDIL.h" #include "SIMachineFunctionInfo.h" #include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/MachineRegisterInfo.h" using namespace llvm; namespace { class SIAssignInterpRegsPass : public MachineFunctionPass { private: static char ID; TargetMachine &TM; void addLiveIn(MachineFunction * MF, MachineRegisterInfo & MRI, unsigned physReg, unsigned virtReg); public: SIAssignInterpRegsPass(TargetMachine &tm) : MachineFunctionPass(ID), TM(tm) { } virtual bool runOnMachineFunction(MachineFunction &MF); const char *getPassName() const { return "SI Assign intrpolation registers"; } }; } // End anonymous namespace char SIAssignInterpRegsPass::ID = 0; #define INTERP_VALUES 16 #define REQUIRED_VALUE_MAX_INDEX 7 struct InterpInfo { bool Enabled; unsigned Regs[3]; unsigned RegCount; }; FunctionPass *llvm::createSIAssignInterpRegsPass(TargetMachine &tm) { return new SIAssignInterpRegsPass(tm); } bool SIAssignInterpRegsPass::runOnMachineFunction(MachineFunction &MF) { struct InterpInfo InterpUse[INTERP_VALUES] = { {false, {AMDGPU::PERSP_SAMPLE_I, AMDGPU::PERSP_SAMPLE_J}, 2}, {false, {AMDGPU::PERSP_CENTER_I, AMDGPU::PERSP_CENTER_J}, 2}, {false, {AMDGPU::PERSP_CENTROID_I, AMDGPU::PERSP_CENTROID_J}, 2}, {false, {AMDGPU::PERSP_I_W, AMDGPU::PERSP_J_W, AMDGPU::PERSP_1_W}, 3}, {false, {AMDGPU::LINEAR_SAMPLE_I, AMDGPU::LINEAR_SAMPLE_J}, 2}, {false, {AMDGPU::LINEAR_CENTER_I, AMDGPU::LINEAR_CENTER_J}, 2}, {false, {AMDGPU::LINEAR_CENTROID_I, AMDGPU::LINEAR_CENTROID_J}, 2}, {false, {AMDGPU::LINE_STIPPLE_TEX_COORD}, 1}, {false, {AMDGPU::POS_X_FLOAT}, 1}, {false, {AMDGPU::POS_Y_FLOAT}, 1}, {false, {AMDGPU::POS_Z_FLOAT}, 1}, {false, {AMDGPU::POS_W_FLOAT}, 1}, {false, {AMDGPU::FRONT_FACE}, 1}, {false, {AMDGPU::ANCILLARY}, 1}, {false, {AMDGPU::SAMPLE_COVERAGE}, 1}, {false, {AMDGPU::POS_FIXED_PT}, 1} }; SIMachineFunctionInfo * MFI = MF.getInfo(); // This pass is only needed for pixel shaders. if (MFI->ShaderType != ShaderType::PIXEL) { return false; } MachineRegisterInfo &MRI = MF.getRegInfo(); bool ForceEnable = true; // First pass, mark the interpolation values that are used. for (unsigned InterpIdx = 0; InterpIdx < INTERP_VALUES; InterpIdx++) { for (unsigned RegIdx = 0; RegIdx < InterpUse[InterpIdx].RegCount; RegIdx++) { InterpUse[InterpIdx].Enabled = InterpUse[InterpIdx].Enabled || !MRI.use_empty(InterpUse[InterpIdx].Regs[RegIdx]); if (InterpUse[InterpIdx].Enabled && InterpIdx <= REQUIRED_VALUE_MAX_INDEX) { ForceEnable = false; } } } // At least one interpolation mode must be enabled or else the GPU will hang. if (ForceEnable) { InterpUse[0].Enabled = true; } unsigned UsedVgprs = 0; // Second pass, replace with VGPRs. for (unsigned InterpIdx = 0; InterpIdx < INTERP_VALUES; InterpIdx++) { if (!InterpUse[InterpIdx].Enabled) { continue; } MFI->SPIPSInputAddr |= (1 << InterpIdx); for (unsigned RegIdx = 0; RegIdx < InterpUse[InterpIdx].RegCount; RegIdx++, UsedVgprs++) { unsigned NewReg = AMDGPU::VReg_32RegClass.getRegister(UsedVgprs); unsigned VirtReg = MRI.createVirtualRegister(&AMDGPU::VReg_32RegClass); MRI.replaceRegWith(InterpUse[InterpIdx].Regs[RegIdx], VirtReg); addLiveIn(&MF, MRI, NewReg, VirtReg); } } return false; } void SIAssignInterpRegsPass::addLiveIn(MachineFunction * MF, MachineRegisterInfo & MRI, unsigned physReg, unsigned virtReg) { const TargetInstrInfo * TII = TM.getInstrInfo(); if (!MRI.isLiveIn(physReg)) { MRI.addLiveIn(physReg, virtReg); MF->front().addLiveIn(physReg); BuildMI(MF->front(), MF->front().begin(), DebugLoc(), TII->get(TargetOpcode::COPY), virtReg) .addReg(physReg); } else { MRI.replaceRegWith(virtReg, MRI.getLiveInVirtReg(physReg)); } }