| //===-- R600ISelDAGToDAG.cpp - A dag to dag inst selector for R600 --------===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //==-----------------------------------------------------------------------===// |
| // |
| /// \file |
| /// Defines an instruction selector for the R600 subtarget. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "AMDGPU.h" |
| #include "AMDGPUISelDAGToDAG.h" |
| #include "MCTargetDesc/R600MCTargetDesc.h" |
| #include "R600.h" |
| #include "R600Subtarget.h" |
| #include "llvm/Analysis/ValueTracking.h" |
| |
| class R600DAGToDAGISel : public AMDGPUDAGToDAGISel { |
| const R600Subtarget *Subtarget; |
| |
| bool isConstantLoad(const MemSDNode *N, int cbID) const; |
| bool SelectGlobalValueConstantOffset(SDValue Addr, SDValue &IntPtr); |
| bool SelectGlobalValueVariableOffset(SDValue Addr, SDValue &BaseReg, |
| SDValue &Offset); |
| |
| public: |
| explicit R600DAGToDAGISel(TargetMachine *TM, CodeGenOpt::Level OptLevel) |
| : AMDGPUDAGToDAGISel(TM, OptLevel) {} |
| |
| void Select(SDNode *N) override; |
| |
| bool SelectADDRIndirect(SDValue Addr, SDValue &Base, |
| SDValue &Offset) override; |
| bool SelectADDRVTX_READ(SDValue Addr, SDValue &Base, |
| SDValue &Offset) override; |
| |
| bool runOnMachineFunction(MachineFunction &MF) override; |
| |
| void PreprocessISelDAG() override {} |
| |
| protected: |
| // Include the pieces autogenerated from the target description. |
| #include "R600GenDAGISel.inc" |
| }; |
| |
| bool R600DAGToDAGISel::runOnMachineFunction(MachineFunction &MF) { |
| Subtarget = &MF.getSubtarget<R600Subtarget>(); |
| return SelectionDAGISel::runOnMachineFunction(MF); |
| } |
| |
| bool R600DAGToDAGISel::isConstantLoad(const MemSDNode *N, int CbId) const { |
| if (!N->readMem()) |
| return false; |
| if (CbId == -1) |
| return N->getAddressSpace() == AMDGPUAS::CONSTANT_ADDRESS || |
| N->getAddressSpace() == AMDGPUAS::CONSTANT_ADDRESS_32BIT; |
| |
| return N->getAddressSpace() == AMDGPUAS::CONSTANT_BUFFER_0 + CbId; |
| } |
| |
| bool R600DAGToDAGISel::SelectGlobalValueConstantOffset(SDValue Addr, |
| SDValue &IntPtr) { |
| if (ConstantSDNode *Cst = dyn_cast<ConstantSDNode>(Addr)) { |
| IntPtr = |
| CurDAG->getIntPtrConstant(Cst->getZExtValue() / 4, SDLoc(Addr), true); |
| return true; |
| } |
| return false; |
| } |
| |
| bool R600DAGToDAGISel::SelectGlobalValueVariableOffset(SDValue Addr, |
| SDValue &BaseReg, |
| SDValue &Offset) { |
| if (!isa<ConstantSDNode>(Addr)) { |
| BaseReg = Addr; |
| Offset = CurDAG->getIntPtrConstant(0, SDLoc(Addr), true); |
| return true; |
| } |
| return false; |
| } |
| |
| void R600DAGToDAGISel::Select(SDNode *N) { |
| unsigned int Opc = N->getOpcode(); |
| if (N->isMachineOpcode()) { |
| N->setNodeId(-1); |
| return; // Already selected. |
| } |
| |
| switch (Opc) { |
| default: |
| break; |
| case AMDGPUISD::BUILD_VERTICAL_VECTOR: |
| case ISD::SCALAR_TO_VECTOR: |
| case ISD::BUILD_VECTOR: { |
| EVT VT = N->getValueType(0); |
| unsigned NumVectorElts = VT.getVectorNumElements(); |
| unsigned RegClassID; |
| // BUILD_VECTOR was lowered into an IMPLICIT_DEF + 4 INSERT_SUBREG |
| // that adds a 128 bits reg copy when going through TwoAddressInstructions |
| // pass. We want to avoid 128 bits copies as much as possible because they |
| // can't be bundled by our scheduler. |
| switch (NumVectorElts) { |
| case 2: |
| RegClassID = R600::R600_Reg64RegClassID; |
| break; |
| case 4: |
| if (Opc == AMDGPUISD::BUILD_VERTICAL_VECTOR) |
| RegClassID = R600::R600_Reg128VerticalRegClassID; |
| else |
| RegClassID = R600::R600_Reg128RegClassID; |
| break; |
| default: |
| llvm_unreachable("Do not know how to lower this BUILD_VECTOR"); |
| } |
| SelectBuildVector(N, RegClassID); |
| return; |
| } |
| } |
| |
| SelectCode(N); |
| } |
| |
| bool R600DAGToDAGISel::SelectADDRIndirect(SDValue Addr, SDValue &Base, |
| SDValue &Offset) { |
| ConstantSDNode *C; |
| SDLoc DL(Addr); |
| |
| if ((C = dyn_cast<ConstantSDNode>(Addr))) { |
| Base = CurDAG->getRegister(R600::INDIRECT_BASE_ADDR, MVT::i32); |
| Offset = CurDAG->getTargetConstant(C->getZExtValue(), DL, MVT::i32); |
| } else if ((Addr.getOpcode() == AMDGPUISD::DWORDADDR) && |
| (C = dyn_cast<ConstantSDNode>(Addr.getOperand(0)))) { |
| Base = CurDAG->getRegister(R600::INDIRECT_BASE_ADDR, MVT::i32); |
| Offset = CurDAG->getTargetConstant(C->getZExtValue(), DL, MVT::i32); |
| } else if ((Addr.getOpcode() == ISD::ADD || Addr.getOpcode() == ISD::OR) && |
| (C = dyn_cast<ConstantSDNode>(Addr.getOperand(1)))) { |
| Base = Addr.getOperand(0); |
| Offset = CurDAG->getTargetConstant(C->getZExtValue(), DL, MVT::i32); |
| } else { |
| Base = Addr; |
| Offset = CurDAG->getTargetConstant(0, DL, MVT::i32); |
| } |
| |
| return true; |
| } |
| |
| bool R600DAGToDAGISel::SelectADDRVTX_READ(SDValue Addr, SDValue &Base, |
| SDValue &Offset) { |
| ConstantSDNode *IMMOffset; |
| |
| if (Addr.getOpcode() == ISD::ADD && |
| (IMMOffset = dyn_cast<ConstantSDNode>(Addr.getOperand(1))) && |
| isInt<16>(IMMOffset->getZExtValue())) { |
| |
| Base = Addr.getOperand(0); |
| Offset = CurDAG->getTargetConstant(IMMOffset->getZExtValue(), SDLoc(Addr), |
| MVT::i32); |
| return true; |
| // If the pointer address is constant, we can move it to the offset field. |
| } else if ((IMMOffset = dyn_cast<ConstantSDNode>(Addr)) && |
| isInt<16>(IMMOffset->getZExtValue())) { |
| Base = CurDAG->getCopyFromReg(CurDAG->getEntryNode(), |
| SDLoc(CurDAG->getEntryNode()), R600::ZERO, |
| MVT::i32); |
| Offset = CurDAG->getTargetConstant(IMMOffset->getZExtValue(), SDLoc(Addr), |
| MVT::i32); |
| return true; |
| } |
| |
| // Default case, no offset |
| Base = Addr; |
| Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32); |
| return true; |
| } |
| |
| /// This pass converts a legalized DAG into a R600-specific |
| // DAG, ready for instruction scheduling. |
| FunctionPass *llvm::createR600ISelDag(TargetMachine *TM, |
| CodeGenOpt::Level OptLevel) { |
| return new R600DAGToDAGISel(TM, OptLevel); |
| } |