xref: /freebsd/contrib/llvm-project/llvm/lib/Target/AMDGPU/R600ISelDAGToDAG.cpp (revision 9c77fb6aaa366cbabc80ee1b834bcfe4df135491)
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 
20 using namespace llvm;
21 
22 namespace {
23 class 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 
31 public:
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 
48 protected:
49   // Include the pieces autogenerated from the target description.
50 #include "R600GenDAGISel.inc"
51 };
52 
53 class R600DAGToDAGISelLegacy : public SelectionDAGISelLegacy {
54 public:
55   static char ID;
56   explicit R600DAGToDAGISelLegacy(TargetMachine &TM, CodeGenOptLevel OptLevel)
57       : SelectionDAGISelLegacy(
58             ID, std::make_unique<R600DAGToDAGISel>(TM, OptLevel)) {}
59 };
60 
61 char R600DAGToDAGISelLegacy::ID = 0;
62 
63 } // namespace
64 
65 bool R600DAGToDAGISel::runOnMachineFunction(MachineFunction &MF) {
66   Subtarget = &MF.getSubtarget<R600Subtarget>();
67   return SelectionDAGISel::runOnMachineFunction(MF);
68 }
69 
70 bool 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 
80 bool 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 
90 bool 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 
101 void 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_SUBREG
118     // that adds a 128 bits reg copy when going through TwoAddressInstructions
119     // pass. We want to avoid 128 bits copies as much as possible because they
120     // 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       else
129         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 
142 bool 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 
166 bool 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 offset
191   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-specific
197 // DAG, ready for instruction scheduling.
198 FunctionPass *llvm::createR600ISelDag(TargetMachine &TM,
199                                       CodeGenOptLevel OptLevel) {
200   return new R600DAGToDAGISelLegacy(TM, OptLevel);
201 }
202