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 | } // namespace |
52 | |
53 | bool R600DAGToDAGISel::runOnMachineFunction(MachineFunction &MF) { |
54 | Subtarget = &MF.getSubtarget<R600Subtarget>(); |
55 | return SelectionDAGISel::runOnMachineFunction(MF); |
56 | } |
57 | |
58 | bool 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 | |
68 | bool 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 | |
78 | bool 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 | |
89 | void 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 | |
130 | bool 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 | |
154 | bool 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. |
185 | FunctionPass *llvm::createR600ISelDag(TargetMachine &TM, |
186 | CodeGenOptLevel OptLevel) { |
187 | return new R600DAGToDAGISel(TM, OptLevel); |
188 | } |
189 | |