R600/SI: add post ISel folding for SI v2

Include immediate folding and SGPR limit handling for VOP3 instructions.

v2: remove leftover hasExtraSrcRegAllocReq

Signed-off-by: Christian König <christian.koenig@amd.com>
Reviewed-by: Tom Stellard <thomas.stellard@amd.com>

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@176101 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Christian Konig 2013-02-26 17:52:23 +00:00
parent c018ecac2f
commit d3b5509b80
5 changed files with 231 additions and 23 deletions

View File

@ -16,6 +16,7 @@
#include "AMDGPURegisterInfo.h"
#include "AMDILDevices.h"
#include "R600InstrInfo.h"
#include "SIISelLowering.h"
#include "llvm/ADT/ValueMap.h"
#include "llvm/CodeGen/PseudoSourceValue.h"
#include "llvm/CodeGen/SelectionDAGISel.h"

View File

@ -26,7 +26,8 @@ using namespace llvm;
SITargetLowering::SITargetLowering(TargetMachine &TM) :
AMDGPUTargetLowering(TM),
TII(static_cast<const SIInstrInfo*>(TM.getInstrInfo())) {
TII(static_cast<const SIInstrInfo*>(TM.getInstrInfo())),
TRI(TM.getRegisterInfo()) {
addRegisterClass(MVT::v4f32, &AMDGPU::VReg_128RegClass);
addRegisterClass(MVT::f32, &AMDGPU::VReg_32RegClass);
addRegisterClass(MVT::i32, &AMDGPU::VReg_32RegClass);
@ -358,8 +359,206 @@ SDValue SITargetLowering::PerformDAGCombine(SDNode *N,
return SDValue();
}
/// \brief Test if RegClass is one of the VSrc classes
static bool isVSrc(unsigned RegClass) {
return AMDGPU::VSrc_32RegClassID == RegClass ||
AMDGPU::VSrc_64RegClassID == RegClass;
}
/// \brief Test if RegClass is one of the SSrc classes
static bool isSSrc(unsigned RegClass) {
return AMDGPU::SSrc_32RegClassID == RegClass ||
AMDGPU::SSrc_64RegClassID == RegClass;
}
/// \brief Analyze the possible immediate value Op
///
/// Returns -1 if it isn't an immediate, 0 if it's and inline immediate
/// and the immediate value if it's a literal immediate
int32_t SITargetLowering::analyzeImmediate(const SDNode *N) const {
union {
int32_t I;
float F;
} Imm;
if (const ConstantSDNode *Node = dyn_cast<ConstantSDNode>(N))
Imm.I = Node->getSExtValue();
else if (const ConstantFPSDNode *Node = dyn_cast<ConstantFPSDNode>(N))
Imm.F = Node->getValueAPF().convertToFloat();
else
return -1; // It isn't an immediate
if ((Imm.I >= -16 && Imm.I <= 64) ||
Imm.F == 0.5f || Imm.F == -0.5f ||
Imm.F == 1.0f || Imm.F == -1.0f ||
Imm.F == 2.0f || Imm.F == -2.0f ||
Imm.F == 4.0f || Imm.F == -4.0f)
return 0; // It's an inline immediate
return Imm.I; // It's a literal immediate
}
/// \brief Try to fold an immediate directly into an instruction
bool SITargetLowering::foldImm(SDValue &Operand, int32_t &Immediate,
bool &ScalarSlotUsed) const {
MachineSDNode *Mov = dyn_cast<MachineSDNode>(Operand);
if (Mov == 0 || !TII->isMov(Mov->getMachineOpcode()))
return false;
const SDValue &Op = Mov->getOperand(0);
int32_t Value = analyzeImmediate(Op.getNode());
if (Value == -1) {
// Not an immediate at all
return false;
} else if (Value == 0) {
// Inline immediates can always be fold
Operand = Op;
return true;
} else if (Value == Immediate) {
// Already fold literal immediate
Operand = Op;
return true;
} else if (!ScalarSlotUsed && !Immediate) {
// Fold this literal immediate
ScalarSlotUsed = true;
Immediate = Value;
Operand = Op;
return true;
}
return false;
}
/// \brief Does "Op" fit into register class "RegClass" ?
bool SITargetLowering::fitsRegClass(SelectionDAG &DAG, SDValue &Op,
unsigned RegClass) const {
MachineRegisterInfo &MRI = DAG.getMachineFunction().getRegInfo();
SDNode *Node = Op.getNode();
int OpClass;
if (MachineSDNode *MN = dyn_cast<MachineSDNode>(Node)) {
const MCInstrDesc &Desc = TII->get(MN->getMachineOpcode());
OpClass = Desc.OpInfo[Op.getResNo()].RegClass;
} else if (Node->getOpcode() == ISD::CopyFromReg) {
RegisterSDNode *Reg = cast<RegisterSDNode>(Node->getOperand(1).getNode());
OpClass = MRI.getRegClass(Reg->getReg())->getID();
} else
return false;
if (OpClass == -1)
return false;
return TRI->getRegClass(RegClass)->hasSubClassEq(TRI->getRegClass(OpClass));
}
/// \brief Make sure that we don't exeed the number of allowed scalars
void SITargetLowering::ensureSRegLimit(SelectionDAG &DAG, SDValue &Operand,
unsigned RegClass,
bool &ScalarSlotUsed) const {
// First map the operands register class to a destination class
if (RegClass == AMDGPU::VSrc_32RegClassID)
RegClass = AMDGPU::VReg_32RegClassID;
else if (RegClass == AMDGPU::VSrc_64RegClassID)
RegClass = AMDGPU::VReg_64RegClassID;
else
return;
// Nothing todo if they fit naturaly
if (fitsRegClass(DAG, Operand, RegClass))
return;
// If the scalar slot isn't used yet use it now
if (!ScalarSlotUsed) {
ScalarSlotUsed = true;
return;
}
// This is a conservative aproach, it is possible that we can't determine
// the correct register class and copy too often, but better save than sorry.
SDValue RC = DAG.getTargetConstant(RegClass, MVT::i32);
SDNode *Node = DAG.getMachineNode(TargetOpcode::COPY_TO_REGCLASS, DebugLoc(),
Operand.getValueType(), Operand, RC);
Operand = SDValue(Node, 0);
}
SDNode *SITargetLowering::PostISelFolding(MachineSDNode *Node,
SelectionDAG &DAG) const {
// TODO: Implement immediate folding
return Node;
// Original encoding (either e32 or e64)
int Opcode = Node->getMachineOpcode();
const MCInstrDesc *Desc = &TII->get(Opcode);
unsigned NumDefs = Desc->getNumDefs();
unsigned NumOps = Desc->getNumOperands();
int32_t Immediate = Desc->getSize() == 4 ? 0 : -1;
bool HaveVSrc = false, HaveSSrc = false;
// First figure out what we alread have in this instruction
for (unsigned i = 0, e = Node->getNumOperands(), Op = NumDefs;
i != e && Op < NumOps; ++i, ++Op) {
unsigned RegClass = Desc->OpInfo[Op].RegClass;
if (isVSrc(RegClass))
HaveVSrc = true;
else if (isSSrc(RegClass))
HaveSSrc = true;
else
continue;
int32_t Imm = analyzeImmediate(Node->getOperand(i).getNode());
if (Imm != -1 && Imm != 0) {
// Literal immediate
Immediate = Imm;
}
}
// If we neither have VSrc nor SSrc it makes no sense to continue
if (!HaveVSrc && !HaveSSrc)
return Node;
// No scalar allowed when we have both VSrc and SSrc
bool ScalarSlotUsed = HaveVSrc && HaveSSrc;
// Second go over the operands and try to fold them
std::vector<SDValue> Ops;
for (unsigned i = 0, e = Node->getNumOperands(), Op = NumDefs;
i != e && Op < NumOps; ++i, ++Op) {
const SDValue &Operand = Node->getOperand(i);
Ops.push_back(Operand);
// Already folded immediate ?
if (isa<ConstantSDNode>(Operand.getNode()) ||
isa<ConstantFPSDNode>(Operand.getNode()))
continue;
// Is this a VSrc or SSrc operand ?
unsigned RegClass = Desc->OpInfo[Op].RegClass;
if (!isVSrc(RegClass) && !isSSrc(RegClass))
continue;
// Try to fold the immediates
if (!foldImm(Ops[i], Immediate, ScalarSlotUsed)) {
// Folding didn't worked, make sure we don't hit the SReg limit
ensureSRegLimit(DAG, Ops[i], RegClass, ScalarSlotUsed);
}
}
// Add optional chain and glue
for (unsigned i = NumOps - NumDefs, e = Node->getNumOperands(); i < e; ++i)
Ops.push_back(Node->getOperand(i));
// Update the instruction parameters
return DAG.UpdateNodeOperands(Node, Ops.data(), Ops.size());
}

View File

@ -22,6 +22,7 @@ namespace llvm {
class SITargetLowering : public AMDGPUTargetLowering {
const SIInstrInfo * TII;
const TargetRegisterInfo * TRI;
void LowerMOV_IMM(MachineInstr *MI, MachineBasicBlock &BB,
MachineBasicBlock::iterator I, unsigned Opocde) const;
@ -34,6 +35,12 @@ class SITargetLowering : public AMDGPUTargetLowering {
SDValue LowerSELECT_CC(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerBRCOND(SDValue Op, SelectionDAG &DAG) const;
bool foldImm(SDValue &Operand, int32_t &Immediate,
bool &ScalarSlotUsed) const;
bool fitsRegClass(SelectionDAG &DAG, SDValue &Op, unsigned RegClass) const;
void ensureSRegLimit(SelectionDAG &DAG, SDValue &Operand,
unsigned RegClass, bool &ScalarSlotUsed) const;
public:
SITargetLowering(TargetMachine &tm);
virtual MachineBasicBlock * EmitInstrWithCustomInserter(MachineInstr * MI,
@ -42,6 +49,8 @@ public:
virtual SDValue LowerOperation(SDValue Op, SelectionDAG &DAG) const;
virtual SDValue PerformDAGCombine(SDNode *N, DAGCombinerInfo &DCI) const;
virtual SDNode *PostISelFolding(MachineSDNode *N, SelectionDAG &DAG) const;
int32_t analyzeImmediate(const SDNode *N) const;
};
} // End namespace llvm

View File

@ -40,11 +40,10 @@ def IMM12bit : ImmLeaf <
[{return isUInt<12>(Imm);}]
>;
class InlineImm <ValueType vt> : ImmLeaf <vt, [{
return -16 <= Imm && Imm <= 64;
class InlineImm <ValueType vt> : PatLeaf <(vt imm), [{
return ((const SITargetLowering &)TLI).analyzeImmediate(N) == 0;
}]>;
//===----------------------------------------------------------------------===//
// SI assembler operands
//===----------------------------------------------------------------------===//
@ -181,7 +180,7 @@ multiclass VOP2_Helper <bits<6> op, RegisterClass vrc, RegisterClass arc,
def _e64 : VOP3 <
{1, 0, 0, op{5}, op{4}, op{3}, op{2}, op{1}, op{0}},
(outs vrc:$dst),
(ins arc:$src0, vrc:$src1,
(ins arc:$src0, arc:$src1,
i32imm:$abs, i32imm:$clamp,
i32imm:$omod, i32imm:$neg),
opName#"_e64 $dst, $src0, $src1, $abs, $clamp, $omod, $neg", []
@ -206,7 +205,7 @@ multiclass VOP2b_32 <bits<6> op, string opName, list<dag> pattern> {
def _e64 : VOP3b <
{1, 0, 0, op{5}, op{4}, op{3}, op{2}, op{1}, op{0}},
(outs VReg_32:$dst),
(ins VSrc_32:$src0, VReg_32:$src1,
(ins VSrc_32:$src0, VSrc_32:$src1,
i32imm:$abs, i32imm:$clamp,
i32imm:$omod, i32imm:$neg),
opName#"_e64 $dst, $src0, $src1, $abs, $clamp, $omod, $neg", []
@ -230,12 +229,12 @@ multiclass VOPC_Helper <bits<8> op, RegisterClass vrc, RegisterClass arc,
def _e64 : VOP3 <
{0, op{7}, op{6}, op{5}, op{4}, op{3}, op{2}, op{1}, op{0}},
(outs SReg_64:$dst),
(ins arc:$src0, vrc:$src1,
(ins arc:$src0, arc:$src1,
InstFlag:$abs, InstFlag:$clamp,
InstFlag:$omod, InstFlag:$neg),
opName#"_e64 $dst, $src0, $src1, $abs, $clamp, $omod, $neg",
!if(!eq(!cast<string>(cond), "COND_NULL"), []<dag>,
[(set SReg_64:$dst, (i1 (setcc (vt arc:$src0), vrc:$src1, cond)))]
[(set SReg_64:$dst, (i1 (setcc (vt arc:$src0), arc:$src1, cond)))]
)
> {
let SRC2 = SIOperand.ZERO;
@ -252,14 +251,14 @@ multiclass VOPC_64 <bits<8> op, string opName,
class VOP3_32 <bits<9> op, string opName, list<dag> pattern> : VOP3 <
op, (outs VReg_32:$dst),
(ins VSrc_32:$src0, VReg_32:$src1, VReg_32:$src2,
(ins VSrc_32:$src0, VSrc_32:$src1, VSrc_32:$src2,
i32imm:$abs, i32imm:$clamp, i32imm:$omod, i32imm:$neg),
opName#" $dst, $src0, $src1, $src2, $abs, $clamp, $omod, $neg", pattern
>;
class VOP3_64 <bits<9> op, string opName, list<dag> pattern> : VOP3 <
op, (outs VReg_64:$dst),
(ins VSrc_64:$src0, VReg_64:$src1, VReg_64:$src2,
(ins VSrc_64:$src0, VSrc_64:$src1, VSrc_64:$src2,
i32imm:$abs, i32imm:$clamp, i32imm:$omod, i32imm:$neg),
opName#" $dst, $src0, $src1, $src2, $abs, $clamp, $omod, $neg", pattern
>;

View File

@ -732,17 +732,17 @@ def V_CNDMASK_B32_e32 : VOP2 <0x00000000, (outs VReg_32:$dst),
}
def V_CNDMASK_B32_e64 : VOP3 <0x00000100, (outs VReg_32:$dst),
(ins VReg_32:$src0, VReg_32:$src1, SReg_64:$src2,
(ins VSrc_32:$src0, VSrc_32:$src1, SSrc_64:$src2,
InstFlag:$abs, InstFlag:$clamp, InstFlag:$omod, InstFlag:$neg),
"V_CNDMASK_B32_e64 $dst, $src0, $src1, $src2, $abs, $clamp, $omod, $neg",
[(set (i32 VReg_32:$dst), (select (i1 SReg_64:$src2),
VReg_32:$src1, VReg_32:$src0))]
[(set (i32 VReg_32:$dst), (select (i1 SSrc_64:$src2),
VSrc_32:$src1, VSrc_32:$src0))]
>;
//f32 pattern for V_CNDMASK_B32_e64
def : Pat <
(f32 (select (i1 SReg_64:$src2), VReg_32:$src1, VReg_32:$src0)),
(V_CNDMASK_B32_e64 VReg_32:$src0, VReg_32:$src1, SReg_64:$src2)
(f32 (select (i1 SSrc_64:$src2), VSrc_32:$src1, VSrc_32:$src0)),
(V_CNDMASK_B32_e64 VSrc_32:$src0, VSrc_32:$src1, SSrc_64:$src2)
>;
defm V_READLANE_B32 : VOP2_32 <0x00000001, "V_READLANE_B32", []>;
@ -895,7 +895,7 @@ def V_MUL_HI_U32 : VOP3_32 <0x0000016a, "V_MUL_HI_U32", []>;
def V_MUL_LO_I32 : VOP3_32 <0x0000016b, "V_MUL_LO_I32", []>;
def : Pat <
(mul VSrc_32:$src0, VReg_32:$src1),
(V_MUL_LO_I32 VSrc_32:$src0, VReg_32:$src1, (i32 SIOperand.ZERO), 0, 0, 0, 0)
(V_MUL_LO_I32 VSrc_32:$src0, VReg_32:$src1, (i32 0), 0, 0, 0, 0)
>;
def V_MUL_HI_I32 : VOP3_32 <0x0000016c, "V_MUL_HI_I32", []>;
def V_DIV_SCALE_F32 : VOP3_32 <0x0000016d, "V_DIV_SCALE_F32", []>;
@ -1219,19 +1219,19 @@ def : BitConvert <f32, i32, VReg_32>;
def : Pat <
(int_AMDIL_clamp VReg_32:$src, (f32 FP_ZERO), (f32 FP_ONE)),
(V_ADD_F32_e64 VReg_32:$src, (i32 0x80 /* SRC1 */),
(V_ADD_F32_e64 VReg_32:$src, (i32 0 /* SRC1 */),
0 /* ABS */, 1 /* CLAMP */, 0 /* OMOD */, 0 /* NEG */)
>;
def : Pat <
(fabs VReg_32:$src),
(V_ADD_F32_e64 VReg_32:$src, (i32 0x80 /* SRC1 */),
(V_ADD_F32_e64 VReg_32:$src, (i32 0 /* SRC1 */),
1 /* ABS */, 0 /* CLAMP */, 0 /* OMOD */, 0 /* NEG */)
>;
def : Pat <
(fneg VReg_32:$src),
(V_ADD_F32_e64 VReg_32:$src, (i32 0x80 /* SRC1 */),
(V_ADD_F32_e64 VReg_32:$src, (i32 0 /* SRC1 */),
0 /* ABS */, 0 /* CLAMP */, 0 /* OMOD */, 1 /* NEG */)
>;
@ -1394,8 +1394,8 @@ def : Pat <
/********** VOP3 Patterns **********/
/********** ================== **********/
def : Pat <(f32 (fadd (fmul VSrc_32:$src0, VReg_32:$src1), VReg_32:$src2)),
(V_MAD_F32 VSrc_32:$src0, VReg_32:$src1, VReg_32:$src2,
def : Pat <(f32 (fadd (fmul VSrc_32:$src0, VSrc_32:$src1), VSrc_32:$src2)),
(V_MAD_F32 VSrc_32:$src0, VSrc_32:$src1, VSrc_32:$src2,
0, 0, 0, 0)>;
/********** ================== **********/