xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/AMDGPU/R600ISelDAGToDAG.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1349cc55cSDimitry Andric //===-- R600ISelDAGToDAG.cpp - A dag to dag inst selector for R600 --------===//
2349cc55cSDimitry Andric //
3349cc55cSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4349cc55cSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5349cc55cSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6349cc55cSDimitry Andric //
7349cc55cSDimitry Andric //==-----------------------------------------------------------------------===//
8349cc55cSDimitry Andric //
9349cc55cSDimitry Andric /// \file
10349cc55cSDimitry Andric /// Defines an instruction selector for the R600 subtarget.
11349cc55cSDimitry Andric //
12349cc55cSDimitry Andric //===----------------------------------------------------------------------===//
13349cc55cSDimitry Andric 
14349cc55cSDimitry Andric #include "AMDGPU.h"
15349cc55cSDimitry Andric #include "AMDGPUISelDAGToDAG.h"
16349cc55cSDimitry Andric #include "MCTargetDesc/R600MCTargetDesc.h"
17349cc55cSDimitry Andric #include "R600.h"
18349cc55cSDimitry Andric #include "R600Subtarget.h"
19349cc55cSDimitry Andric #include "llvm/Analysis/ValueTracking.h"
20349cc55cSDimitry Andric 
21bdd1243dSDimitry Andric namespace {
22349cc55cSDimitry Andric class R600DAGToDAGISel : public AMDGPUDAGToDAGISel {
2306c3fb27SDimitry Andric   const R600Subtarget *Subtarget = nullptr;
24349cc55cSDimitry Andric 
25349cc55cSDimitry Andric   bool isConstantLoad(const MemSDNode *N, int cbID) const;
26349cc55cSDimitry Andric   bool SelectGlobalValueConstantOffset(SDValue Addr, SDValue &IntPtr);
27349cc55cSDimitry Andric   bool SelectGlobalValueVariableOffset(SDValue Addr, SDValue &BaseReg,
28349cc55cSDimitry Andric                                        SDValue &Offset);
29349cc55cSDimitry Andric 
30349cc55cSDimitry Andric public:
31bdd1243dSDimitry Andric   R600DAGToDAGISel() = delete;
32bdd1243dSDimitry Andric 
335f757f3fSDimitry Andric   explicit R600DAGToDAGISel(TargetMachine &TM, CodeGenOptLevel OptLevel)
34349cc55cSDimitry Andric       : AMDGPUDAGToDAGISel(TM, OptLevel) {}
35349cc55cSDimitry Andric 
36349cc55cSDimitry Andric   void Select(SDNode *N) override;
37349cc55cSDimitry Andric 
38349cc55cSDimitry Andric   bool SelectADDRIndirect(SDValue Addr, SDValue &Base,
39349cc55cSDimitry Andric                           SDValue &Offset) override;
40349cc55cSDimitry Andric   bool SelectADDRVTX_READ(SDValue Addr, SDValue &Base,
41349cc55cSDimitry Andric                           SDValue &Offset) override;
42349cc55cSDimitry Andric 
43349cc55cSDimitry Andric   bool runOnMachineFunction(MachineFunction &MF) override;
44349cc55cSDimitry Andric 
45349cc55cSDimitry Andric   void PreprocessISelDAG() override {}
46349cc55cSDimitry Andric 
47349cc55cSDimitry Andric protected:
48349cc55cSDimitry Andric   // Include the pieces autogenerated from the target description.
49349cc55cSDimitry Andric #include "R600GenDAGISel.inc"
50349cc55cSDimitry Andric };
51*0fca6ea1SDimitry Andric 
52*0fca6ea1SDimitry Andric class R600DAGToDAGISelLegacy : public SelectionDAGISelLegacy {
53*0fca6ea1SDimitry Andric public:
54*0fca6ea1SDimitry Andric   static char ID;
55*0fca6ea1SDimitry Andric   explicit R600DAGToDAGISelLegacy(TargetMachine &TM, CodeGenOptLevel OptLevel)
56*0fca6ea1SDimitry Andric       : SelectionDAGISelLegacy(
57*0fca6ea1SDimitry Andric             ID, std::make_unique<R600DAGToDAGISel>(TM, OptLevel)) {}
58*0fca6ea1SDimitry Andric };
59*0fca6ea1SDimitry Andric 
60*0fca6ea1SDimitry Andric char R600DAGToDAGISelLegacy::ID = 0;
61*0fca6ea1SDimitry Andric 
62bdd1243dSDimitry Andric } // namespace
63349cc55cSDimitry Andric 
64349cc55cSDimitry Andric bool R600DAGToDAGISel::runOnMachineFunction(MachineFunction &MF) {
65349cc55cSDimitry Andric   Subtarget = &MF.getSubtarget<R600Subtarget>();
66349cc55cSDimitry Andric   return SelectionDAGISel::runOnMachineFunction(MF);
67349cc55cSDimitry Andric }
68349cc55cSDimitry Andric 
69349cc55cSDimitry Andric bool R600DAGToDAGISel::isConstantLoad(const MemSDNode *N, int CbId) const {
70349cc55cSDimitry Andric   if (!N->readMem())
71349cc55cSDimitry Andric     return false;
72349cc55cSDimitry Andric   if (CbId == -1)
73349cc55cSDimitry Andric     return N->getAddressSpace() == AMDGPUAS::CONSTANT_ADDRESS ||
74349cc55cSDimitry Andric            N->getAddressSpace() == AMDGPUAS::CONSTANT_ADDRESS_32BIT;
75349cc55cSDimitry Andric 
76349cc55cSDimitry Andric   return N->getAddressSpace() == AMDGPUAS::CONSTANT_BUFFER_0 + CbId;
77349cc55cSDimitry Andric }
78349cc55cSDimitry Andric 
79349cc55cSDimitry Andric bool R600DAGToDAGISel::SelectGlobalValueConstantOffset(SDValue Addr,
80349cc55cSDimitry Andric                                                        SDValue &IntPtr) {
81349cc55cSDimitry Andric   if (ConstantSDNode *Cst = dyn_cast<ConstantSDNode>(Addr)) {
82349cc55cSDimitry Andric     IntPtr =
83349cc55cSDimitry Andric         CurDAG->getIntPtrConstant(Cst->getZExtValue() / 4, SDLoc(Addr), true);
84349cc55cSDimitry Andric     return true;
85349cc55cSDimitry Andric   }
86349cc55cSDimitry Andric   return false;
87349cc55cSDimitry Andric }
88349cc55cSDimitry Andric 
89349cc55cSDimitry Andric bool R600DAGToDAGISel::SelectGlobalValueVariableOffset(SDValue Addr,
90349cc55cSDimitry Andric                                                        SDValue &BaseReg,
91349cc55cSDimitry Andric                                                        SDValue &Offset) {
92349cc55cSDimitry Andric   if (!isa<ConstantSDNode>(Addr)) {
93349cc55cSDimitry Andric     BaseReg = Addr;
94349cc55cSDimitry Andric     Offset = CurDAG->getIntPtrConstant(0, SDLoc(Addr), true);
95349cc55cSDimitry Andric     return true;
96349cc55cSDimitry Andric   }
97349cc55cSDimitry Andric   return false;
98349cc55cSDimitry Andric }
99349cc55cSDimitry Andric 
100349cc55cSDimitry Andric void R600DAGToDAGISel::Select(SDNode *N) {
101349cc55cSDimitry Andric   unsigned int Opc = N->getOpcode();
102349cc55cSDimitry Andric   if (N->isMachineOpcode()) {
103349cc55cSDimitry Andric     N->setNodeId(-1);
104349cc55cSDimitry Andric     return; // Already selected.
105349cc55cSDimitry Andric   }
106349cc55cSDimitry Andric 
107349cc55cSDimitry Andric   switch (Opc) {
108349cc55cSDimitry Andric   default:
109349cc55cSDimitry Andric     break;
110349cc55cSDimitry Andric   case AMDGPUISD::BUILD_VERTICAL_VECTOR:
111349cc55cSDimitry Andric   case ISD::SCALAR_TO_VECTOR:
112349cc55cSDimitry Andric   case ISD::BUILD_VECTOR: {
113349cc55cSDimitry Andric     EVT VT = N->getValueType(0);
114349cc55cSDimitry Andric     unsigned NumVectorElts = VT.getVectorNumElements();
115349cc55cSDimitry Andric     unsigned RegClassID;
116349cc55cSDimitry Andric     // BUILD_VECTOR was lowered into an IMPLICIT_DEF + 4 INSERT_SUBREG
117349cc55cSDimitry Andric     // that adds a 128 bits reg copy when going through TwoAddressInstructions
118349cc55cSDimitry Andric     // pass. We want to avoid 128 bits copies as much as possible because they
119349cc55cSDimitry Andric     // can't be bundled by our scheduler.
120349cc55cSDimitry Andric     switch (NumVectorElts) {
121349cc55cSDimitry Andric     case 2:
122349cc55cSDimitry Andric       RegClassID = R600::R600_Reg64RegClassID;
123349cc55cSDimitry Andric       break;
124349cc55cSDimitry Andric     case 4:
125349cc55cSDimitry Andric       if (Opc == AMDGPUISD::BUILD_VERTICAL_VECTOR)
126349cc55cSDimitry Andric         RegClassID = R600::R600_Reg128VerticalRegClassID;
127349cc55cSDimitry Andric       else
128349cc55cSDimitry Andric         RegClassID = R600::R600_Reg128RegClassID;
129349cc55cSDimitry Andric       break;
130349cc55cSDimitry Andric     default:
131349cc55cSDimitry Andric       llvm_unreachable("Do not know how to lower this BUILD_VECTOR");
132349cc55cSDimitry Andric     }
133349cc55cSDimitry Andric     SelectBuildVector(N, RegClassID);
134349cc55cSDimitry Andric     return;
135349cc55cSDimitry Andric   }
136349cc55cSDimitry Andric   }
137349cc55cSDimitry Andric 
138349cc55cSDimitry Andric   SelectCode(N);
139349cc55cSDimitry Andric }
140349cc55cSDimitry Andric 
141349cc55cSDimitry Andric bool R600DAGToDAGISel::SelectADDRIndirect(SDValue Addr, SDValue &Base,
142349cc55cSDimitry Andric                                           SDValue &Offset) {
143349cc55cSDimitry Andric   ConstantSDNode *C;
144349cc55cSDimitry Andric   SDLoc DL(Addr);
145349cc55cSDimitry Andric 
146349cc55cSDimitry Andric   if ((C = dyn_cast<ConstantSDNode>(Addr))) {
147349cc55cSDimitry Andric     Base = CurDAG->getRegister(R600::INDIRECT_BASE_ADDR, MVT::i32);
148349cc55cSDimitry Andric     Offset = CurDAG->getTargetConstant(C->getZExtValue(), DL, MVT::i32);
149349cc55cSDimitry Andric   } else if ((Addr.getOpcode() == AMDGPUISD::DWORDADDR) &&
150349cc55cSDimitry Andric              (C = dyn_cast<ConstantSDNode>(Addr.getOperand(0)))) {
151349cc55cSDimitry Andric     Base = CurDAG->getRegister(R600::INDIRECT_BASE_ADDR, MVT::i32);
152349cc55cSDimitry Andric     Offset = CurDAG->getTargetConstant(C->getZExtValue(), DL, MVT::i32);
153349cc55cSDimitry Andric   } else if ((Addr.getOpcode() == ISD::ADD || Addr.getOpcode() == ISD::OR) &&
154349cc55cSDimitry Andric              (C = dyn_cast<ConstantSDNode>(Addr.getOperand(1)))) {
155349cc55cSDimitry Andric     Base = Addr.getOperand(0);
156349cc55cSDimitry Andric     Offset = CurDAG->getTargetConstant(C->getZExtValue(), DL, MVT::i32);
157349cc55cSDimitry Andric   } else {
158349cc55cSDimitry Andric     Base = Addr;
159349cc55cSDimitry Andric     Offset = CurDAG->getTargetConstant(0, DL, MVT::i32);
160349cc55cSDimitry Andric   }
161349cc55cSDimitry Andric 
162349cc55cSDimitry Andric   return true;
163349cc55cSDimitry Andric }
164349cc55cSDimitry Andric 
165349cc55cSDimitry Andric bool R600DAGToDAGISel::SelectADDRVTX_READ(SDValue Addr, SDValue &Base,
166349cc55cSDimitry Andric                                           SDValue &Offset) {
167349cc55cSDimitry Andric   ConstantSDNode *IMMOffset;
168349cc55cSDimitry Andric 
169349cc55cSDimitry Andric   if (Addr.getOpcode() == ISD::ADD &&
170349cc55cSDimitry Andric       (IMMOffset = dyn_cast<ConstantSDNode>(Addr.getOperand(1))) &&
171349cc55cSDimitry Andric       isInt<16>(IMMOffset->getZExtValue())) {
172349cc55cSDimitry Andric 
173349cc55cSDimitry Andric     Base = Addr.getOperand(0);
174349cc55cSDimitry Andric     Offset = CurDAG->getTargetConstant(IMMOffset->getZExtValue(), SDLoc(Addr),
175349cc55cSDimitry Andric                                        MVT::i32);
176349cc55cSDimitry Andric     return true;
177349cc55cSDimitry Andric     // If the pointer address is constant, we can move it to the offset field.
178*0fca6ea1SDimitry Andric   }
179*0fca6ea1SDimitry Andric   if ((IMMOffset = dyn_cast<ConstantSDNode>(Addr)) &&
180349cc55cSDimitry Andric       isInt<16>(IMMOffset->getZExtValue())) {
181349cc55cSDimitry Andric     Base = CurDAG->getCopyFromReg(CurDAG->getEntryNode(),
182349cc55cSDimitry Andric                                   SDLoc(CurDAG->getEntryNode()), R600::ZERO,
183349cc55cSDimitry Andric                                   MVT::i32);
184349cc55cSDimitry Andric     Offset = CurDAG->getTargetConstant(IMMOffset->getZExtValue(), SDLoc(Addr),
185349cc55cSDimitry Andric                                        MVT::i32);
186349cc55cSDimitry Andric     return true;
187349cc55cSDimitry Andric   }
188349cc55cSDimitry Andric 
189349cc55cSDimitry Andric   // Default case, no offset
190349cc55cSDimitry Andric   Base = Addr;
191349cc55cSDimitry Andric   Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32);
192349cc55cSDimitry Andric   return true;
193349cc55cSDimitry Andric }
194349cc55cSDimitry Andric 
195349cc55cSDimitry Andric /// This pass converts a legalized DAG into a R600-specific
196349cc55cSDimitry Andric // DAG, ready for instruction scheduling.
197bdd1243dSDimitry Andric FunctionPass *llvm::createR600ISelDag(TargetMachine &TM,
1985f757f3fSDimitry Andric                                       CodeGenOptLevel OptLevel) {
199*0fca6ea1SDimitry Andric   return new R600DAGToDAGISelLegacy(TM, OptLevel);
200349cc55cSDimitry Andric }
201