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