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