blob: 85d0f9dd69127ff6cf5fc00db638dc9d3984d96b [file] [log] [blame]
Tom Stellard75aadc22012-12-11 21:25:42 +00001//===-- AMDILISelDAGToDAG.cpp - A dag to dag inst selector for AMDIL ------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//==-----------------------------------------------------------------------===//
9//
10/// \file
11/// \brief Defines an instruction selector for the AMDGPU target.
12//
13//===----------------------------------------------------------------------===//
14#include "AMDGPUInstrInfo.h"
15#include "AMDGPUISelLowering.h" // For AMDGPUISD
16#include "AMDGPURegisterInfo.h"
Tom Stellard2e59a452014-06-13 01:32:00 +000017#include "AMDGPUSubtarget.h"
Tom Stellard75aadc22012-12-11 21:25:42 +000018#include "R600InstrInfo.h"
Christian Konigf82901a2013-02-26 17:52:23 +000019#include "SIISelLowering.h"
Tom Stellard58ac7442014-04-29 23:12:48 +000020#include "llvm/CodeGen/FunctionLoweringInfo.h"
Tom Stellard75aadc22012-12-11 21:25:42 +000021#include "llvm/CodeGen/PseudoSourceValue.h"
Benjamin Kramerd78bb462013-05-23 17:10:37 +000022#include "llvm/CodeGen/SelectionDAG.h"
Tom Stellard75aadc22012-12-11 21:25:42 +000023#include "llvm/CodeGen/SelectionDAGISel.h"
Tom Stellard58ac7442014-04-29 23:12:48 +000024#include "llvm/IR/Function.h"
Tom Stellard75aadc22012-12-11 21:25:42 +000025
26using namespace llvm;
27
28//===----------------------------------------------------------------------===//
29// Instruction Selector Implementation
30//===----------------------------------------------------------------------===//
31
32namespace {
33/// AMDGPU specific code to select AMDGPU machine instructions for
34/// SelectionDAG operations.
35class AMDGPUDAGToDAGISel : public SelectionDAGISel {
36 // Subtarget - Keep a pointer to the AMDGPU Subtarget around so that we can
37 // make the right decision when generating code for different targets.
38 const AMDGPUSubtarget &Subtarget;
39public:
40 AMDGPUDAGToDAGISel(TargetMachine &TM);
41 virtual ~AMDGPUDAGToDAGISel();
42
Craig Topper5656db42014-04-29 07:57:24 +000043 SDNode *Select(SDNode *N) override;
44 const char *getPassName() const override;
45 void PostprocessISelDAG() override;
Tom Stellard75aadc22012-12-11 21:25:42 +000046
47private:
Tom Stellard7ed0b522014-04-03 20:19:27 +000048 bool isInlineImmediate(SDNode *N) const;
Tom Stellard75aadc22012-12-11 21:25:42 +000049 inline SDValue getSmallIPtrImm(unsigned Imm);
Vincent Lejeunec6896792013-06-04 23:17:15 +000050 bool FoldOperand(SDValue &Src, SDValue &Sel, SDValue &Neg, SDValue &Abs,
Tom Stellard84021442013-07-23 01:48:24 +000051 const R600InstrInfo *TII);
Tom Stellard365366f2013-01-23 02:09:06 +000052 bool FoldOperands(unsigned, const R600InstrInfo *, std::vector<SDValue> &);
Vincent Lejeunec6896792013-06-04 23:17:15 +000053 bool FoldDotOperands(unsigned, const R600InstrInfo *, std::vector<SDValue> &);
Tom Stellard75aadc22012-12-11 21:25:42 +000054
55 // Complex pattern selectors
56 bool SelectADDRParam(SDValue Addr, SDValue& R1, SDValue& R2);
57 bool SelectADDR(SDValue N, SDValue &R1, SDValue &R2);
58 bool SelectADDR64(SDValue N, SDValue &R1, SDValue &R2);
59
60 static bool checkType(const Value *ptr, unsigned int addrspace);
Nick Lewyckyaad475b2014-04-15 07:22:52 +000061 static bool checkPrivateAddress(const MachineMemOperand *Op);
Tom Stellard75aadc22012-12-11 21:25:42 +000062
63 static bool isGlobalStore(const StoreSDNode *N);
64 static bool isPrivateStore(const StoreSDNode *N);
65 static bool isLocalStore(const StoreSDNode *N);
66 static bool isRegionStore(const StoreSDNode *N);
67
Matt Arsenault2aabb062013-06-18 23:37:58 +000068 bool isCPLoad(const LoadSDNode *N) const;
69 bool isConstantLoad(const LoadSDNode *N, int cbID) const;
70 bool isGlobalLoad(const LoadSDNode *N) const;
71 bool isParamLoad(const LoadSDNode *N) const;
72 bool isPrivateLoad(const LoadSDNode *N) const;
73 bool isLocalLoad(const LoadSDNode *N) const;
74 bool isRegionLoad(const LoadSDNode *N) const;
Tom Stellard75aadc22012-12-11 21:25:42 +000075
Tom Stellard58ac7442014-04-29 23:12:48 +000076 /// \returns True if the current basic block being selected is at control
77 /// flow depth 0. Meaning that the current block dominates the
78 // exit block.
79 bool isCFDepth0() const;
80
Tom Stellarddf94dc32013-08-14 23:24:24 +000081 const TargetRegisterClass *getOperandRegClass(SDNode *N, unsigned OpNo) const;
Tom Stellard365366f2013-01-23 02:09:06 +000082 bool SelectGlobalValueConstantOffset(SDValue Addr, SDValue& IntPtr);
Matt Arsenault209a7b92014-04-18 07:40:20 +000083 bool SelectGlobalValueVariableOffset(SDValue Addr, SDValue &BaseReg,
84 SDValue& Offset);
Tom Stellard75aadc22012-12-11 21:25:42 +000085 bool SelectADDRVTX_READ(SDValue Addr, SDValue &Base, SDValue &Offset);
Tom Stellardf3b2a1e2013-02-06 17:32:29 +000086 bool SelectADDRIndirect(SDValue Addr, SDValue &Base, SDValue &Offset);
Tom Stellard75aadc22012-12-11 21:25:42 +000087
Matt Arsenaultb8b51532014-06-23 18:00:38 +000088 SDNode *SelectADD_SUB_I64(SDNode *N);
Matt Arsenault9fa3f932014-06-23 18:00:34 +000089
Tom Stellard75aadc22012-12-11 21:25:42 +000090 // Include the pieces autogenerated from the target description.
91#include "AMDGPUGenDAGISel.inc"
92};
93} // end anonymous namespace
94
95/// \brief This pass converts a legalized DAG into a AMDGPU-specific
96// DAG, ready for instruction scheduling.
Matt Arsenault209a7b92014-04-18 07:40:20 +000097FunctionPass *llvm::createAMDGPUISelDag(TargetMachine &TM) {
Tom Stellard75aadc22012-12-11 21:25:42 +000098 return new AMDGPUDAGToDAGISel(TM);
99}
100
Bill Wendlinga3cd3502013-06-19 21:36:55 +0000101AMDGPUDAGToDAGISel::AMDGPUDAGToDAGISel(TargetMachine &TM)
Tom Stellard75aadc22012-12-11 21:25:42 +0000102 : SelectionDAGISel(TM), Subtarget(TM.getSubtarget<AMDGPUSubtarget>()) {
103}
104
105AMDGPUDAGToDAGISel::~AMDGPUDAGToDAGISel() {
106}
107
Tom Stellard7ed0b522014-04-03 20:19:27 +0000108bool AMDGPUDAGToDAGISel::isInlineImmediate(SDNode *N) const {
109 const SITargetLowering *TL
110 = static_cast<const SITargetLowering *>(getTargetLowering());
111 return TL->analyzeImmediate(N) == 0;
112}
113
Tom Stellarddf94dc32013-08-14 23:24:24 +0000114/// \brief Determine the register class for \p OpNo
115/// \returns The register class of the virtual register that will be used for
116/// the given operand number \OpNo or NULL if the register class cannot be
117/// determined.
118const TargetRegisterClass *AMDGPUDAGToDAGISel::getOperandRegClass(SDNode *N,
119 unsigned OpNo) const {
Matt Arsenault209a7b92014-04-18 07:40:20 +0000120 if (!N->isMachineOpcode())
121 return nullptr;
122
Tom Stellarddf94dc32013-08-14 23:24:24 +0000123 switch (N->getMachineOpcode()) {
124 default: {
125 const MCInstrDesc &Desc = TM.getInstrInfo()->get(N->getMachineOpcode());
Alexey Samsonov3186eb32013-08-15 07:11:34 +0000126 unsigned OpIdx = Desc.getNumDefs() + OpNo;
127 if (OpIdx >= Desc.getNumOperands())
Matt Arsenault209a7b92014-04-18 07:40:20 +0000128 return nullptr;
Alexey Samsonov3186eb32013-08-15 07:11:34 +0000129 int RegClass = Desc.OpInfo[OpIdx].RegClass;
Matt Arsenault209a7b92014-04-18 07:40:20 +0000130 if (RegClass == -1)
131 return nullptr;
132
Tom Stellarddf94dc32013-08-14 23:24:24 +0000133 return TM.getRegisterInfo()->getRegClass(RegClass);
134 }
135 case AMDGPU::REG_SEQUENCE: {
Matt Arsenault209a7b92014-04-18 07:40:20 +0000136 unsigned RCID = cast<ConstantSDNode>(N->getOperand(0))->getZExtValue();
137 const TargetRegisterClass *SuperRC = TM.getRegisterInfo()->getRegClass(RCID);
138
139 SDValue SubRegOp = N->getOperand(OpNo + 1);
140 unsigned SubRegIdx = cast<ConstantSDNode>(SubRegOp)->getZExtValue();
Tom Stellarddf94dc32013-08-14 23:24:24 +0000141 return TM.getRegisterInfo()->getSubClassWithSubReg(SuperRC, SubRegIdx);
142 }
143 }
144}
145
Tom Stellard75aadc22012-12-11 21:25:42 +0000146SDValue AMDGPUDAGToDAGISel::getSmallIPtrImm(unsigned int Imm) {
147 return CurDAG->getTargetConstant(Imm, MVT::i32);
148}
149
150bool AMDGPUDAGToDAGISel::SelectADDRParam(
Matt Arsenault209a7b92014-04-18 07:40:20 +0000151 SDValue Addr, SDValue& R1, SDValue& R2) {
Tom Stellard75aadc22012-12-11 21:25:42 +0000152
153 if (Addr.getOpcode() == ISD::FrameIndex) {
154 if (FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode>(Addr)) {
155 R1 = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i32);
156 R2 = CurDAG->getTargetConstant(0, MVT::i32);
157 } else {
158 R1 = Addr;
159 R2 = CurDAG->getTargetConstant(0, MVT::i32);
160 }
161 } else if (Addr.getOpcode() == ISD::ADD) {
162 R1 = Addr.getOperand(0);
163 R2 = Addr.getOperand(1);
164 } else {
165 R1 = Addr;
166 R2 = CurDAG->getTargetConstant(0, MVT::i32);
167 }
168 return true;
169}
170
171bool AMDGPUDAGToDAGISel::SelectADDR(SDValue Addr, SDValue& R1, SDValue& R2) {
172 if (Addr.getOpcode() == ISD::TargetExternalSymbol ||
173 Addr.getOpcode() == ISD::TargetGlobalAddress) {
174 return false;
175 }
176 return SelectADDRParam(Addr, R1, R2);
177}
178
179
180bool AMDGPUDAGToDAGISel::SelectADDR64(SDValue Addr, SDValue& R1, SDValue& R2) {
181 if (Addr.getOpcode() == ISD::TargetExternalSymbol ||
182 Addr.getOpcode() == ISD::TargetGlobalAddress) {
183 return false;
184 }
185
186 if (Addr.getOpcode() == ISD::FrameIndex) {
187 if (FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode>(Addr)) {
188 R1 = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i64);
189 R2 = CurDAG->getTargetConstant(0, MVT::i64);
190 } else {
191 R1 = Addr;
192 R2 = CurDAG->getTargetConstant(0, MVT::i64);
193 }
194 } else if (Addr.getOpcode() == ISD::ADD) {
195 R1 = Addr.getOperand(0);
196 R2 = Addr.getOperand(1);
197 } else {
198 R1 = Addr;
199 R2 = CurDAG->getTargetConstant(0, MVT::i64);
200 }
201 return true;
202}
203
204SDNode *AMDGPUDAGToDAGISel::Select(SDNode *N) {
205 unsigned int Opc = N->getOpcode();
206 if (N->isMachineOpcode()) {
Tim Northover31d093c2013-09-22 08:21:56 +0000207 N->setNodeId(-1);
Matt Arsenault209a7b92014-04-18 07:40:20 +0000208 return nullptr; // Already selected.
Tom Stellard75aadc22012-12-11 21:25:42 +0000209 }
Matt Arsenault78b86702014-04-18 05:19:26 +0000210
211 const AMDGPUSubtarget &ST = TM.getSubtarget<AMDGPUSubtarget>();
Tom Stellard75aadc22012-12-11 21:25:42 +0000212 switch (Opc) {
213 default: break;
Tom Stellard1f15bff2014-02-25 21:36:18 +0000214 // We are selecting i64 ADD here instead of custom lower it during
215 // DAG legalization, so we can fold some i64 ADDs used for address
216 // calculation into the LOAD and STORE instructions.
Matt Arsenaultb8b51532014-06-23 18:00:38 +0000217 case ISD::ADD:
218 case ISD::SUB: {
Tom Stellard1f15bff2014-02-25 21:36:18 +0000219 if (N->getValueType(0) != MVT::i64 ||
220 ST.getGeneration() < AMDGPUSubtarget::SOUTHERN_ISLANDS)
221 break;
222
Matt Arsenaultb8b51532014-06-23 18:00:38 +0000223 return SelectADD_SUB_I64(N);
Tom Stellard1f15bff2014-02-25 21:36:18 +0000224 }
Matt Arsenault064c2062014-06-11 17:40:32 +0000225 case ISD::SCALAR_TO_VECTOR:
Tom Stellard880a80a2014-06-17 16:53:14 +0000226 case AMDGPUISD::BUILD_VERTICAL_VECTOR:
Vincent Lejeune3b6f20e2013-03-05 15:04:49 +0000227 case ISD::BUILD_VECTOR: {
Tom Stellard8e5da412013-08-14 23:24:32 +0000228 unsigned RegClassID;
Tom Stellard8e5da412013-08-14 23:24:32 +0000229 const AMDGPURegisterInfo *TRI =
230 static_cast<const AMDGPURegisterInfo*>(TM.getRegisterInfo());
231 const SIRegisterInfo *SIRI =
232 static_cast<const SIRegisterInfo*>(TM.getRegisterInfo());
233 EVT VT = N->getValueType(0);
234 unsigned NumVectorElts = VT.getVectorNumElements();
Matt Arsenault064c2062014-06-11 17:40:32 +0000235 EVT EltVT = VT.getVectorElementType();
236 assert(EltVT.bitsEq(MVT::i32));
Tom Stellard8e5da412013-08-14 23:24:32 +0000237 if (ST.getGeneration() >= AMDGPUSubtarget::SOUTHERN_ISLANDS) {
238 bool UseVReg = true;
239 for (SDNode::use_iterator U = N->use_begin(), E = SDNode::use_end();
240 U != E; ++U) {
241 if (!U->isMachineOpcode()) {
242 continue;
243 }
244 const TargetRegisterClass *RC = getOperandRegClass(*U, U.getOperandNo());
245 if (!RC) {
246 continue;
247 }
248 if (SIRI->isSGPRClass(RC)) {
249 UseVReg = false;
250 }
251 }
252 switch(NumVectorElts) {
253 case 1: RegClassID = UseVReg ? AMDGPU::VReg_32RegClassID :
254 AMDGPU::SReg_32RegClassID;
255 break;
256 case 2: RegClassID = UseVReg ? AMDGPU::VReg_64RegClassID :
257 AMDGPU::SReg_64RegClassID;
258 break;
259 case 4: RegClassID = UseVReg ? AMDGPU::VReg_128RegClassID :
260 AMDGPU::SReg_128RegClassID;
261 break;
262 case 8: RegClassID = UseVReg ? AMDGPU::VReg_256RegClassID :
263 AMDGPU::SReg_256RegClassID;
264 break;
265 case 16: RegClassID = UseVReg ? AMDGPU::VReg_512RegClassID :
266 AMDGPU::SReg_512RegClassID;
267 break;
Benjamin Kramerbda73ff2013-08-31 21:20:04 +0000268 default: llvm_unreachable("Do not know how to lower this BUILD_VECTOR");
Tom Stellard8e5da412013-08-14 23:24:32 +0000269 }
270 } else {
271 // BUILD_VECTOR was lowered into an IMPLICIT_DEF + 4 INSERT_SUBREG
272 // that adds a 128 bits reg copy when going through TwoAddressInstructions
273 // pass. We want to avoid 128 bits copies as much as possible because they
274 // can't be bundled by our scheduler.
275 switch(NumVectorElts) {
276 case 2: RegClassID = AMDGPU::R600_Reg64RegClassID; break;
Tom Stellard880a80a2014-06-17 16:53:14 +0000277 case 4:
278 if (Opc == AMDGPUISD::BUILD_VERTICAL_VECTOR)
279 RegClassID = AMDGPU::R600_Reg128VerticalRegClassID;
280 else
281 RegClassID = AMDGPU::R600_Reg128RegClassID;
282 break;
Tom Stellard8e5da412013-08-14 23:24:32 +0000283 default: llvm_unreachable("Do not know how to lower this BUILD_VECTOR");
284 }
Vincent Lejeune3b6f20e2013-03-05 15:04:49 +0000285 }
Tom Stellard0344cdf2013-08-01 15:23:42 +0000286
Tom Stellard8e5da412013-08-14 23:24:32 +0000287 SDValue RegClass = CurDAG->getTargetConstant(RegClassID, MVT::i32);
288
289 if (NumVectorElts == 1) {
Matt Arsenault064c2062014-06-11 17:40:32 +0000290 return CurDAG->SelectNodeTo(N, AMDGPU::COPY_TO_REGCLASS, EltVT,
Tom Stellard8e5da412013-08-14 23:24:32 +0000291 N->getOperand(0), RegClass);
Tom Stellard0344cdf2013-08-01 15:23:42 +0000292 }
Tom Stellard8e5da412013-08-14 23:24:32 +0000293
294 assert(NumVectorElts <= 16 && "Vectors with more than 16 elements not "
295 "supported yet");
296 // 16 = Max Num Vector Elements
297 // 2 = 2 REG_SEQUENCE operands per element (value, subreg index)
298 // 1 = Vector Register Class
Matt Arsenault064c2062014-06-11 17:40:32 +0000299 SmallVector<SDValue, 16 * 2 + 1> RegSeqArgs(NumVectorElts * 2 + 1);
Tom Stellard8e5da412013-08-14 23:24:32 +0000300
301 RegSeqArgs[0] = CurDAG->getTargetConstant(RegClassID, MVT::i32);
Vincent Lejeune3b6f20e2013-03-05 15:04:49 +0000302 bool IsRegSeq = true;
Matt Arsenault064c2062014-06-11 17:40:32 +0000303 unsigned NOps = N->getNumOperands();
304 for (unsigned i = 0; i < NOps; i++) {
Tom Stellard8e5da412013-08-14 23:24:32 +0000305 // XXX: Why is this here?
Vincent Lejeune3b6f20e2013-03-05 15:04:49 +0000306 if (dyn_cast<RegisterSDNode>(N->getOperand(i))) {
307 IsRegSeq = false;
308 break;
309 }
Tom Stellard8e5da412013-08-14 23:24:32 +0000310 RegSeqArgs[1 + (2 * i)] = N->getOperand(i);
311 RegSeqArgs[1 + (2 * i) + 1] =
312 CurDAG->getTargetConstant(TRI->getSubRegFromChannel(i), MVT::i32);
Vincent Lejeune3b6f20e2013-03-05 15:04:49 +0000313 }
Matt Arsenault064c2062014-06-11 17:40:32 +0000314
315 if (NOps != NumVectorElts) {
316 // Fill in the missing undef elements if this was a scalar_to_vector.
317 assert(Opc == ISD::SCALAR_TO_VECTOR && NOps < NumVectorElts);
318
319 MachineSDNode *ImpDef = CurDAG->getMachineNode(TargetOpcode::IMPLICIT_DEF,
320 SDLoc(N), EltVT);
321 for (unsigned i = NOps; i < NumVectorElts; ++i) {
322 RegSeqArgs[1 + (2 * i)] = SDValue(ImpDef, 0);
323 RegSeqArgs[1 + (2 * i) + 1] =
324 CurDAG->getTargetConstant(TRI->getSubRegFromChannel(i), MVT::i32);
325 }
326 }
327
Vincent Lejeune3b6f20e2013-03-05 15:04:49 +0000328 if (!IsRegSeq)
329 break;
330 return CurDAG->SelectNodeTo(N, AMDGPU::REG_SEQUENCE, N->getVTList(),
Craig Topper481fb282014-04-27 19:21:11 +0000331 RegSeqArgs);
Vincent Lejeune3b6f20e2013-03-05 15:04:49 +0000332 }
Tom Stellard754f80f2013-04-05 23:31:51 +0000333 case ISD::BUILD_PAIR: {
334 SDValue RC, SubReg0, SubReg1;
Tom Stellarda6c6e1b2013-06-07 20:37:48 +0000335 if (ST.getGeneration() <= AMDGPUSubtarget::NORTHERN_ISLANDS) {
Tom Stellard754f80f2013-04-05 23:31:51 +0000336 break;
337 }
338 if (N->getValueType(0) == MVT::i128) {
339 RC = CurDAG->getTargetConstant(AMDGPU::SReg_128RegClassID, MVT::i32);
340 SubReg0 = CurDAG->getTargetConstant(AMDGPU::sub0_sub1, MVT::i32);
341 SubReg1 = CurDAG->getTargetConstant(AMDGPU::sub2_sub3, MVT::i32);
342 } else if (N->getValueType(0) == MVT::i64) {
Tom Stellard1aa6cb42014-04-18 00:36:21 +0000343 RC = CurDAG->getTargetConstant(AMDGPU::SReg_64RegClassID, MVT::i32);
Tom Stellard754f80f2013-04-05 23:31:51 +0000344 SubReg0 = CurDAG->getTargetConstant(AMDGPU::sub0, MVT::i32);
345 SubReg1 = CurDAG->getTargetConstant(AMDGPU::sub1, MVT::i32);
346 } else {
347 llvm_unreachable("Unhandled value type for BUILD_PAIR");
348 }
349 const SDValue Ops[] = { RC, N->getOperand(0), SubReg0,
350 N->getOperand(1), SubReg1 };
351 return CurDAG->getMachineNode(TargetOpcode::REG_SEQUENCE,
Andrew Trickef9de2a2013-05-25 02:42:55 +0000352 SDLoc(N), N->getValueType(0), Ops);
Tom Stellard754f80f2013-04-05 23:31:51 +0000353 }
Tom Stellard7ed0b522014-04-03 20:19:27 +0000354
355 case ISD::Constant:
356 case ISD::ConstantFP: {
357 const AMDGPUSubtarget &ST = TM.getSubtarget<AMDGPUSubtarget>();
358 if (ST.getGeneration() < AMDGPUSubtarget::SOUTHERN_ISLANDS ||
359 N->getValueType(0).getSizeInBits() != 64 || isInlineImmediate(N))
360 break;
361
362 uint64_t Imm;
363 if (ConstantFPSDNode *FP = dyn_cast<ConstantFPSDNode>(N))
364 Imm = FP->getValueAPF().bitcastToAPInt().getZExtValue();
365 else {
Tom Stellard3cbe0142014-04-07 19:31:13 +0000366 ConstantSDNode *C = cast<ConstantSDNode>(N);
Tom Stellard7ed0b522014-04-03 20:19:27 +0000367 Imm = C->getZExtValue();
368 }
369
370 SDNode *Lo = CurDAG->getMachineNode(AMDGPU::S_MOV_B32, SDLoc(N), MVT::i32,
371 CurDAG->getConstant(Imm & 0xFFFFFFFF, MVT::i32));
372 SDNode *Hi = CurDAG->getMachineNode(AMDGPU::S_MOV_B32, SDLoc(N), MVT::i32,
373 CurDAG->getConstant(Imm >> 32, MVT::i32));
374 const SDValue Ops[] = {
375 CurDAG->getTargetConstant(AMDGPU::SReg_64RegClassID, MVT::i32),
376 SDValue(Lo, 0), CurDAG->getTargetConstant(AMDGPU::sub0, MVT::i32),
377 SDValue(Hi, 0), CurDAG->getTargetConstant(AMDGPU::sub1, MVT::i32)
378 };
379
380 return CurDAG->getMachineNode(TargetOpcode::REG_SEQUENCE, SDLoc(N),
381 N->getValueType(0), Ops);
382 }
383
Tom Stellard81d871d2013-11-13 23:36:50 +0000384 case AMDGPUISD::REGISTER_LOAD: {
Tom Stellard81d871d2013-11-13 23:36:50 +0000385 if (ST.getGeneration() <= AMDGPUSubtarget::NORTHERN_ISLANDS)
386 break;
387 SDValue Addr, Offset;
388
389 SelectADDRIndirect(N->getOperand(1), Addr, Offset);
390 const SDValue Ops[] = {
391 Addr,
392 Offset,
393 CurDAG->getTargetConstant(0, MVT::i32),
394 N->getOperand(0),
395 };
396 return CurDAG->getMachineNode(AMDGPU::SI_RegisterLoad, SDLoc(N),
397 CurDAG->getVTList(MVT::i32, MVT::i64, MVT::Other),
398 Ops);
399 }
400 case AMDGPUISD::REGISTER_STORE: {
Tom Stellard81d871d2013-11-13 23:36:50 +0000401 if (ST.getGeneration() <= AMDGPUSubtarget::NORTHERN_ISLANDS)
402 break;
403 SDValue Addr, Offset;
404 SelectADDRIndirect(N->getOperand(2), Addr, Offset);
405 const SDValue Ops[] = {
406 N->getOperand(1),
407 Addr,
408 Offset,
409 CurDAG->getTargetConstant(0, MVT::i32),
410 N->getOperand(0),
411 };
412 return CurDAG->getMachineNode(AMDGPU::SI_RegisterStorePseudo, SDLoc(N),
413 CurDAG->getVTList(MVT::Other),
414 Ops);
415 }
Matt Arsenault78b86702014-04-18 05:19:26 +0000416
417 case AMDGPUISD::BFE_I32:
418 case AMDGPUISD::BFE_U32: {
419 if (ST.getGeneration() < AMDGPUSubtarget::SOUTHERN_ISLANDS)
420 break;
421
422 // There is a scalar version available, but unlike the vector version which
423 // has a separate operand for the offset and width, the scalar version packs
424 // the width and offset into a single operand. Try to move to the scalar
425 // version if the offsets are constant, so that we can try to keep extended
426 // loads of kernel arguments in SGPRs.
427
428 // TODO: Technically we could try to pattern match scalar bitshifts of
429 // dynamic values, but it's probably not useful.
430 ConstantSDNode *Offset = dyn_cast<ConstantSDNode>(N->getOperand(1));
431 if (!Offset)
432 break;
433
434 ConstantSDNode *Width = dyn_cast<ConstantSDNode>(N->getOperand(2));
435 if (!Width)
436 break;
437
438 bool Signed = Opc == AMDGPUISD::BFE_I32;
439
440 // Transformation function, pack the offset and width of a BFE into
441 // the format expected by the S_BFE_I32 / S_BFE_U32. In the second
442 // source, bits [5:0] contain the offset and bits [22:16] the width.
443
444 uint32_t OffsetVal = Offset->getZExtValue();
445 uint32_t WidthVal = Width->getZExtValue();
446
447 uint32_t PackedVal = OffsetVal | WidthVal << 16;
448
449 SDValue PackedOffsetWidth = CurDAG->getTargetConstant(PackedVal, MVT::i32);
450 return CurDAG->getMachineNode(Signed ? AMDGPU::S_BFE_I32 : AMDGPU::S_BFE_U32,
451 SDLoc(N),
452 MVT::i32,
453 N->getOperand(0),
454 PackedOffsetWidth);
455
456 }
Tom Stellard75aadc22012-12-11 21:25:42 +0000457 }
Vincent Lejeune0167a312013-09-12 23:45:00 +0000458 return SelectCode(N);
Tom Stellard365366f2013-01-23 02:09:06 +0000459}
460
Tom Stellard75aadc22012-12-11 21:25:42 +0000461
Matt Arsenault209a7b92014-04-18 07:40:20 +0000462bool AMDGPUDAGToDAGISel::checkType(const Value *Ptr, unsigned AS) {
463 assert(AS != 0 && "Use checkPrivateAddress instead.");
464 if (!Ptr)
Tom Stellard75aadc22012-12-11 21:25:42 +0000465 return false;
Matt Arsenault209a7b92014-04-18 07:40:20 +0000466
467 return Ptr->getType()->getPointerAddressSpace() == AS;
Tom Stellard75aadc22012-12-11 21:25:42 +0000468}
469
Nick Lewyckyaad475b2014-04-15 07:22:52 +0000470bool AMDGPUDAGToDAGISel::checkPrivateAddress(const MachineMemOperand *Op) {
Matt Arsenault209a7b92014-04-18 07:40:20 +0000471 if (Op->getPseudoValue())
472 return true;
473
474 if (PointerType *PT = dyn_cast<PointerType>(Op->getValue()->getType()))
475 return PT->getAddressSpace() == AMDGPUAS::PRIVATE_ADDRESS;
476
477 return false;
Nick Lewyckyaad475b2014-04-15 07:22:52 +0000478}
479
Tom Stellard75aadc22012-12-11 21:25:42 +0000480bool AMDGPUDAGToDAGISel::isGlobalStore(const StoreSDNode *N) {
Nick Lewyckyaad475b2014-04-15 07:22:52 +0000481 return checkType(N->getMemOperand()->getValue(), AMDGPUAS::GLOBAL_ADDRESS);
Tom Stellard75aadc22012-12-11 21:25:42 +0000482}
483
484bool AMDGPUDAGToDAGISel::isPrivateStore(const StoreSDNode *N) {
Matt Arsenault209a7b92014-04-18 07:40:20 +0000485 const Value *MemVal = N->getMemOperand()->getValue();
486 return (!checkType(MemVal, AMDGPUAS::LOCAL_ADDRESS) &&
487 !checkType(MemVal, AMDGPUAS::GLOBAL_ADDRESS) &&
488 !checkType(MemVal, AMDGPUAS::REGION_ADDRESS));
Tom Stellard75aadc22012-12-11 21:25:42 +0000489}
490
491bool AMDGPUDAGToDAGISel::isLocalStore(const StoreSDNode *N) {
Nick Lewyckyaad475b2014-04-15 07:22:52 +0000492 return checkType(N->getMemOperand()->getValue(), AMDGPUAS::LOCAL_ADDRESS);
Tom Stellard75aadc22012-12-11 21:25:42 +0000493}
494
495bool AMDGPUDAGToDAGISel::isRegionStore(const StoreSDNode *N) {
Nick Lewyckyaad475b2014-04-15 07:22:52 +0000496 return checkType(N->getMemOperand()->getValue(), AMDGPUAS::REGION_ADDRESS);
Tom Stellard75aadc22012-12-11 21:25:42 +0000497}
498
Tom Stellard1e803092013-07-23 01:48:18 +0000499bool AMDGPUDAGToDAGISel::isConstantLoad(const LoadSDNode *N, int CbId) const {
Matt Arsenault209a7b92014-04-18 07:40:20 +0000500 const Value *MemVal = N->getMemOperand()->getValue();
501 if (CbId == -1)
502 return checkType(MemVal, AMDGPUAS::CONSTANT_ADDRESS);
503
504 return checkType(MemVal, AMDGPUAS::CONSTANT_BUFFER_0 + CbId);
Tom Stellard75aadc22012-12-11 21:25:42 +0000505}
506
Matt Arsenault2aabb062013-06-18 23:37:58 +0000507bool AMDGPUDAGToDAGISel::isGlobalLoad(const LoadSDNode *N) const {
Tom Stellard8cb0e472013-07-23 23:54:56 +0000508 if (N->getAddressSpace() == AMDGPUAS::CONSTANT_ADDRESS) {
509 const AMDGPUSubtarget &ST = TM.getSubtarget<AMDGPUSubtarget>();
510 if (ST.getGeneration() < AMDGPUSubtarget::SOUTHERN_ISLANDS ||
511 N->getMemoryVT().bitsLT(MVT::i32)) {
512 return true;
513 }
514 }
Nick Lewyckyaad475b2014-04-15 07:22:52 +0000515 return checkType(N->getMemOperand()->getValue(), AMDGPUAS::GLOBAL_ADDRESS);
Tom Stellard75aadc22012-12-11 21:25:42 +0000516}
517
Matt Arsenault2aabb062013-06-18 23:37:58 +0000518bool AMDGPUDAGToDAGISel::isParamLoad(const LoadSDNode *N) const {
Nick Lewyckyaad475b2014-04-15 07:22:52 +0000519 return checkType(N->getMemOperand()->getValue(), AMDGPUAS::PARAM_I_ADDRESS);
Tom Stellard75aadc22012-12-11 21:25:42 +0000520}
521
Matt Arsenault2aabb062013-06-18 23:37:58 +0000522bool AMDGPUDAGToDAGISel::isLocalLoad(const LoadSDNode *N) const {
Nick Lewyckyaad475b2014-04-15 07:22:52 +0000523 return checkType(N->getMemOperand()->getValue(), AMDGPUAS::LOCAL_ADDRESS);
Tom Stellard75aadc22012-12-11 21:25:42 +0000524}
525
Matt Arsenault2aabb062013-06-18 23:37:58 +0000526bool AMDGPUDAGToDAGISel::isRegionLoad(const LoadSDNode *N) const {
Nick Lewyckyaad475b2014-04-15 07:22:52 +0000527 return checkType(N->getMemOperand()->getValue(), AMDGPUAS::REGION_ADDRESS);
Tom Stellard75aadc22012-12-11 21:25:42 +0000528}
529
Matt Arsenault2aabb062013-06-18 23:37:58 +0000530bool AMDGPUDAGToDAGISel::isCPLoad(const LoadSDNode *N) const {
Tom Stellard75aadc22012-12-11 21:25:42 +0000531 MachineMemOperand *MMO = N->getMemOperand();
Nick Lewyckyaad475b2014-04-15 07:22:52 +0000532 if (checkPrivateAddress(N->getMemOperand())) {
Tom Stellard75aadc22012-12-11 21:25:42 +0000533 if (MMO) {
Nick Lewyckyaad475b2014-04-15 07:22:52 +0000534 const PseudoSourceValue *PSV = MMO->getPseudoValue();
Tom Stellard75aadc22012-12-11 21:25:42 +0000535 if (PSV && PSV == PseudoSourceValue::getConstantPool()) {
536 return true;
537 }
538 }
539 }
540 return false;
541}
542
Matt Arsenault2aabb062013-06-18 23:37:58 +0000543bool AMDGPUDAGToDAGISel::isPrivateLoad(const LoadSDNode *N) const {
Nick Lewyckyaad475b2014-04-15 07:22:52 +0000544 if (checkPrivateAddress(N->getMemOperand())) {
Tom Stellard75aadc22012-12-11 21:25:42 +0000545 // Check to make sure we are not a constant pool load or a constant load
546 // that is marked as a private load
547 if (isCPLoad(N) || isConstantLoad(N, -1)) {
548 return false;
549 }
550 }
Matt Arsenault209a7b92014-04-18 07:40:20 +0000551
552 const Value *MemVal = N->getMemOperand()->getValue();
553 if (!checkType(MemVal, AMDGPUAS::LOCAL_ADDRESS) &&
554 !checkType(MemVal, AMDGPUAS::GLOBAL_ADDRESS) &&
555 !checkType(MemVal, AMDGPUAS::REGION_ADDRESS) &&
556 !checkType(MemVal, AMDGPUAS::CONSTANT_ADDRESS) &&
557 !checkType(MemVal, AMDGPUAS::PARAM_D_ADDRESS) &&
558 !checkType(MemVal, AMDGPUAS::PARAM_I_ADDRESS)){
Tom Stellard75aadc22012-12-11 21:25:42 +0000559 return true;
560 }
561 return false;
562}
563
Tom Stellard58ac7442014-04-29 23:12:48 +0000564bool AMDGPUDAGToDAGISel::isCFDepth0() const {
565 // FIXME: Figure out a way to use DominatorTree analysis here.
566 const BasicBlock *CurBlock = FuncInfo->MBB->getBasicBlock();
567 const Function *Fn = FuncInfo->Fn;
568 return &Fn->front() == CurBlock || &Fn->back() == CurBlock;
569}
570
571
Tom Stellard75aadc22012-12-11 21:25:42 +0000572const char *AMDGPUDAGToDAGISel::getPassName() const {
573 return "AMDGPU DAG->DAG Pattern Instruction Selection";
574}
575
576#ifdef DEBUGTMP
577#undef INT64_C
578#endif
579#undef DEBUGTMP
580
Tom Stellard41fc7852013-07-23 01:48:42 +0000581//===----------------------------------------------------------------------===//
582// Complex Patterns
583//===----------------------------------------------------------------------===//
Tom Stellard75aadc22012-12-11 21:25:42 +0000584
Tom Stellard365366f2013-01-23 02:09:06 +0000585bool AMDGPUDAGToDAGISel::SelectGlobalValueConstantOffset(SDValue Addr,
Matt Arsenault209a7b92014-04-18 07:40:20 +0000586 SDValue& IntPtr) {
Tom Stellard365366f2013-01-23 02:09:06 +0000587 if (ConstantSDNode *Cst = dyn_cast<ConstantSDNode>(Addr)) {
588 IntPtr = CurDAG->getIntPtrConstant(Cst->getZExtValue() / 4, true);
589 return true;
590 }
591 return false;
592}
593
594bool AMDGPUDAGToDAGISel::SelectGlobalValueVariableOffset(SDValue Addr,
595 SDValue& BaseReg, SDValue &Offset) {
Matt Arsenault209a7b92014-04-18 07:40:20 +0000596 if (!isa<ConstantSDNode>(Addr)) {
Tom Stellard365366f2013-01-23 02:09:06 +0000597 BaseReg = Addr;
598 Offset = CurDAG->getIntPtrConstant(0, true);
599 return true;
600 }
601 return false;
602}
603
Tom Stellard75aadc22012-12-11 21:25:42 +0000604bool AMDGPUDAGToDAGISel::SelectADDRVTX_READ(SDValue Addr, SDValue &Base,
605 SDValue &Offset) {
Matt Arsenault209a7b92014-04-18 07:40:20 +0000606 ConstantSDNode *IMMOffset;
Tom Stellard75aadc22012-12-11 21:25:42 +0000607
608 if (Addr.getOpcode() == ISD::ADD
609 && (IMMOffset = dyn_cast<ConstantSDNode>(Addr.getOperand(1)))
610 && isInt<16>(IMMOffset->getZExtValue())) {
611
612 Base = Addr.getOperand(0);
613 Offset = CurDAG->getTargetConstant(IMMOffset->getZExtValue(), MVT::i32);
614 return true;
615 // If the pointer address is constant, we can move it to the offset field.
616 } else if ((IMMOffset = dyn_cast<ConstantSDNode>(Addr))
617 && isInt<16>(IMMOffset->getZExtValue())) {
618 Base = CurDAG->getCopyFromReg(CurDAG->getEntryNode(),
Andrew Trickef9de2a2013-05-25 02:42:55 +0000619 SDLoc(CurDAG->getEntryNode()),
Tom Stellard75aadc22012-12-11 21:25:42 +0000620 AMDGPU::ZERO, MVT::i32);
621 Offset = CurDAG->getTargetConstant(IMMOffset->getZExtValue(), MVT::i32);
622 return true;
623 }
624
625 // Default case, no offset
626 Base = Addr;
627 Offset = CurDAG->getTargetConstant(0, MVT::i32);
628 return true;
629}
630
Tom Stellardf3b2a1e2013-02-06 17:32:29 +0000631bool AMDGPUDAGToDAGISel::SelectADDRIndirect(SDValue Addr, SDValue &Base,
632 SDValue &Offset) {
633 ConstantSDNode *C;
634
635 if ((C = dyn_cast<ConstantSDNode>(Addr))) {
636 Base = CurDAG->getRegister(AMDGPU::INDIRECT_BASE_ADDR, MVT::i32);
637 Offset = CurDAG->getTargetConstant(C->getZExtValue(), MVT::i32);
638 } else if ((Addr.getOpcode() == ISD::ADD || Addr.getOpcode() == ISD::OR) &&
639 (C = dyn_cast<ConstantSDNode>(Addr.getOperand(1)))) {
640 Base = Addr.getOperand(0);
641 Offset = CurDAG->getTargetConstant(C->getZExtValue(), MVT::i32);
642 } else {
643 Base = Addr;
644 Offset = CurDAG->getTargetConstant(0, MVT::i32);
645 }
646
647 return true;
648}
Christian Konigd910b7d2013-02-26 17:52:16 +0000649
Matt Arsenaultb8b51532014-06-23 18:00:38 +0000650SDNode *AMDGPUDAGToDAGISel::SelectADD_SUB_I64(SDNode *N) {
Matt Arsenault9fa3f932014-06-23 18:00:34 +0000651 SDLoc DL(N);
652 SDValue LHS = N->getOperand(0);
653 SDValue RHS = N->getOperand(1);
654
Matt Arsenaultb8b51532014-06-23 18:00:38 +0000655 bool IsAdd = (N->getOpcode() == ISD::ADD);
656
Matt Arsenault9fa3f932014-06-23 18:00:34 +0000657 SDValue Sub0 = CurDAG->getTargetConstant(AMDGPU::sub0, MVT::i32);
658 SDValue Sub1 = CurDAG->getTargetConstant(AMDGPU::sub1, MVT::i32);
659
660 SDNode *Lo0 = CurDAG->getMachineNode(TargetOpcode::EXTRACT_SUBREG,
661 DL, MVT::i32, LHS, Sub0);
662 SDNode *Hi0 = CurDAG->getMachineNode(TargetOpcode::EXTRACT_SUBREG,
663 DL, MVT::i32, LHS, Sub1);
664
665 SDNode *Lo1 = CurDAG->getMachineNode(TargetOpcode::EXTRACT_SUBREG,
666 DL, MVT::i32, RHS, Sub0);
667 SDNode *Hi1 = CurDAG->getMachineNode(TargetOpcode::EXTRACT_SUBREG,
668 DL, MVT::i32, RHS, Sub1);
669
670 SDVTList VTList = CurDAG->getVTList(MVT::i32, MVT::Glue);
Matt Arsenault9fa3f932014-06-23 18:00:34 +0000671 SDValue AddLoArgs[] = { SDValue(Lo0, 0), SDValue(Lo1, 0) };
672
Matt Arsenaultb8b51532014-06-23 18:00:38 +0000673
674 unsigned Opc = IsAdd ? AMDGPU::S_ADD_I32 : AMDGPU::S_SUB_I32;
675 unsigned CarryOpc = IsAdd ? AMDGPU::S_ADDC_U32 : AMDGPU::S_SUBB_U32;
676
677 if (!isCFDepth0()) {
678 Opc = IsAdd ? AMDGPU::V_ADD_I32_e32 : AMDGPU::V_SUB_I32_e32;
679 CarryOpc = IsAdd ? AMDGPU::V_ADDC_U32_e32 : AMDGPU::V_SUBB_U32_e32;
680 }
681
682 SDNode *AddLo = CurDAG->getMachineNode( Opc, DL, VTList, AddLoArgs);
683 SDValue Carry(AddLo, 1);
684 SDNode *AddHi
685 = CurDAG->getMachineNode(CarryOpc, DL, MVT::i32,
686 SDValue(Hi0, 0), SDValue(Hi1, 0), Carry);
Matt Arsenault9fa3f932014-06-23 18:00:34 +0000687
688 SDValue Args[5] = {
689 CurDAG->getTargetConstant(AMDGPU::SReg_64RegClassID, MVT::i32),
690 SDValue(AddLo,0),
691 Sub0,
692 SDValue(AddHi,0),
693 Sub1,
694 };
695 return CurDAG->SelectNodeTo(N, AMDGPU::REG_SEQUENCE, MVT::i64, Args);
696}
697
Christian Konigd910b7d2013-02-26 17:52:16 +0000698void AMDGPUDAGToDAGISel::PostprocessISelDAG() {
Bill Wendlinga3cd3502013-06-19 21:36:55 +0000699 const AMDGPUTargetLowering& Lowering =
Matt Arsenault209a7b92014-04-18 07:40:20 +0000700 *static_cast<const AMDGPUTargetLowering*>(getTargetLowering());
Vincent Lejeuneab3baf82013-09-12 23:44:44 +0000701 bool IsModified = false;
702 do {
703 IsModified = false;
704 // Go over all selected nodes and try to fold them a bit more
705 for (SelectionDAG::allnodes_iterator I = CurDAG->allnodes_begin(),
706 E = CurDAG->allnodes_end(); I != E; ++I) {
Christian Konigd910b7d2013-02-26 17:52:16 +0000707
Vincent Lejeuneab3baf82013-09-12 23:44:44 +0000708 SDNode *Node = I;
Tom Stellard2183b702013-06-03 17:39:46 +0000709
Vincent Lejeuneab3baf82013-09-12 23:44:44 +0000710 MachineSDNode *MachineNode = dyn_cast<MachineSDNode>(I);
711 if (!MachineNode)
712 continue;
Christian Konigd910b7d2013-02-26 17:52:16 +0000713
Vincent Lejeuneab3baf82013-09-12 23:44:44 +0000714 SDNode *ResNode = Lowering.PostISelFolding(MachineNode, *CurDAG);
715 if (ResNode != Node) {
716 ReplaceUses(Node, ResNode);
717 IsModified = true;
718 }
Tom Stellard2183b702013-06-03 17:39:46 +0000719 }
Vincent Lejeuneab3baf82013-09-12 23:44:44 +0000720 CurDAG->RemoveDeadNodes();
721 } while (IsModified);
Christian Konigd910b7d2013-02-26 17:52:16 +0000722}