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:
R600DAGToDAGISel(TargetMachine * TM,CodeGenOpt::Level OptLevel)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
PreprocessISelDAG()42 void PreprocessISelDAG() override {}
43
44 protected:
45 // Include the pieces autogenerated from the target description.
46 #include "R600GenDAGISel.inc"
47 };
48
runOnMachineFunction(MachineFunction & MF)49 bool R600DAGToDAGISel::runOnMachineFunction(MachineFunction &MF) {
50 Subtarget = &MF.getSubtarget<R600Subtarget>();
51 return SelectionDAGISel::runOnMachineFunction(MF);
52 }
53
isConstantLoad(const MemSDNode * N,int CbId) const54 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
SelectGlobalValueConstantOffset(SDValue Addr,SDValue & IntPtr)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
SelectGlobalValueVariableOffset(SDValue Addr,SDValue & BaseReg,SDValue & Offset)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
Select(SDNode * N)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
SelectADDRIndirect(SDValue Addr,SDValue & Base,SDValue & Offset)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
SelectADDRVTX_READ(SDValue Addr,SDValue & Base,SDValue & Offset)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.
createR600ISelDag(TargetMachine * TM,CodeGenOpt::Level OptLevel)181 FunctionPass *llvm::createR600ISelDag(TargetMachine *TM,
182 CodeGenOpt::Level OptLevel) {
183 return new R600DAGToDAGISel(TM, OptLevel);
184 }
185