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