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