mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-10-26 06:22:56 +02:00
6f17e7033b
A new backend supporting AMD GPUs: Radeon HD2XXX - HD7XXX llvm-svn: 169915
153 lines
5.0 KiB
C++
153 lines
5.0 KiB
C++
//===-- 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<SIMachineFunctionInfo>();
|
|
// 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));
|
|
}
|
|
}
|