202 lines · cpp
1//===-- R600ISelDAGToDAG.cpp - A dag to dag inst selector for R600 --------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//==-----------------------------------------------------------------------===//8//9/// \file10/// Defines an instruction selector for the R600 subtarget.11//12//===----------------------------------------------------------------------===//13 14#include "AMDGPU.h"15#include "AMDGPUISelDAGToDAG.h"16#include "MCTargetDesc/R600MCTargetDesc.h"17#include "R600.h"18#include "R600Subtarget.h"19 20using namespace llvm;21 22namespace {23class R600DAGToDAGISel : public AMDGPUDAGToDAGISel {24 const R600Subtarget *Subtarget = nullptr;25 26 bool isConstantLoad(const MemSDNode *N, int cbID) const;27 bool SelectGlobalValueConstantOffset(SDValue Addr, SDValue &IntPtr);28 bool SelectGlobalValueVariableOffset(SDValue Addr, SDValue &BaseReg,29 SDValue &Offset);30 31public:32 R600DAGToDAGISel() = delete;33 34 explicit R600DAGToDAGISel(TargetMachine &TM, CodeGenOptLevel OptLevel)35 : AMDGPUDAGToDAGISel(TM, OptLevel) {}36 37 void Select(SDNode *N) override;38 39 bool SelectADDRIndirect(SDValue Addr, SDValue &Base,40 SDValue &Offset) override;41 bool SelectADDRVTX_READ(SDValue Addr, SDValue &Base,42 SDValue &Offset) override;43 44 bool runOnMachineFunction(MachineFunction &MF) override;45 46 void PreprocessISelDAG() override {}47 48protected:49 // Include the pieces autogenerated from the target description.50#include "R600GenDAGISel.inc"51};52 53class R600DAGToDAGISelLegacy : public SelectionDAGISelLegacy {54public:55 static char ID;56 explicit R600DAGToDAGISelLegacy(TargetMachine &TM, CodeGenOptLevel OptLevel)57 : SelectionDAGISelLegacy(58 ID, std::make_unique<R600DAGToDAGISel>(TM, OptLevel)) {}59};60 61char R600DAGToDAGISelLegacy::ID = 0;62 63} // namespace64 65bool R600DAGToDAGISel::runOnMachineFunction(MachineFunction &MF) {66 Subtarget = &MF.getSubtarget<R600Subtarget>();67 return SelectionDAGISel::runOnMachineFunction(MF);68}69 70bool R600DAGToDAGISel::isConstantLoad(const MemSDNode *N, int CbId) const {71 if (!N->readMem())72 return false;73 if (CbId == -1)74 return N->getAddressSpace() == AMDGPUAS::CONSTANT_ADDRESS ||75 N->getAddressSpace() == AMDGPUAS::CONSTANT_ADDRESS_32BIT;76 77 return N->getAddressSpace() == AMDGPUAS::CONSTANT_BUFFER_0 + CbId;78}79 80bool R600DAGToDAGISel::SelectGlobalValueConstantOffset(SDValue Addr,81 SDValue &IntPtr) {82 if (ConstantSDNode *Cst = dyn_cast<ConstantSDNode>(Addr)) {83 IntPtr =84 CurDAG->getIntPtrConstant(Cst->getZExtValue() / 4, SDLoc(Addr), true);85 return true;86 }87 return false;88}89 90bool R600DAGToDAGISel::SelectGlobalValueVariableOffset(SDValue Addr,91 SDValue &BaseReg,92 SDValue &Offset) {93 if (!isa<ConstantSDNode>(Addr)) {94 BaseReg = Addr;95 Offset = CurDAG->getIntPtrConstant(0, SDLoc(Addr), true);96 return true;97 }98 return false;99}100 101void R600DAGToDAGISel::Select(SDNode *N) {102 unsigned int Opc = N->getOpcode();103 if (N->isMachineOpcode()) {104 N->setNodeId(-1);105 return; // Already selected.106 }107 108 switch (Opc) {109 default:110 break;111 case AMDGPUISD::BUILD_VERTICAL_VECTOR:112 case ISD::SCALAR_TO_VECTOR:113 case ISD::BUILD_VECTOR: {114 EVT VT = N->getValueType(0);115 unsigned NumVectorElts = VT.getVectorNumElements();116 unsigned RegClassID;117 // BUILD_VECTOR was lowered into an IMPLICIT_DEF + 4 INSERT_SUBREG118 // that adds a 128 bits reg copy when going through TwoAddressInstructions119 // pass. We want to avoid 128 bits copies as much as possible because they120 // can't be bundled by our scheduler.121 switch (NumVectorElts) {122 case 2:123 RegClassID = R600::R600_Reg64RegClassID;124 break;125 case 4:126 if (Opc == AMDGPUISD::BUILD_VERTICAL_VECTOR)127 RegClassID = R600::R600_Reg128VerticalRegClassID;128 else129 RegClassID = R600::R600_Reg128RegClassID;130 break;131 default:132 llvm_unreachable("Do not know how to lower this BUILD_VECTOR");133 }134 SelectBuildVector(N, RegClassID);135 return;136 }137 }138 139 SelectCode(N);140}141 142bool R600DAGToDAGISel::SelectADDRIndirect(SDValue Addr, SDValue &Base,143 SDValue &Offset) {144 ConstantSDNode *C;145 SDLoc DL(Addr);146 147 if ((C = dyn_cast<ConstantSDNode>(Addr))) {148 Base = CurDAG->getRegister(R600::INDIRECT_BASE_ADDR, MVT::i32);149 Offset = CurDAG->getTargetConstant(C->getZExtValue(), DL, MVT::i32);150 } else if ((Addr.getOpcode() == AMDGPUISD::DWORDADDR) &&151 (C = dyn_cast<ConstantSDNode>(Addr.getOperand(0)))) {152 Base = CurDAG->getRegister(R600::INDIRECT_BASE_ADDR, MVT::i32);153 Offset = CurDAG->getTargetConstant(C->getZExtValue(), DL, MVT::i32);154 } else if ((Addr.getOpcode() == ISD::ADD || Addr.getOpcode() == ISD::OR) &&155 (C = dyn_cast<ConstantSDNode>(Addr.getOperand(1)))) {156 Base = Addr.getOperand(0);157 Offset = CurDAG->getTargetConstant(C->getZExtValue(), DL, MVT::i32);158 } else {159 Base = Addr;160 Offset = CurDAG->getTargetConstant(0, DL, MVT::i32);161 }162 163 return true;164}165 166bool R600DAGToDAGISel::SelectADDRVTX_READ(SDValue Addr, SDValue &Base,167 SDValue &Offset) {168 ConstantSDNode *IMMOffset;169 170 if (Addr.getOpcode() == ISD::ADD &&171 (IMMOffset = dyn_cast<ConstantSDNode>(Addr.getOperand(1))) &&172 isInt<16>(IMMOffset->getZExtValue())) {173 174 Base = Addr.getOperand(0);175 Offset = CurDAG->getTargetConstant(IMMOffset->getZExtValue(), SDLoc(Addr),176 MVT::i32);177 return true;178 // If the pointer address is constant, we can move it to the offset field.179 }180 if ((IMMOffset = dyn_cast<ConstantSDNode>(Addr)) &&181 isInt<16>(IMMOffset->getZExtValue())) {182 Base = CurDAG->getCopyFromReg(CurDAG->getEntryNode(),183 SDLoc(CurDAG->getEntryNode()), R600::ZERO,184 MVT::i32);185 Offset = CurDAG->getTargetConstant(IMMOffset->getZExtValue(), SDLoc(Addr),186 MVT::i32);187 return true;188 }189 190 // Default case, no offset191 Base = Addr;192 Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32);193 return true;194}195 196/// This pass converts a legalized DAG into a R600-specific197// DAG, ready for instruction scheduling.198FunctionPass *llvm::createR600ISelDag(TargetMachine &TM,199 CodeGenOptLevel OptLevel) {200 return new R600DAGToDAGISelLegacy(TM, OptLevel);201}202