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} // namespace
52
53bool R600DAGToDAGISel::runOnMachineFunction(MachineFunction &MF) {
54 Subtarget = &MF.getSubtarget<R600Subtarget>();
55 return SelectionDAGISel::runOnMachineFunction(MF);
56}
57
58bool 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
68bool R600DAGToDAGISel::SelectGlobalValueConstantOffset(SDValue Addr,
69 SDValue &IntPtr) {
70 if (ConstantSDNode *Cst = dyn_cast<ConstantSDNode>(Val&: Addr)) {
71 IntPtr =
72 CurDAG->getIntPtrConstant(Val: Cst->getZExtValue() / 4, DL: SDLoc(Addr), isTarget: true);
73 return true;
74 }
75 return false;
76}
77
78bool R600DAGToDAGISel::SelectGlobalValueVariableOffset(SDValue Addr,
79 SDValue &BaseReg,
80 SDValue &Offset) {
81 if (!isa<ConstantSDNode>(Val: Addr)) {
82 BaseReg = Addr;
83 Offset = CurDAG->getIntPtrConstant(Val: 0, DL: SDLoc(Addr), isTarget: true);
84 return true;
85 }
86 return false;
87}
88
89void 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(ResNo: 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
130bool R600DAGToDAGISel::SelectADDRIndirect(SDValue Addr, SDValue &Base,
131 SDValue &Offset) {
132 ConstantSDNode *C;
133 SDLoc DL(Addr);
134
135 if ((C = dyn_cast<ConstantSDNode>(Val&: Addr))) {
136 Base = CurDAG->getRegister(R600::Reg: INDIRECT_BASE_ADDR, MVT::VT: i32);
137 Offset = CurDAG->getTargetConstant(C->getZExtValue(), DL, MVT::i32);
138 } else if ((Addr.getOpcode() == AMDGPUISD::DWORDADDR) &&
139 (C = dyn_cast<ConstantSDNode>(Val: Addr.getOperand(i: 0)))) {
140 Base = CurDAG->getRegister(R600::Reg: INDIRECT_BASE_ADDR, MVT::VT: 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>(Val: Addr.getOperand(i: 1)))) {
144 Base = Addr.getOperand(i: 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
154bool 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>(Val: Addr.getOperand(i: 1))) &&
160 isInt<16>(x: IMMOffset->getZExtValue())) {
161
162 Base = Addr.getOperand(i: 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>(Val&: Addr)) &&
168 isInt<16>(x: 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.
185FunctionPass *llvm::createR600ISelDag(TargetMachine &TM,
186 CodeGenOptLevel OptLevel) {
187 return new R600DAGToDAGISel(TM, OptLevel);
188}
189

source code of llvm/lib/Target/AMDGPU/R600ISelDAGToDAG.cpp