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 | |
52 | class R600DAGToDAGISelLegacy : public SelectionDAGISelLegacy { |
53 | public: |
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 | |
60 | char R600DAGToDAGISelLegacy::ID = 0; |
61 | |
62 | } // namespace |
63 | |
64 | bool R600DAGToDAGISel::runOnMachineFunction(MachineFunction &MF) { |
65 | Subtarget = &MF.getSubtarget<R600Subtarget>(); |
66 | return SelectionDAGISel::runOnMachineFunction(mf&: MF); |
67 | } |
68 | |
69 | bool 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 | |
79 | bool 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 | |
89 | bool 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 | |
100 | void 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 | |
141 | bool 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 | |
165 | bool 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. |
197 | FunctionPass *llvm::createR600ISelDag(TargetMachine &TM, |
198 | CodeGenOptLevel OptLevel) { |
199 | return new R600DAGToDAGISelLegacy(TM, OptLevel); |
200 | } |
201 | |