#include "SIISelLowering.h"
#include "AMDGPU.h"
-#include "AMDIL.h"
#include "AMDILIntrinsicInfo.h"
#include "SIInstrInfo.h"
#include "SIMachineFunctionInfo.h"
using namespace llvm;
SITargetLowering::SITargetLowering(TargetMachine &TM) :
- AMDGPUTargetLowering(TM),
- TII(static_cast<const SIInstrInfo*>(TM.getInstrInfo())),
- TRI(TM.getRegisterInfo()) {
+ AMDGPUTargetLowering(TM) {
addRegisterClass(MVT::i1, &AMDGPU::SReg_64RegClass);
- addRegisterClass(MVT::i64, &AMDGPU::SReg_64RegClass);
+ addRegisterClass(MVT::i64, &AMDGPU::VSrc_64RegClass);
+
+ addRegisterClass(MVT::v2i1, &AMDGPU::VReg_64RegClass);
+ addRegisterClass(MVT::v4i1, &AMDGPU::VReg_128RegClass);
addRegisterClass(MVT::v16i8, &AMDGPU::SReg_128RegClass);
addRegisterClass(MVT::v32i8, &AMDGPU::SReg_256RegClass);
addRegisterClass(MVT::v64i8, &AMDGPU::SReg_512RegClass);
- addRegisterClass(MVT::i32, &AMDGPU::VReg_32RegClass);
- addRegisterClass(MVT::f32, &AMDGPU::VReg_32RegClass);
+ addRegisterClass(MVT::i32, &AMDGPU::VSrc_32RegClass);
+ addRegisterClass(MVT::f32, &AMDGPU::VSrc_32RegClass);
- addRegisterClass(MVT::v1i32, &AMDGPU::VReg_32RegClass);
+ addRegisterClass(MVT::v1i32, &AMDGPU::VSrc_32RegClass);
- addRegisterClass(MVT::v2i32, &AMDGPU::VReg_64RegClass);
- addRegisterClass(MVT::v2f32, &AMDGPU::VReg_64RegClass);
+ addRegisterClass(MVT::f64, &AMDGPU::VSrc_64RegClass);
+ addRegisterClass(MVT::v2i32, &AMDGPU::VSrc_64RegClass);
+ addRegisterClass(MVT::v2f32, &AMDGPU::VSrc_64RegClass);
addRegisterClass(MVT::v4i32, &AMDGPU::VReg_128RegClass);
addRegisterClass(MVT::v4f32, &AMDGPU::VReg_128RegClass);
setOperationAction(ISD::SELECT_CC, MVT::Other, Expand);
+ setOperationAction(ISD::SETCC, MVT::v2i1, Expand);
+ setOperationAction(ISD::SETCC, MVT::v4i1, Expand);
+
setOperationAction(ISD::SIGN_EXTEND, MVT::i64, Custom);
+ setOperationAction(ISD::ZERO_EXTEND, MVT::i64, Custom);
+
+ setOperationAction(ISD::INTRINSIC_WO_CHAIN, MVT::Other, Custom);
+
+ setLoadExtAction(ISD::SEXTLOAD, MVT::i32, Expand);
+
+ setLoadExtAction(ISD::EXTLOAD, MVT::f32, Expand);
+ setTruncStoreAction(MVT::f64, MVT::f32, Expand);
+
+ setOperationAction(ISD::GlobalAddress, MVT::i64, Custom);
setTargetDAGCombine(ISD::SELECT_CC);
setSchedulingPreference(Sched::RegPressure);
}
+//===----------------------------------------------------------------------===//
+// TargetLowering queries
+//===----------------------------------------------------------------------===//
+
+bool SITargetLowering::allowsUnalignedMemoryAccesses(EVT VT,
+ bool *IsFast) const {
+ // XXX: This depends on the address space and also we may want to revist
+ // the alignment values we specify in the DataLayout.
+ return VT.bitsGT(MVT::i32);
+}
+
+
+SDValue SITargetLowering::LowerParameter(SelectionDAG &DAG, EVT VT,
+ SDLoc DL, SDValue Chain,
+ unsigned Offset) const {
+ MachineRegisterInfo &MRI = DAG.getMachineFunction().getRegInfo();
+ PointerType *PtrTy = PointerType::get(VT.getTypeForEVT(*DAG.getContext()),
+ AMDGPUAS::CONSTANT_ADDRESS);
+ EVT ArgVT = MVT::getIntegerVT(VT.getSizeInBits());
+ SDValue BasePtr = DAG.getCopyFromReg(Chain, DL,
+ MRI.getLiveInVirtReg(AMDGPU::SGPR0_SGPR1), MVT::i64);
+ SDValue Ptr = DAG.getNode(ISD::ADD, DL, MVT::i64, BasePtr,
+ DAG.getConstant(Offset, MVT::i64));
+ return DAG.getLoad(VT, DL, Chain, Ptr,
+ MachinePointerInfo(UndefValue::get(PtrTy)),
+ false, false, false, ArgVT.getSizeInBits() >> 3);
+
+}
+
SDValue SITargetLowering::LowerFormalArguments(
SDValue Chain,
CallingConv::ID CallConv,
}
// Second split vertices into their elements
- if (Arg.VT.isVector()) {
+ if (Info->ShaderType != ShaderType::COMPUTE && Arg.VT.isVector()) {
ISD::InputArg NewArg = Arg;
NewArg.Flags.setSplit();
NewArg.VT = Arg.VT.getVectorElementType();
CCInfo.AllocateReg(AMDGPU::VGPR1);
}
+ // The pointer to the list of arguments is stored in SGPR0, SGPR1
+ if (Info->ShaderType == ShaderType::COMPUTE) {
+ CCInfo.AllocateReg(AMDGPU::SGPR0);
+ CCInfo.AllocateReg(AMDGPU::SGPR1);
+ MF.addLiveIn(AMDGPU::SGPR0_SGPR1, &AMDGPU::SReg_64RegClass);
+ }
+
AnalyzeFormalArguments(CCInfo, Splits);
for (unsigned i = 0, e = Ins.size(), ArgIdx = 0; i != e; ++i) {
}
CCValAssign &VA = ArgLocs[ArgIdx++];
+ EVT VT = VA.getLocVT();
+
+ if (VA.isMemLoc()) {
+ // The first 36 bytes of the input buffer contains information about
+ // thread group and global sizes.
+ SDValue Arg = LowerParameter(DAG, VT, DL, DAG.getRoot(),
+ 36 + VA.getLocMemOffset());
+ InVals.push_back(Arg);
+ continue;
+ }
assert(VA.isRegLoc() && "Parameter must be in a register!");
unsigned Reg = VA.getLocReg();
- MVT VT = VA.getLocVT();
if (VT == MVT::i64) {
// For now assume it is a pointer
return AMDGPUTargetLowering::EmitInstrWithCustomInserter(MI, BB);
case AMDGPU::BRANCH: return BB;
case AMDGPU::SI_ADDR64_RSRC: {
+ const SIInstrInfo *TII =
+ static_cast<const SIInstrInfo*>(getTargetMachine().getInstrInfo());
MachineRegisterInfo &MRI = BB->getParent()->getRegInfo();
unsigned SuperReg = MI->getOperand(0).getReg();
unsigned SubRegLo = MRI.createVirtualRegister(&AMDGPU::SReg_64RegClass);
MI->eraseFromParent();
break;
}
+ case AMDGPU::V_SUB_F64: {
+ const SIInstrInfo *TII =
+ static_cast<const SIInstrInfo*>(getTargetMachine().getInstrInfo());
+ BuildMI(*BB, I, MI->getDebugLoc(), TII->get(AMDGPU::V_ADD_F64),
+ MI->getOperand(0).getReg())
+ .addReg(MI->getOperand(1).getReg())
+ .addReg(MI->getOperand(2).getReg())
+ .addImm(0) /* src2 */
+ .addImm(0) /* ABS */
+ .addImm(0) /* CLAMP */
+ .addImm(0) /* OMOD */
+ .addImm(2); /* NEG */
+ MI->eraseFromParent();
+ break;
+ }
}
return BB;
}
EVT SITargetLowering::getSetCCResultType(LLVMContext &, EVT VT) const {
- return MVT::i1;
+ if (!VT.isVector()) {
+ return MVT::i1;
+ }
+ return MVT::getVectorVT(MVT::i1, VT.getVectorNumElements());
}
MVT SITargetLowering::getScalarShiftAmountTy(EVT VT) const {
//===----------------------------------------------------------------------===//
SDValue SITargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const {
+ MachineFunction &MF = DAG.getMachineFunction();
+ SIMachineFunctionInfo *MFI = MF.getInfo<SIMachineFunctionInfo>();
switch (Op.getOpcode()) {
default: return AMDGPUTargetLowering::LowerOperation(Op, DAG);
case ISD::BRCOND: return LowerBRCOND(Op, DAG);
case ISD::SELECT_CC: return LowerSELECT_CC(Op, DAG);
case ISD::SIGN_EXTEND: return LowerSIGN_EXTEND(Op, DAG);
+ case ISD::ZERO_EXTEND: return LowerZERO_EXTEND(Op, DAG);
+ case ISD::GlobalAddress: return LowerGlobalAddress(MFI, Op, DAG);
+ case ISD::INTRINSIC_WO_CHAIN: {
+ unsigned IntrinsicID =
+ cast<ConstantSDNode>(Op.getOperand(0))->getZExtValue();
+ EVT VT = Op.getValueType();
+ SDLoc DL(Op);
+ //XXX: Hardcoded we only use two to store the pointer to the parameters.
+ unsigned NumUserSGPRs = 2;
+ switch (IntrinsicID) {
+ default: return AMDGPUTargetLowering::LowerOperation(Op, DAG);
+ case Intrinsic::r600_read_ngroups_x:
+ return LowerParameter(DAG, VT, DL, DAG.getEntryNode(), 0);
+ case Intrinsic::r600_read_ngroups_y:
+ return LowerParameter(DAG, VT, DL, DAG.getEntryNode(), 4);
+ case Intrinsic::r600_read_ngroups_z:
+ return LowerParameter(DAG, VT, DL, DAG.getEntryNode(), 8);
+ case Intrinsic::r600_read_global_size_x:
+ return LowerParameter(DAG, VT, DL, DAG.getEntryNode(), 12);
+ case Intrinsic::r600_read_global_size_y:
+ return LowerParameter(DAG, VT, DL, DAG.getEntryNode(), 16);
+ case Intrinsic::r600_read_global_size_z:
+ return LowerParameter(DAG, VT, DL, DAG.getEntryNode(), 20);
+ case Intrinsic::r600_read_local_size_x:
+ return LowerParameter(DAG, VT, DL, DAG.getEntryNode(), 24);
+ case Intrinsic::r600_read_local_size_y:
+ return LowerParameter(DAG, VT, DL, DAG.getEntryNode(), 28);
+ case Intrinsic::r600_read_local_size_z:
+ return LowerParameter(DAG, VT, DL, DAG.getEntryNode(), 32);
+ case Intrinsic::r600_read_tgid_x:
+ return CreateLiveInRegister(DAG, &AMDGPU::SReg_32RegClass,
+ AMDGPU::SReg_32RegClass.getRegister(NumUserSGPRs + 0), VT);
+ case Intrinsic::r600_read_tgid_y:
+ return CreateLiveInRegister(DAG, &AMDGPU::SReg_32RegClass,
+ AMDGPU::SReg_32RegClass.getRegister(NumUserSGPRs + 1), VT);
+ case Intrinsic::r600_read_tgid_z:
+ return CreateLiveInRegister(DAG, &AMDGPU::SReg_32RegClass,
+ AMDGPU::SReg_32RegClass.getRegister(NumUserSGPRs + 2), VT);
+ case Intrinsic::r600_read_tidig_x:
+ return CreateLiveInRegister(DAG, &AMDGPU::VReg_32RegClass,
+ AMDGPU::VGPR0, VT);
+ case Intrinsic::r600_read_tidig_y:
+ return CreateLiveInRegister(DAG, &AMDGPU::VReg_32RegClass,
+ AMDGPU::VGPR1, VT);
+ case Intrinsic::r600_read_tidig_z:
+ return CreateLiveInRegister(DAG, &AMDGPU::VReg_32RegClass,
+ AMDGPU::VGPR2, VT);
+
+ }
+ }
}
return SDValue();
}
return DAG.getNode(ISD::BUILD_PAIR, DL, VT, Op.getOperand(0), Hi);
}
+SDValue SITargetLowering::LowerZERO_EXTEND(SDValue Op,
+ SelectionDAG &DAG) const {
+ EVT VT = Op.getValueType();
+ SDLoc DL(Op);
+
+ if (VT != MVT::i64) {
+ return SDValue();
+ }
+
+ return DAG.getNode(ISD::BUILD_PAIR, DL, VT, Op.getOperand(0),
+ DAG.getConstant(0, MVT::i32));
+}
+
//===----------------------------------------------------------------------===//
// Custom DAG optimizations
//===----------------------------------------------------------------------===//
bool &ScalarSlotUsed) const {
MachineSDNode *Mov = dyn_cast<MachineSDNode>(Operand);
+ const SIInstrInfo *TII =
+ static_cast<const SIInstrInfo*>(getTargetMachine().getInstrInfo());
if (Mov == 0 || !TII->isMov(Mov->getMachineOpcode()))
return false;
return false;
}
-/// \brief Does "Op" fit into register class "RegClass" ?
-bool SITargetLowering::fitsRegClass(SelectionDAG &DAG, const SDValue &Op,
- unsigned RegClass) const {
-
- MachineRegisterInfo &MRI = DAG.getMachineFunction().getRegInfo();
- SDNode *Node = Op.getNode();
-
- const TargetRegisterClass *OpClass;
- if (MachineSDNode *MN = dyn_cast<MachineSDNode>(Node)) {
- const MCInstrDesc &Desc = TII->get(MN->getMachineOpcode());
- int OpClassID = Desc.OpInfo[Op.getResNo()].RegClass;
- if (OpClassID == -1) {
- switch (MN->getMachineOpcode()) {
- case AMDGPU::REG_SEQUENCE:
- // Operand 0 is the register class id for REG_SEQUENCE instructions.
- OpClass = TRI->getRegClass(
- cast<ConstantSDNode>(MN->getOperand(0))->getZExtValue());
- break;
- default:
- OpClass = getRegClassFor(Op.getSimpleValueType());
- break;
+const TargetRegisterClass *SITargetLowering::getRegClassForNode(
+ SelectionDAG &DAG, const SDValue &Op) const {
+ const SIInstrInfo *TII =
+ static_cast<const SIInstrInfo*>(getTargetMachine().getInstrInfo());
+ const SIRegisterInfo &TRI = TII->getRegisterInfo();
+
+ if (!Op->isMachineOpcode()) {
+ switch(Op->getOpcode()) {
+ case ISD::CopyFromReg: {
+ MachineRegisterInfo &MRI = DAG.getMachineFunction().getRegInfo();
+ unsigned Reg = cast<RegisterSDNode>(Op->getOperand(1))->getReg();
+ if (TargetRegisterInfo::isVirtualRegister(Reg)) {
+ return MRI.getRegClass(Reg);
}
- } else {
- OpClass = TRI->getRegClass(OpClassID);
+ return TRI.getPhysRegClass(Reg);
}
+ default: return NULL;
+ }
+ }
+ const MCInstrDesc &Desc = TII->get(Op->getMachineOpcode());
+ int OpClassID = Desc.OpInfo[Op.getResNo()].RegClass;
+ if (OpClassID != -1) {
+ return TRI.getRegClass(OpClassID);
+ }
+ switch(Op.getMachineOpcode()) {
+ case AMDGPU::COPY_TO_REGCLASS:
+ // Operand 1 is the register class id for COPY_TO_REGCLASS instructions.
+ OpClassID = cast<ConstantSDNode>(Op->getOperand(1))->getZExtValue();
+
+ // If the COPY_TO_REGCLASS instruction is copying to a VSrc register
+ // class, then the register class for the value could be either a
+ // VReg or and SReg. In order to get a more accurate
+ if (OpClassID == AMDGPU::VSrc_32RegClassID ||
+ OpClassID == AMDGPU::VSrc_64RegClassID) {
+ return getRegClassForNode(DAG, Op.getOperand(0));
+ }
+ return TRI.getRegClass(OpClassID);
+ case AMDGPU::EXTRACT_SUBREG: {
+ int SubIdx = cast<ConstantSDNode>(Op.getOperand(1))->getZExtValue();
+ const TargetRegisterClass *SuperClass =
+ getRegClassForNode(DAG, Op.getOperand(0));
+ return TRI.getSubClassWithSubReg(SuperClass, SubIdx);
+ }
+ case AMDGPU::REG_SEQUENCE:
+ // Operand 0 is the register class id for REG_SEQUENCE instructions.
+ return TRI.getRegClass(
+ cast<ConstantSDNode>(Op.getOperand(0))->getZExtValue());
+ default:
+ return getRegClassFor(Op.getSimpleValueType());
+ }
+}
- } else if (Node->getOpcode() == ISD::CopyFromReg) {
- RegisterSDNode *Reg = cast<RegisterSDNode>(Node->getOperand(1).getNode());
- OpClass = MRI.getRegClass(Reg->getReg());
-
- } else
+/// \brief Does "Op" fit into register class "RegClass" ?
+bool SITargetLowering::fitsRegClass(SelectionDAG &DAG, const SDValue &Op,
+ unsigned RegClass) const {
+ const TargetRegisterInfo *TRI = getTargetMachine().getRegisterInfo();
+ const TargetRegisterClass *RC = getRegClassForNode(DAG, Op);
+ if (!RC) {
return false;
-
- return TRI->getRegClass(RegClass)->hasSubClassEq(OpClass);
+ }
+ return TRI->getRegClass(RegClass)->hasSubClassEq(RC);
}
/// \brief Make sure that we don't exeed the number of allowed scalars
Operand = SDValue(Node, 0);
}
+/// \returns true if \p Node's operands are different from the SDValue list
+/// \p Ops
+static bool isNodeChanged(const SDNode *Node, const std::vector<SDValue> &Ops) {
+ for (unsigned i = 0, e = Node->getNumOperands(); i < e; ++i) {
+ if (Ops[i].getNode() != Node->getOperand(i).getNode()) {
+ return true;
+ }
+ }
+ return false;
+}
+
/// \brief Try to fold the Nodes operands into the Node
SDNode *SITargetLowering::foldOperands(MachineSDNode *Node,
SelectionDAG &DAG) const {
// Original encoding (either e32 or e64)
int Opcode = Node->getMachineOpcode();
+ const SIInstrInfo *TII =
+ static_cast<const SIInstrInfo*>(getTargetMachine().getInstrInfo());
const MCInstrDesc *Desc = &TII->get(Opcode);
unsigned NumDefs = Desc->getNumDefs();
// Nodes that have a glue result are not CSE'd by getMachineNode(), so in
// this case a brand new node is always be created, even if the operands
// are the same as before. So, manually check if anything has been changed.
- if (Desc->Opcode == Opcode) {
- bool Changed = false;
- for (unsigned i = 0, e = Node->getNumOperands(); i < e; ++i) {
- if (Ops[i].getNode() != Node->getOperand(i).getNode()) {
- Changed = true;
- break;
- }
- }
- if (!Changed) {
- return Node;
- }
+ if (Desc->Opcode == Opcode && !isNodeChanged(Node, Ops)) {
+ return Node;
}
// Create a complete new instruction
switch (N->getMachineOpcode()) {
default: return N;
- case AMDGPU::REG_SEQUENCE: {
- // MVT::i128 only use SGPRs, so i128 REG_SEQUENCEs don't need to be
- // rewritten.
- if (N->getValueType(0) == MVT::i128) {
- return N;
- }
- const SDValue Ops[] = {
- DAG.getTargetConstant(AMDGPU::VReg_64RegClassID, MVT::i32),
- N->getOperand(1) , N->getOperand(2),
- N->getOperand(3), N->getOperand(4)
- };
- return DAG.getMachineNode(AMDGPU::REG_SEQUENCE, DL, MVT::i64, Ops);
- }
-
case AMDGPU::S_LOAD_DWORD_IMM:
NewOpcode = AMDGPU::BUFFER_LOAD_DWORD_ADDR64;
// Fall-through
}
}
}
+
+SDValue SITargetLowering::CreateLiveInRegister(SelectionDAG &DAG,
+ const TargetRegisterClass *RC,
+ unsigned Reg, EVT VT) const {
+ SDValue VReg = AMDGPUTargetLowering::CreateLiveInRegister(DAG, RC, Reg, VT);
+
+ return DAG.getCopyFromReg(DAG.getEntryNode(), SDLoc(DAG.getEntryNode()),
+ cast<RegisterSDNode>(VReg)->getReg(), VT);
+}