|  | //===-- 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" | 
|  |  | 
|  | namespace { | 
|  | 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: | 
|  | R600DAGToDAGISel() = delete; | 
|  |  | 
|  | 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" | 
|  | }; | 
|  | } // namespace | 
|  |  | 
|  | 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); | 
|  | } |