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
21namespace {
22class 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
30public:
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
47protected:
48 // Include the pieces autogenerated from the target description.
49#include "R600GenDAGISel.inc"
50};
51
52class R600DAGToDAGISelLegacy : public SelectionDAGISelLegacy {
53public:
54 static char ID;
55 explicit R600DAGToDAGISelLegacy(TargetMachine &TM, CodeGenOptLevel OptLevel)
56 : SelectionDAGISelLegacy(
57 ID, std::make_unique<R600DAGToDAGISel>(args&: TM, args&: OptLevel)) {}
58};
59
60char R600DAGToDAGISelLegacy::ID = 0;
61
62} // namespace
63
64bool R600DAGToDAGISel::runOnMachineFunction(MachineFunction &MF) {
65 Subtarget = &MF.getSubtarget<R600Subtarget>();
66 return SelectionDAGISel::runOnMachineFunction(mf&: MF);
67}
68
69bool 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
79bool R600DAGToDAGISel::SelectGlobalValueConstantOffset(SDValue Addr,
80 SDValue &IntPtr) {
81 if (ConstantSDNode *Cst = dyn_cast<ConstantSDNode>(Val&: Addr)) {
82 IntPtr =
83 CurDAG->getIntPtrConstant(Val: Cst->getZExtValue() / 4, DL: SDLoc(Addr), isTarget: true);
84 return true;
85 }
86 return false;
87}
88
89bool R600DAGToDAGISel::SelectGlobalValueVariableOffset(SDValue Addr,
90 SDValue &BaseReg,
91 SDValue &Offset) {
92 if (!isa<ConstantSDNode>(Val: Addr)) {
93 BaseReg = Addr;
94 Offset = CurDAG->getIntPtrConstant(Val: 0, DL: SDLoc(Addr), isTarget: true);
95 return true;
96 }
97 return false;
98}
99
100void 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(ResNo: 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
141bool R600DAGToDAGISel::SelectADDRIndirect(SDValue Addr, SDValue &Base,
142 SDValue &Offset) {
143 ConstantSDNode *C;
144 SDLoc DL(Addr);
145
146 if ((C = dyn_cast<ConstantSDNode>(Val&: Addr))) {
147 Base = CurDAG->getRegister(Reg: R600::INDIRECT_BASE_ADDR, VT: MVT::i32);
148 Offset = CurDAG->getTargetConstant(Val: C->getZExtValue(), DL, VT: MVT::i32);
149 } else if ((Addr.getOpcode() == AMDGPUISD::DWORDADDR) &&
150 (C = dyn_cast<ConstantSDNode>(Val: Addr.getOperand(i: 0)))) {
151 Base = CurDAG->getRegister(Reg: R600::INDIRECT_BASE_ADDR, VT: MVT::i32);
152 Offset = CurDAG->getTargetConstant(Val: C->getZExtValue(), DL, VT: MVT::i32);
153 } else if ((Addr.getOpcode() == ISD::ADD || Addr.getOpcode() == ISD::OR) &&
154 (C = dyn_cast<ConstantSDNode>(Val: Addr.getOperand(i: 1)))) {
155 Base = Addr.getOperand(i: 0);
156 Offset = CurDAG->getTargetConstant(Val: C->getZExtValue(), DL, VT: MVT::i32);
157 } else {
158 Base = Addr;
159 Offset = CurDAG->getTargetConstant(Val: 0, DL, VT: MVT::i32);
160 }
161
162 return true;
163}
164
165bool 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>(Val: Addr.getOperand(i: 1))) &&
171 isInt<16>(x: IMMOffset->getZExtValue())) {
172
173 Base = Addr.getOperand(i: 0);
174 Offset = CurDAG->getTargetConstant(Val: IMMOffset->getZExtValue(), DL: SDLoc(Addr),
175 VT: 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>(Val&: Addr)) &&
180 isInt<16>(x: IMMOffset->getZExtValue())) {
181 Base = CurDAG->getCopyFromReg(Chain: CurDAG->getEntryNode(),
182 dl: SDLoc(CurDAG->getEntryNode()), Reg: R600::ZERO,
183 VT: MVT::i32);
184 Offset = CurDAG->getTargetConstant(Val: IMMOffset->getZExtValue(), DL: SDLoc(Addr),
185 VT: MVT::i32);
186 return true;
187 }
188
189 // Default case, no offset
190 Base = Addr;
191 Offset = CurDAG->getTargetConstant(Val: 0, DL: SDLoc(Addr), VT: MVT::i32);
192 return true;
193}
194
195/// This pass converts a legalized DAG into a R600-specific
196// DAG, ready for instruction scheduling.
197FunctionPass *llvm::createR600ISelDag(TargetMachine &TM,
198 CodeGenOptLevel OptLevel) {
199 return new R600DAGToDAGISelLegacy(TM, OptLevel);
200}
201