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