LLVM 24.0.0git
AMDGPUISelDAGToDAG.cpp
Go to the documentation of this file.
1//===-- AMDGPUISelDAGToDAG.cpp - A dag to dag inst selector for AMDGPU ----===//
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 AMDGPU target.
11//
12//===----------------------------------------------------------------------===//
13
14#include "AMDGPUISelDAGToDAG.h"
15#include "AMDGPU.h"
16#include "AMDGPUInstrInfo.h"
17#include "AMDGPUSubtarget.h"
19#include "R600RegisterInfo.h"
20#include "SIISelLowering.h"
27#include "llvm/IR/IntrinsicsAMDGPU.h"
30
31#ifdef EXPENSIVE_CHECKS
33#include "llvm/IR/Dominators.h"
34#endif
35
36#define DEBUG_TYPE "amdgpu-isel"
37
38using namespace llvm;
39
40//===----------------------------------------------------------------------===//
41// Instruction Selector Implementation
42//===----------------------------------------------------------------------===//
43
44namespace {
45static SDValue stripBitcast(SDValue Val) {
46 return Val.getOpcode() == ISD::BITCAST ? Val.getOperand(0) : Val;
47}
48
49// Figure out if this is really an extract of the high 16-bits of a dword.
50static bool isExtractHiElt(SDValue In, SDValue &Out) {
51 In = stripBitcast(In);
52
53 if (In.getOpcode() == ISD::EXTRACT_VECTOR_ELT) {
54 if (ConstantSDNode *Idx = dyn_cast<ConstantSDNode>(In.getOperand(1))) {
55 if (!Idx->isOne())
56 return false;
57 Out = In.getOperand(0);
58 return true;
59 }
60 }
61
62 if (In.getOpcode() != ISD::TRUNCATE)
63 return false;
64
65 SDValue Srl = In.getOperand(0);
66 if (Srl.getOpcode() == ISD::SRL) {
67 if (ConstantSDNode *ShiftAmt = dyn_cast<ConstantSDNode>(Srl.getOperand(1))) {
68 if (ShiftAmt->getZExtValue() == 16) {
69 Out = stripBitcast(Srl.getOperand(0));
70 return true;
71 }
72 }
73 }
74
75 return false;
76}
77
78static SDValue createVOP3PSrc32FromLo16(SDValue Lo, SDValue Src,
79 llvm::SelectionDAG *CurDAG,
80 const GCNSubtarget *Subtarget) {
81 if (!Subtarget->useRealTrue16Insts()) {
82 return Lo;
83 }
84
85 SDValue NewSrc;
86 SDLoc SL(Lo);
87
88 if (Lo->isDivergent()) {
89 SDValue Undef = SDValue(CurDAG->getMachineNode(TargetOpcode::IMPLICIT_DEF,
90 SL, Lo.getValueType()),
91 0);
92 const SDValue Ops[] = {
93 CurDAG->getTargetConstant(AMDGPU::VGPR_32RegClassID, SL, MVT::i32), Lo,
94 CurDAG->getTargetConstant(AMDGPU::lo16, SL, MVT::i16), Undef,
95 CurDAG->getTargetConstant(AMDGPU::hi16, SL, MVT::i16)};
96
97 NewSrc = SDValue(CurDAG->getMachineNode(TargetOpcode::REG_SEQUENCE, SL,
98 Src.getValueType(), Ops),
99 0);
100 } else {
101 // the S_MOV is needed since the Lo could still be a VGPR16.
102 // With S_MOV, isel insert a "sgpr32 = copy vgpr16" and we reply on
103 // the fixvgpr2sgprcopy pass to legalize it
104 NewSrc = SDValue(
105 CurDAG->getMachineNode(AMDGPU::S_MOV_B32, SL, Src.getValueType(), Lo),
106 0);
107 }
108
109 return NewSrc;
110}
111
112// Look through operations that obscure just looking at the low 16-bits of the
113// same register.
114static SDValue stripExtractLoElt(SDValue In) {
115 if (In.getOpcode() == ISD::EXTRACT_VECTOR_ELT) {
116 SDValue Idx = In.getOperand(1);
117 if (isNullConstant(Idx) && In.getValueSizeInBits() <= 32)
118 return In.getOperand(0);
119 }
120
121 if (In.getOpcode() == ISD::TRUNCATE) {
122 SDValue Src = In.getOperand(0);
123 if (Src.getValueType().getSizeInBits() == 32)
124 return stripBitcast(Src);
125 }
126
127 return In;
128}
129
130static SDValue emitRegSequence(llvm::SelectionDAG &CurDAG, unsigned DstRegClass,
131 EVT DstTy, ArrayRef<SDValue> Elts,
132 ArrayRef<unsigned> SubRegClass,
133 const SDLoc &DL) {
134 assert(Elts.size() == SubRegClass.size() && "array size mismatch");
135 unsigned NumElts = Elts.size();
136 SmallVector<SDValue, 17> Ops(2 * NumElts + 1);
137 Ops[0] = (CurDAG.getTargetConstant(DstRegClass, DL, MVT::i32));
138 for (unsigned i = 0; i < NumElts; ++i) {
139 Ops[2 * i + 1] = Elts[i];
140 Ops[2 * i + 2] = CurDAG.getTargetConstant(SubRegClass[i], DL, MVT::i32);
141 }
142 return SDValue(
143 CurDAG.getMachineNode(TargetOpcode::REG_SEQUENCE, DL, DstTy, Ops), 0);
144}
145
146} // end anonymous namespace
147
149 "AMDGPU DAG->DAG Pattern Instruction Selection", false,
150 false)
151INITIALIZE_PASS_DEPENDENCY(AMDGPUPerfHintAnalysisLegacy)
153#ifdef EXPENSIVE_CHECKS
156#endif
158 "AMDGPU DAG->DAG Pattern Instruction Selection", false,
159 false)
160
161/// This pass converts a legalized DAG into a AMDGPU-specific
162// DAG, ready for instruction scheduling.
164 CodeGenOptLevel OptLevel) {
165 return new AMDGPUDAGToDAGISelLegacy(TM, OptLevel);
166}
167
171
173 Subtarget = &MF.getSubtarget<GCNSubtarget>();
174 Subtarget->checkSubtargetFeatures(MF.getFunction());
175 Mode = SIModeRegisterDefaults(MF.getFunction(), *Subtarget);
177}
178
179bool AMDGPUDAGToDAGISel::fp16SrcZerosHighBits(unsigned Opc) const {
180 // XXX - only need to list legal operations.
181 switch (Opc) {
182 case ISD::POISON:
183 return true;
184 case ISD::FADD:
185 case ISD::FSUB:
186 case ISD::FMUL:
187 case ISD::FDIV:
188 case ISD::FREM:
190 case ISD::UINT_TO_FP:
191 case ISD::SINT_TO_FP:
192 case ISD::FABS:
193 // Fabs is lowered to a bit operation, but it's an and which will clear the
194 // high bits anyway.
195 case ISD::FSQRT:
196 case ISD::FSIN:
197 case ISD::FCOS:
198 case ISD::FPOWI:
199 case ISD::FPOW:
200 case ISD::FLOG:
201 case ISD::FLOG2:
202 case ISD::FLOG10:
203 case ISD::FEXP:
204 case ISD::FEXP2:
205 case ISD::FCEIL:
206 case ISD::FTRUNC:
207 case ISD::FRINT:
208 case ISD::FNEARBYINT:
209 case ISD::FROUNDEVEN:
210 case ISD::FROUND:
211 case ISD::FFLOOR:
212 case ISD::FMINNUM:
213 case ISD::FMAXNUM:
214 case ISD::FLDEXP:
215 case AMDGPUISD::FRACT:
216 case AMDGPUISD::CLAMP:
217 case AMDGPUISD::COS_HW:
218 case AMDGPUISD::SIN_HW:
219 case AMDGPUISD::FMIN3:
220 case AMDGPUISD::FMAX3:
221 case AMDGPUISD::FMED3:
222 case AMDGPUISD::FMAD_FTZ:
223 case AMDGPUISD::RCP:
224 case AMDGPUISD::RSQ:
225 case AMDGPUISD::RCP_IFLAG:
226 // On gfx10, all 16-bit instructions preserve the high bits.
227 return Subtarget->getGeneration() <= AMDGPUSubtarget::GFX9;
228 case ISD::FP_ROUND:
229 // We may select fptrunc (fma/mad) to mad_mixlo, which does not zero the
230 // high bits on gfx9.
231 // TODO: If we had the source node we could see if the source was fma/mad
233 case ISD::FMA:
234 case ISD::FMAD:
235 case AMDGPUISD::DIV_FIXUP:
237 default:
238 // fcopysign, select and others may be lowered to 32-bit bit operations
239 // which don't zero the high bits.
240 return false;
241 }
242}
243
245#ifdef EXPENSIVE_CHECKS
247 LoopInfo *LI = &getAnalysis<LoopInfoWrapperPass>().getLoopInfo();
248 for (auto &L : LI->getLoopsInPreorder()) {
249 assert(L->isLCSSAForm(DT));
250 }
251#endif
253}
254
263
265 assert(Subtarget->d16PreservesUnusedBits());
266 MVT VT = N->getValueType(0).getSimpleVT();
267 if (VT != MVT::v2i16 && VT != MVT::v2f16)
268 return false;
269
270 SDValue Lo = N->getOperand(0);
271 SDValue Hi = N->getOperand(1);
272
273 LoadSDNode *LdHi = dyn_cast<LoadSDNode>(stripBitcast(Hi));
274
275 // build_vector lo, (load ptr) -> load_d16_hi ptr, lo
276 // build_vector lo, (zextload ptr from i8) -> load_d16_hi_u8 ptr, lo
277 // build_vector lo, (sextload ptr from i8) -> load_d16_hi_i8 ptr, lo
278
279 // Need to check for possible indirect dependencies on the other half of the
280 // vector to avoid introducing a cycle.
281 if (LdHi && Hi.hasOneUse() && !LdHi->isPredecessorOf(Lo.getNode())) {
282 SDVTList VTList = CurDAG->getVTList(VT, MVT::Other);
283
284 SDValue TiedIn = CurDAG->getNode(ISD::SCALAR_TO_VECTOR, SDLoc(N), VT, Lo);
285 SDValue Ops[] = {
286 LdHi->getChain(), LdHi->getBasePtr(), TiedIn
287 };
288
289 unsigned LoadOp = AMDGPUISD::LOAD_D16_HI;
290 if (LdHi->getMemoryVT() == MVT::i8) {
291 LoadOp = LdHi->getExtensionType() == ISD::SEXTLOAD ?
292 AMDGPUISD::LOAD_D16_HI_I8 : AMDGPUISD::LOAD_D16_HI_U8;
293 } else {
294 assert(LdHi->getMemoryVT() == MVT::i16);
295 }
296
297 SDValue NewLoadHi =
298 CurDAG->getMemIntrinsicNode(LoadOp, SDLoc(LdHi), VTList,
299 Ops, LdHi->getMemoryVT(),
300 LdHi->getMemOperand());
301
302 CurDAG->ReplaceAllUsesOfValueWith(SDValue(N, 0), NewLoadHi);
303 CurDAG->ReplaceAllUsesOfValueWith(SDValue(LdHi, 1), NewLoadHi.getValue(1));
304 return true;
305 }
306
307 // build_vector (load ptr), hi -> load_d16_lo ptr, hi
308 // build_vector (zextload ptr from i8), hi -> load_d16_lo_u8 ptr, hi
309 // build_vector (sextload ptr from i8), hi -> load_d16_lo_i8 ptr, hi
310 LoadSDNode *LdLo = dyn_cast<LoadSDNode>(stripBitcast(Lo));
311 if (LdLo && Lo.hasOneUse()) {
312 SDValue TiedIn = getHi16Elt(Hi);
313 if (!TiedIn || LdLo->isPredecessorOf(TiedIn.getNode()))
314 return false;
315
316 SDVTList VTList = CurDAG->getVTList(VT, MVT::Other);
317 unsigned LoadOp = AMDGPUISD::LOAD_D16_LO;
318 if (LdLo->getMemoryVT() == MVT::i8) {
319 LoadOp = LdLo->getExtensionType() == ISD::SEXTLOAD ?
320 AMDGPUISD::LOAD_D16_LO_I8 : AMDGPUISD::LOAD_D16_LO_U8;
321 } else {
322 assert(LdLo->getMemoryVT() == MVT::i16);
323 }
324
325 TiedIn = CurDAG->getNode(ISD::BITCAST, SDLoc(N), VT, TiedIn);
326
327 SDValue Ops[] = {
328 LdLo->getChain(), LdLo->getBasePtr(), TiedIn
329 };
330
331 SDValue NewLoadLo =
332 CurDAG->getMemIntrinsicNode(LoadOp, SDLoc(LdLo), VTList,
333 Ops, LdLo->getMemoryVT(),
334 LdLo->getMemOperand());
335
336 CurDAG->ReplaceAllUsesOfValueWith(SDValue(N, 0), NewLoadLo);
337 CurDAG->ReplaceAllUsesOfValueWith(SDValue(LdLo, 1), NewLoadLo.getValue(1));
338 return true;
339 }
340
341 return false;
342}
343
345 auto *Mem = cast<MemSDNode>(N);
346 EVT VT = N->getValueType(0);
347 if (Mem->getAddressSpace() != AMDGPUAS::REGION_ADDRESS || VT.isVector() ||
348 VT.getSizeInBits() != 16)
349 return false;
350
351 SDLoc SL(N);
352 auto *Ld = dyn_cast<LoadSDNode>(N);
353 ISD::LoadExtType ExtType =
354 Ld ? Ld->getExtensionType() : cast<AtomicSDNode>(N)->getExtensionType();
355 if (ExtType == ISD::NON_EXTLOAD)
356 ExtType = ISD::EXTLOAD;
357
358 EVT MemVT = Mem->getMemoryVT().changeTypeToInteger();
359 SDValue NewLoad =
360 Ld ? CurDAG->getExtLoad(ExtType, SL, MVT::i32, Mem->getChain(),
361 Mem->getBasePtr(), MemVT, Mem->getMemOperand())
362 : CurDAG->getAtomicLoad(ExtType, SL, MemVT, MVT::i32, Mem->getChain(),
363 Mem->getBasePtr(), Mem->getMemOperand());
364
365 SDValue Trunc = CurDAG->getNode(ISD::TRUNCATE, SL, MVT::i16, NewLoad);
366 SDValue Ops[] = {CurDAG->getBitcast(VT, Trunc), NewLoad.getValue(1)};
367 CurDAG->ReplaceAllUsesWith(N, Ops);
368 return true;
369}
370
372 SelectionDAG::allnodes_iterator Position = CurDAG->allnodes_end();
373
374 bool MadeChange = false;
375 while (Position != CurDAG->allnodes_begin()) {
376 SDNode *N = &*--Position;
377 if (N->use_empty())
378 continue;
379
380 switch (N->getOpcode()) {
382 // TODO: Match load d16 from shl (extload:i16), 16
383 if (Subtarget->d16PreservesUnusedBits())
384 MadeChange |= matchLoadD16FromBuildVector(N);
385 break;
386 case ISD::LOAD:
387 case ISD::ATOMIC_LOAD:
388 if (Subtarget->useRealTrue16Insts())
389 MadeChange |= widenRegionLoad16(N);
390 break;
391 default:
392 break;
393 }
394 }
395
396 if (MadeChange) {
397 CurDAG->RemoveDeadNodes();
398 LLVM_DEBUG(dbgs() << "After PreProcess:\n";
399 CurDAG->dump(););
400 }
401}
402
403bool AMDGPUDAGToDAGISel::isInlineImmediate(const SDNode *N) const {
404 if (N->isUndef())
405 return true;
406
407 const SIInstrInfo *TII = Subtarget->getInstrInfo();
409 return TII->isInlineConstant(C->getAPIntValue());
410
412 return TII->isInlineConstant(C->getValueAPF());
413
414 return false;
415}
416
417/// Determine the register class for \p OpNo
418/// \returns The register class of the virtual register that will be used for
419/// the given operand number \OpNo or NULL if the register class cannot be
420/// determined.
421const TargetRegisterClass *AMDGPUDAGToDAGISel::getOperandRegClass(SDNode *N,
422 unsigned OpNo) const {
423 if (!N->isMachineOpcode()) {
424 if (N->getOpcode() == ISD::CopyToReg) {
425 Register Reg = cast<RegisterSDNode>(N->getOperand(1))->getReg();
426 if (Reg.isVirtual()) {
428 return MRI.getRegClass(Reg);
429 }
430
431 const SIRegisterInfo *TRI = Subtarget->getRegisterInfo();
432 return TRI->getPhysRegBaseClass(Reg);
433 }
434
435 return nullptr;
436 }
437
438 switch (N->getMachineOpcode()) {
439 default: {
440 const SIInstrInfo *TII = Subtarget->getInstrInfo();
441 const MCInstrDesc &Desc = TII->get(N->getMachineOpcode());
442 unsigned OpIdx = Desc.getNumDefs() + OpNo;
443 if (OpIdx >= Desc.getNumOperands())
444 return nullptr;
445
446 int16_t RegClass = TII->getOpRegClassID(Desc.operands()[OpIdx]);
447 if (RegClass == -1)
448 return nullptr;
449
450 return Subtarget->getRegisterInfo()->getRegClass(RegClass);
451 }
452 case AMDGPU::REG_SEQUENCE: {
453 unsigned RCID = N->getConstantOperandVal(0);
454 const TargetRegisterClass *SuperRC =
455 Subtarget->getRegisterInfo()->getRegClass(RCID);
456
457 SDValue SubRegOp = N->getOperand(OpNo + 1);
458 unsigned SubRegIdx = SubRegOp->getAsZExtVal();
459 return Subtarget->getRegisterInfo()->getSubClassWithSubReg(SuperRC,
460 SubRegIdx);
461 }
462 }
463}
464
465SDNode *AMDGPUDAGToDAGISel::glueCopyToOp(SDNode *N, SDValue NewChain,
466 SDValue Glue) const {
468 Ops.push_back(NewChain); // Replace the chain.
469 for (unsigned i = 1, e = N->getNumOperands(); i != e; ++i)
470 Ops.push_back(N->getOperand(i));
471
472 Ops.push_back(Glue);
473 return CurDAG->MorphNodeTo(N, N->getOpcode(), N->getVTList(), Ops);
474}
475
476SDNode *AMDGPUDAGToDAGISel::glueCopyToM0(SDNode *N, SDValue Val) const {
477 const SITargetLowering& Lowering =
478 *static_cast<const SITargetLowering*>(getTargetLowering());
479
480 assert(N->getOperand(0).getValueType() == MVT::Other && "Expected chain");
481
482 SDValue M0 = Lowering.copyToM0(*CurDAG, N->getOperand(0), SDLoc(N), Val);
483 return glueCopyToOp(N, M0, M0.getValue(1));
484}
485
486SDNode *AMDGPUDAGToDAGISel::glueCopyToM0LDSInit(SDNode *N) const {
487 unsigned AS = cast<MemSDNode>(N)->getAddressSpace();
488 if (AS == AMDGPUAS::LOCAL_ADDRESS) {
489 if (Subtarget->ldsRequiresM0Init())
490 return glueCopyToM0(
491 N, CurDAG->getSignedTargetConstant(-1, SDLoc(N), MVT::i32));
492 } else if (AS == AMDGPUAS::REGION_ADDRESS) {
493 MachineFunction &MF = CurDAG->getMachineFunction();
494 unsigned Value = MF.getInfo<SIMachineFunctionInfo>()->getGDSSize();
495 return
496 glueCopyToM0(N, CurDAG->getTargetConstant(Value, SDLoc(N), MVT::i32));
497 }
498 return N;
499}
500
501MachineSDNode *AMDGPUDAGToDAGISel::buildSMovImm64(SDLoc &DL, uint64_t Imm,
502 EVT VT) const {
503 SDNode *Lo = CurDAG->getMachineNode(
504 AMDGPU::S_MOV_B32, DL, MVT::i32,
505 CurDAG->getTargetConstant(Lo_32(Imm), DL, MVT::i32));
506 SDNode *Hi = CurDAG->getMachineNode(
507 AMDGPU::S_MOV_B32, DL, MVT::i32,
508 CurDAG->getTargetConstant(Hi_32(Imm), DL, MVT::i32));
509 const SDValue Ops[] = {
510 CurDAG->getTargetConstant(AMDGPU::SReg_64RegClassID, DL, MVT::i32),
511 SDValue(Lo, 0), CurDAG->getTargetConstant(AMDGPU::sub0, DL, MVT::i32),
512 SDValue(Hi, 0), CurDAG->getTargetConstant(AMDGPU::sub1, DL, MVT::i32)};
513
514 return CurDAG->getMachineNode(TargetOpcode::REG_SEQUENCE, DL, VT, Ops);
515}
516
517SDNode *AMDGPUDAGToDAGISel::packConstantV2I16(const SDNode *N,
518 SelectionDAG &DAG) const {
519 // TODO: Handle undef as zero
520
521 assert(N->getOpcode() == ISD::BUILD_VECTOR && N->getNumOperands() == 2);
522 uint32_t LHSVal, RHSVal;
523 if (getConstantValue(N->getOperand(0), LHSVal) &&
524 getConstantValue(N->getOperand(1), RHSVal)) {
525 SDLoc SL(N);
526 uint32_t K = (LHSVal & 0xffff) | (RHSVal << 16);
527 return DAG.getMachineNode(
528 isVGPRImm(N) ? AMDGPU::V_MOV_B32_e32 : AMDGPU::S_MOV_B32, SL,
529 N->getValueType(0), DAG.getTargetConstant(K, SL, MVT::i32));
530 }
531
532 return nullptr;
533}
534
535void AMDGPUDAGToDAGISel::SelectBuildVector(SDNode *N, unsigned RegClassID) {
536 EVT VT = N->getValueType(0);
537 unsigned NumVectorElts = VT.getVectorNumElements();
538 EVT EltVT = VT.getVectorElementType();
539 SDLoc DL(N);
540 SDValue RegClass = CurDAG->getTargetConstant(RegClassID, DL, MVT::i32);
541
542 if (NumVectorElts == 1) {
543 CurDAG->SelectNodeTo(N, AMDGPU::COPY_TO_REGCLASS, EltVT, N->getOperand(0),
544 RegClass);
545 return;
546 }
547
548 bool IsGCN = CurDAG->getSubtarget().getTargetTriple().isAMDGCN();
549 if (IsGCN && Subtarget->has64BitLiterals() && VT.getSizeInBits() == 64 &&
550 CurDAG->isConstantValueOfAnyType(SDValue(N, 0))) {
551 uint64_t C = 0;
552 bool AllConst = true;
553 unsigned EltSize = EltVT.getSizeInBits();
554 for (unsigned I = 0; I < NumVectorElts; ++I) {
555 SDValue Op = N->getOperand(I);
556 if (Op.isUndef()) {
557 AllConst = false;
558 break;
559 }
560 uint64_t Val;
562 Val = CF->getValueAPF().bitcastToAPInt().getZExtValue();
563 } else
564 Val = cast<ConstantSDNode>(Op)->getZExtValue();
565 C |= Val << (EltSize * I);
566 }
567 if (AllConst) {
568 SDValue CV = CurDAG->getTargetConstant(C, DL, MVT::i64);
569 MachineSDNode *Copy =
570 CurDAG->getMachineNode(AMDGPU::S_MOV_B64_IMM_PSEUDO, DL, VT, CV);
571 CurDAG->SelectNodeTo(N, AMDGPU::COPY_TO_REGCLASS, VT, SDValue(Copy, 0),
572 RegClass);
573 return;
574 }
575 }
576
577 assert(NumVectorElts <= 32 && "Vectors with more than 32 elements not "
578 "supported yet");
579 // 32 = Max Num Vector Elements
580 // 2 = 2 REG_SEQUENCE operands per element (value, subreg index)
581 // 1 = Vector Register Class
582 SmallVector<SDValue, 32 * 2 + 1> RegSeqArgs(NumVectorElts * 2 + 1);
583
584 RegSeqArgs[0] = CurDAG->getTargetConstant(RegClassID, DL, MVT::i32);
585 bool IsRegSeq = true;
586 unsigned NOps = N->getNumOperands();
587 unsigned EltSizeInRegs = EltVT.getSizeInBits() / 32;
588 assert(IsGCN || EltSizeInRegs == 1);
589 for (unsigned i = 0; i < NOps; i++) {
590 // XXX: Why is this here?
591 if (isa<RegisterSDNode>(N->getOperand(i))) {
592 IsRegSeq = false;
593 break;
594 }
595 unsigned Sub = IsGCN ? SIRegisterInfo::getSubRegFromChannel(
596 i * EltSizeInRegs, EltSizeInRegs)
598 RegSeqArgs[1 + (2 * i)] = N->getOperand(i);
599 RegSeqArgs[1 + (2 * i) + 1] = CurDAG->getTargetConstant(Sub, DL, MVT::i32);
600 }
601 if (NOps != NumVectorElts) {
602 // Fill in the missing undef elements if this was a scalar_to_vector.
603 assert(N->getOpcode() == ISD::SCALAR_TO_VECTOR && NOps < NumVectorElts);
604 MachineSDNode *ImpDef = CurDAG->getMachineNode(TargetOpcode::IMPLICIT_DEF,
605 DL, EltVT);
606 for (unsigned i = NOps; i < NumVectorElts; ++i) {
607 unsigned Sub = IsGCN ? SIRegisterInfo::getSubRegFromChannel(
608 i * EltSizeInRegs, EltSizeInRegs)
610 RegSeqArgs[1 + (2 * i)] = SDValue(ImpDef, 0);
611 RegSeqArgs[1 + (2 * i) + 1] =
612 CurDAG->getTargetConstant(Sub, DL, MVT::i32);
613 }
614 }
615
616 if (!IsRegSeq)
617 SelectCode(N);
618 CurDAG->SelectNodeTo(N, AMDGPU::REG_SEQUENCE, N->getVTList(), RegSeqArgs);
619}
620
622 EVT VT = N->getValueType(0);
623 EVT EltVT = VT.getVectorElementType();
624
625 // TODO: Handle 16-bit element vectors with even aligned masks.
626 if (!Subtarget->hasPkMovB32() || !EltVT.bitsEq(MVT::i32) ||
627 VT.getVectorNumElements() != 2) {
628 SelectCode(N);
629 return;
630 }
631
632 auto *SVN = cast<ShuffleVectorSDNode>(N);
633
634 SDValue Src0 = SVN->getOperand(0);
635 SDValue Src1 = SVN->getOperand(1);
636 ArrayRef<int> Mask = SVN->getMask();
637 SDLoc DL(N);
638
639 assert(Src0.getValueType().getVectorNumElements() == 2 && Mask.size() == 2 &&
640 Mask[0] < 4 && Mask[1] < 4);
641
642 SDValue VSrc0 = Mask[0] < 2 ? Src0 : Src1;
643 SDValue VSrc1 = Mask[1] < 2 ? Src0 : Src1;
644 unsigned Src0SubReg = Mask[0] & 1 ? AMDGPU::sub1 : AMDGPU::sub0;
645 unsigned Src1SubReg = Mask[1] & 1 ? AMDGPU::sub1 : AMDGPU::sub0;
646
647 if (Mask[0] < 0) {
648 Src0SubReg = Src1SubReg;
649 MachineSDNode *ImpDef =
650 CurDAG->getMachineNode(TargetOpcode::IMPLICIT_DEF, DL, VT);
651 VSrc0 = SDValue(ImpDef, 0);
652 }
653
654 if (Mask[1] < 0) {
655 Src1SubReg = Src0SubReg;
656 MachineSDNode *ImpDef =
657 CurDAG->getMachineNode(TargetOpcode::IMPLICIT_DEF, DL, VT);
658 VSrc1 = SDValue(ImpDef, 0);
659 }
660
661 // SGPR case needs to lower to copies.
662 //
663 // Also use subregister extract when we can directly blend the registers with
664 // a simple subregister copy.
665 //
666 // TODO: Maybe we should fold this out earlier
667 if (N->isDivergent() && Src0SubReg == AMDGPU::sub1 &&
668 Src1SubReg == AMDGPU::sub0) {
669 // The low element of the result always comes from src0.
670 // The high element of the result always comes from src1.
671 // op_sel selects the high half of src0.
672 // op_sel_hi selects the high half of src1.
673
674 unsigned Src0OpSel =
675 Src0SubReg == AMDGPU::sub1 ? SISrcMods::OP_SEL_0 : SISrcMods::NONE;
676 unsigned Src1OpSel =
677 Src1SubReg == AMDGPU::sub1 ? SISrcMods::OP_SEL_0 : SISrcMods::NONE;
678
679 // Enable op_sel_hi to avoid printing it. This should have no effect on the
680 // result.
681 Src0OpSel |= SISrcMods::OP_SEL_1;
682 Src1OpSel |= SISrcMods::OP_SEL_1;
683
684 SDValue Src0OpSelVal = CurDAG->getTargetConstant(Src0OpSel, DL, MVT::i32);
685 SDValue Src1OpSelVal = CurDAG->getTargetConstant(Src1OpSel, DL, MVT::i32);
686 SDValue ZeroMods = CurDAG->getTargetConstant(0, DL, MVT::i32);
687
688 CurDAG->SelectNodeTo(N, AMDGPU::V_PK_MOV_B32, N->getVTList(),
689 {Src0OpSelVal, VSrc0, Src1OpSelVal, VSrc1,
690 ZeroMods, // clamp
691 ZeroMods, // op_sel
692 ZeroMods, // op_sel_hi
693 ZeroMods, // neg_lo
694 ZeroMods}); // neg_hi
695 return;
696 }
697
698 SDValue ResultElt0 =
699 CurDAG->getTargetExtractSubreg(Src0SubReg, DL, EltVT, VSrc0);
700 SDValue ResultElt1 =
701 CurDAG->getTargetExtractSubreg(Src1SubReg, DL, EltVT, VSrc1);
702
703 const SDValue Ops[] = {
704 CurDAG->getTargetConstant(AMDGPU::SReg_64RegClassID, DL, MVT::i32),
705 ResultElt0, CurDAG->getTargetConstant(AMDGPU::sub0, DL, MVT::i32),
706 ResultElt1, CurDAG->getTargetConstant(AMDGPU::sub1, DL, MVT::i32)};
707 CurDAG->SelectNodeTo(N, TargetOpcode::REG_SEQUENCE, VT, Ops);
708}
709
711 unsigned int Opc = N->getOpcode();
712 if (N->isMachineOpcode()) {
713 N->setNodeId(-1);
714 return; // Already selected.
715 }
716
717 // isa<MemSDNode> almost works but is slightly too permissive for some DS
718 // intrinsics.
719 if (Opc == ISD::LOAD || Opc == ISD::STORE || isa<AtomicSDNode>(N)) {
720 N = glueCopyToM0LDSInit(N);
721 SelectCode(N);
722 return;
723 }
724
725 switch (Opc) {
726 default:
727 break;
728 case ISD::UADDO_CARRY:
729 case ISD::USUBO_CARRY:
730 if (N->getValueType(0) == MVT::i64) {
731 SelectAddcSubbI64(N);
732 return;
733 }
734
735 if (N->getValueType(0) != MVT::i32)
736 break;
737
738 SelectAddcSubb(N);
739 return;
740 case ISD::UADDO:
741 case ISD::USUBO: {
742 if (N->getValueType(0) == MVT::i64) {
743 SelectAddcSubbI64(N);
744 return;
745 }
746
747 SelectUADDO_USUBO(N);
748 return;
749 }
750 case AMDGPUISD::FMUL_W_CHAIN: {
751 SelectFMUL_W_CHAIN(N);
752 return;
753 }
754 case AMDGPUISD::FMA_W_CHAIN: {
755 SelectFMA_W_CHAIN(N);
756 return;
757 }
758
760 case ISD::BUILD_VECTOR: {
761 EVT VT = N->getValueType(0);
762 unsigned NumVectorElts = VT.getVectorNumElements();
763 if (VT.getScalarSizeInBits() == 16) {
764 if (Opc == ISD::BUILD_VECTOR && NumVectorElts == 2) {
765 if (SDNode *Packed = packConstantV2I16(N, *CurDAG)) {
766 ReplaceNode(N, Packed);
767 return;
768 }
769 }
770
771 break;
772 }
773
774 const SIRegisterInfo *TRI = Subtarget->getRegisterInfo();
775 EVT EltTy = VT.getVectorElementType();
776 assert(EltTy.bitsEq(MVT::i32) || EltTy.bitsEq(MVT::i64));
777 unsigned VecInBits = NumVectorElts * EltTy.getScalarSizeInBits();
778 const TargetRegisterClass *RegClass =
779 N->isDivergent() ? TRI->getDefaultVectorSuperClassForBitWidth(VecInBits)
781
782 SelectBuildVector(N, RegClass->getID());
783 return;
784 }
787 return;
788 case ISD::BUILD_PAIR: {
789 SDValue RC, SubReg0, SubReg1;
790 SDLoc DL(N);
791 if (N->getValueType(0) == MVT::i128) {
792 RC = CurDAG->getTargetConstant(AMDGPU::SGPR_128RegClassID, DL, MVT::i32);
793 SubReg0 = CurDAG->getTargetConstant(AMDGPU::sub0_sub1, DL, MVT::i32);
794 SubReg1 = CurDAG->getTargetConstant(AMDGPU::sub2_sub3, DL, MVT::i32);
795 } else if (N->getValueType(0) == MVT::i64) {
796 RC = CurDAG->getTargetConstant(AMDGPU::SReg_64RegClassID, DL, MVT::i32);
797 SubReg0 = CurDAG->getTargetConstant(AMDGPU::sub0, DL, MVT::i32);
798 SubReg1 = CurDAG->getTargetConstant(AMDGPU::sub1, DL, MVT::i32);
799 } else {
800 llvm_unreachable("Unhandled value type for BUILD_PAIR");
801 }
802 const SDValue Ops[] = { RC, N->getOperand(0), SubReg0,
803 N->getOperand(1), SubReg1 };
804 ReplaceNode(N, CurDAG->getMachineNode(TargetOpcode::REG_SEQUENCE, DL,
805 N->getValueType(0), Ops));
806 return;
807 }
808
809 case ISD::Constant:
810 case ISD::ConstantFP: {
811 if (N->getValueType(0).getSizeInBits() != 64 || isInlineImmediate(N) ||
812 Subtarget->has64BitLiterals())
813 break;
814
815 uint64_t Imm;
817 Imm = FP->getValueAPF().bitcastToAPInt().getZExtValue();
819 break;
820 } else {
822 Imm = C->getZExtValue();
824 break;
825 }
826
827 SDLoc DL(N);
828 ReplaceNode(N, buildSMovImm64(DL, Imm, N->getValueType(0)));
829 return;
830 }
831 case AMDGPUISD::BFE_I32:
832 case AMDGPUISD::BFE_U32: {
833 // There is a scalar version available, but unlike the vector version which
834 // has a separate operand for the offset and width, the scalar version packs
835 // the width and offset into a single operand. Try to move to the scalar
836 // version if the offsets are constant, so that we can try to keep extended
837 // loads of kernel arguments in SGPRs.
838
839 // TODO: Technically we could try to pattern match scalar bitshifts of
840 // dynamic values, but it's probably not useful.
842 if (!Offset)
843 break;
844
845 ConstantSDNode *Width = dyn_cast<ConstantSDNode>(N->getOperand(2));
846 if (!Width)
847 break;
848
849 bool Signed = Opc == AMDGPUISD::BFE_I32;
850
851 uint32_t OffsetVal = Offset->getZExtValue();
852 uint32_t WidthVal = Width->getZExtValue();
853
854 ReplaceNode(N, getBFE32(Signed, SDLoc(N), N->getOperand(0), OffsetVal,
855 WidthVal));
856 return;
857 }
858 case AMDGPUISD::DIV_SCALE: {
859 SelectDIV_SCALE(N);
860 return;
861 }
864 SelectMAD_64_32(N);
865 return;
866 }
867 case ISD::SMUL_LOHI:
868 case ISD::UMUL_LOHI:
869 return SelectMUL_LOHI(N);
870 case ISD::CopyToReg: {
872 *static_cast<const SITargetLowering*>(getTargetLowering());
873 N = Lowering.legalizeTargetIndependentNode(N, *CurDAG);
874 break;
875 }
876 case ISD::AND:
877 case ISD::SRL:
878 case ISD::SRA:
880 if (N->getValueType(0) != MVT::i32)
881 break;
882
883 SelectS_BFE(N);
884 return;
885 case ISD::BRCOND:
886 SelectBRCOND(N);
887 return;
888 case ISD::FP_EXTEND:
889 SelectFP_EXTEND(N);
890 return;
891 case AMDGPUISD::CVT_PKRTZ_F16_F32:
892 case AMDGPUISD::CVT_PKNORM_I16_F32:
893 case AMDGPUISD::CVT_PKNORM_U16_F32:
894 case AMDGPUISD::CVT_PK_U16_U32:
895 case AMDGPUISD::CVT_PK_I16_I32: {
896 // Hack around using a legal type if f16 is illegal.
897 if (N->getValueType(0) == MVT::i32) {
898 MVT NewVT = Opc == AMDGPUISD::CVT_PKRTZ_F16_F32 ? MVT::v2f16 : MVT::v2i16;
899 N = CurDAG->MorphNodeTo(N, N->getOpcode(), CurDAG->getVTList(NewVT),
900 { N->getOperand(0), N->getOperand(1) });
901 SelectCode(N);
902 return;
903 }
904
905 break;
906 }
908 SelectINTRINSIC_W_CHAIN(N);
909 return;
910 }
912 SelectINTRINSIC_WO_CHAIN(N);
913 return;
914 }
915 case ISD::INTRINSIC_VOID: {
916 SelectINTRINSIC_VOID(N);
917 return;
918 }
920 SelectWAVE_ADDRESS(N);
921 return;
922 }
923 case ISD::STACKRESTORE: {
924 SelectSTACKRESTORE(N);
925 return;
926 }
927 case ISD::WRITE_REGISTER: {
928 SelectWRITE_REGISTER(N);
929 return;
930 }
931 }
932
933 SelectCode(N);
934}
935
937 if (!Subtarget->hasSDWA())
938 return false;
939
940 if (N->getOpcode() == ISD::SIGN_EXTEND_INREG) {
941 EVT VT = cast<VTSDNode>(N->getOperand(1))->getVT();
942 return VT.getScalarSizeInBits() == 8 || VT.getScalarSizeInBits() == 16;
943 }
944
945 if (N->getOpcode() == ISD::AND)
946 if (auto *RHS = dyn_cast<ConstantSDNode>(N->getOperand(1)))
947 return RHS->getZExtValue() == 0xFF || RHS->getZExtValue() == 0xFFFF;
948
949 if (N->getOpcode() == ISD::SRA || N->getOpcode() == ISD::SRL)
950 if (auto *RHS = dyn_cast<ConstantSDNode>(N->getOperand(1)))
951 return (RHS->getZExtValue() % 8) == 0;
952
953 return false;
954}
955
956bool AMDGPUDAGToDAGISel::isUniformBr(const SDNode *N) const {
957 const BasicBlock *BB = FuncInfo->MBB->getBasicBlock();
958 const Instruction *Term = BB->getTerminator();
959 return Term->getMetadata("amdgpu.uniform") ||
960 Term->getMetadata("structurizecfg.uniform");
961}
962
963bool AMDGPUDAGToDAGISel::isUnneededShiftMask(const SDNode *N,
964 unsigned ShAmtBits) const {
965 assert(N->getOpcode() == ISD::AND);
966
967 const APInt &RHS = N->getConstantOperandAPInt(1);
968 if (RHS.countr_one() >= ShAmtBits)
969 return true;
970
971 const APInt &LHSKnownZeros = CurDAG->computeKnownBits(N->getOperand(0)).Zero;
972 return (LHSKnownZeros | RHS).countr_one() >= ShAmtBits;
973}
974
976 SDValue &N0, SDValue &N1) {
977 if (Addr.getValueType() == MVT::i64 && Addr.getOpcode() == ISD::BITCAST &&
979 // As we split 64-bit `or` earlier, it's complicated pattern to match, i.e.
980 // (i64 (bitcast (v2i32 (build_vector
981 // (or (extract_vector_elt V, 0), OFFSET),
982 // (extract_vector_elt V, 1)))))
983 SDValue Lo = Addr.getOperand(0).getOperand(0);
984 if (Lo.getOpcode() == ISD::OR && DAG.isBaseWithConstantOffset(Lo)) {
985 SDValue BaseLo = Lo.getOperand(0);
986 SDValue BaseHi = Addr.getOperand(0).getOperand(1);
987 // Check that split base (Lo and Hi) are extracted from the same one.
988 if (BaseLo.getOpcode() == ISD::EXTRACT_VECTOR_ELT &&
990 BaseLo.getOperand(0) == BaseHi.getOperand(0) &&
991 // Lo is statically extracted from index 0.
992 isa<ConstantSDNode>(BaseLo.getOperand(1)) &&
993 BaseLo.getConstantOperandVal(1) == 0 &&
994 // Hi is statically extracted from index 0.
995 isa<ConstantSDNode>(BaseHi.getOperand(1)) &&
996 BaseHi.getConstantOperandVal(1) == 1) {
997 N0 = BaseLo.getOperand(0).getOperand(0);
998 N1 = Lo.getOperand(1);
999 return true;
1000 }
1001 }
1002 }
1003 return false;
1004}
1005
1006bool AMDGPUDAGToDAGISel::isBaseWithConstantOffset64(SDValue Addr, SDValue &LHS,
1007 SDValue &RHS) const {
1008 if (CurDAG->isBaseWithConstantOffset(Addr)) {
1009 LHS = Addr.getOperand(0);
1010 RHS = Addr.getOperand(1);
1011 return true;
1012 }
1013
1016 return true;
1017 }
1018
1019 return false;
1020}
1021
1023 return "AMDGPU DAG->DAG Pattern Instruction Selection";
1024}
1025
1029
1034 .getManager();
1035 auto &F = MF.getFunction();
1036 // UniformityInfoAnalysis is optional in generic dag isel,
1037 // AMDGPUISelDAGToDAGPass requires it, calculate it explicitly.
1038 FAM.getResult<UniformityInfoAnalysis>(F);
1039#ifdef EXPENSIVE_CHECKS
1040 DominatorTree &DT = FAM.getResult<DominatorTreeAnalysis>(F);
1041 LoopInfo &LI = FAM.getResult<LoopAnalysis>(F);
1042 for (auto &L : LI.getLoopsInPreorder())
1043 assert(L->isLCSSAForm(DT) && "Loop is not in LCSSA form!");
1044#endif
1045 return SelectionDAGISelPass::run(MF, MFAM);
1046}
1047
1048//===----------------------------------------------------------------------===//
1049// Complex Patterns
1050//===----------------------------------------------------------------------===//
1051
1052bool AMDGPUDAGToDAGISel::SelectADDRVTX_READ(SDValue Addr, SDValue &Base,
1053 SDValue &Offset) {
1054 return false;
1055}
1056
1057bool AMDGPUDAGToDAGISel::SelectADDRIndirect(SDValue Addr, SDValue &Base,
1058 SDValue &Offset) {
1060 SDLoc DL(Addr);
1061
1062 if ((C = dyn_cast<ConstantSDNode>(Addr))) {
1063 Base = CurDAG->getRegister(R600::INDIRECT_BASE_ADDR, MVT::i32);
1064 Offset = CurDAG->getTargetConstant(C->getZExtValue(), DL, MVT::i32);
1065 } else if ((Addr.getOpcode() == AMDGPUISD::DWORDADDR) &&
1066 (C = dyn_cast<ConstantSDNode>(Addr.getOperand(0)))) {
1067 Base = CurDAG->getRegister(R600::INDIRECT_BASE_ADDR, MVT::i32);
1068 Offset = CurDAG->getTargetConstant(C->getZExtValue(), DL, MVT::i32);
1069 } else if ((Addr.getOpcode() == ISD::ADD || Addr.getOpcode() == ISD::OR) &&
1070 (C = dyn_cast<ConstantSDNode>(Addr.getOperand(1)))) {
1071 Base = Addr.getOperand(0);
1072 Offset = CurDAG->getTargetConstant(C->getZExtValue(), DL, MVT::i32);
1073 } else {
1074 Base = Addr;
1075 Offset = CurDAG->getTargetConstant(0, DL, MVT::i32);
1076 }
1077
1078 return true;
1079}
1080
1081SDValue AMDGPUDAGToDAGISel::getMaterializedScalarImm32(int64_t Val,
1082 const SDLoc &DL) const {
1083 SDNode *Mov = CurDAG->getMachineNode(
1084 AMDGPU::S_MOV_B32, DL, MVT::i32,
1085 CurDAG->getTargetConstant(Val, DL, MVT::i32));
1086 return SDValue(Mov, 0);
1087}
1088
1089void AMDGPUDAGToDAGISel::SelectAddcSubb(SDNode *N) {
1090 SDValue LHS = N->getOperand(0);
1091 SDValue RHS = N->getOperand(1);
1092 SDValue CI = N->getOperand(2);
1093
1094 if (N->isDivergent()) {
1095 unsigned Opc = N->getOpcode() == ISD::UADDO_CARRY ? AMDGPU::V_ADDC_U32_e64
1096 : AMDGPU::V_SUBB_U32_e64;
1097 CurDAG->SelectNodeTo(
1098 N, Opc, N->getVTList(),
1099 {LHS, RHS, CI,
1100 CurDAG->getTargetConstant(0, {}, MVT::i1) /*clamp bit*/});
1101 } else {
1102 unsigned Opc = N->getOpcode() == ISD::UADDO_CARRY ? AMDGPU::S_ADD_CO_PSEUDO
1103 : AMDGPU::S_SUB_CO_PSEUDO;
1104 CurDAG->SelectNodeTo(N, Opc, N->getVTList(), {LHS, RHS, CI});
1105 }
1106}
1107
1108void AMDGPUDAGToDAGISel::SelectAddcSubbI64(SDNode *N) {
1109 SDLoc DL(N);
1110 SDValue LHS = N->getOperand(0);
1111 SDValue RHS = N->getOperand(1);
1112
1113 unsigned Opcode = N->getOpcode();
1114 bool ConsumeCarry = Opcode == ISD::UADDO_CARRY || Opcode == ISD::USUBO_CARRY;
1115 bool IsAdd = Opcode == ISD::UADDO || Opcode == ISD::UADDO_CARRY;
1116
1117 SDValue Sub0 = CurDAG->getTargetConstant(AMDGPU::sub0, DL, MVT::i32);
1118 SDValue Sub1 = CurDAG->getTargetConstant(AMDGPU::sub1, DL, MVT::i32);
1119
1120 SDNode *Lo0 = CurDAG->getMachineNode(TargetOpcode::EXTRACT_SUBREG, DL,
1121 MVT::i32, LHS, Sub0);
1122 SDNode *Hi0 = CurDAG->getMachineNode(TargetOpcode::EXTRACT_SUBREG, DL,
1123 MVT::i32, LHS, Sub1);
1124
1125 SDNode *Lo1 = CurDAG->getMachineNode(TargetOpcode::EXTRACT_SUBREG, DL,
1126 MVT::i32, RHS, Sub0);
1127 SDNode *Hi1 = CurDAG->getMachineNode(TargetOpcode::EXTRACT_SUBREG, DL,
1128 MVT::i32, RHS, Sub1);
1129
1130 SDVTList VTList = CurDAG->getVTList(MVT::i32, N->getValueType(1));
1131
1132 static const unsigned NoCarryOpcMap[2][2] = {
1133 {AMDGPU::S_USUBO_PSEUDO, AMDGPU::S_UADDO_PSEUDO},
1134 {AMDGPU::V_SUB_CO_U32_e64, AMDGPU::V_ADD_CO_U32_e64}};
1135 static const unsigned CarryOpcMap[2][2] = {
1136 {AMDGPU::S_SUB_CO_PSEUDO, AMDGPU::S_ADD_CO_PSEUDO},
1137 {AMDGPU::V_SUBB_U32_e64, AMDGPU::V_ADDC_U32_e64}};
1138
1139 bool IsVALU = N->isDivergent();
1140
1141 unsigned NoCarryOpc = NoCarryOpcMap[IsVALU][IsAdd];
1142 unsigned CarryOpc = CarryOpcMap[IsVALU][IsAdd];
1143 SDValue Clamp = CurDAG->getTargetConstant(0, DL, MVT::i1);
1144
1145 SDNode *AddLo;
1146 if (!ConsumeCarry) {
1147 if (IsVALU) {
1148 SDValue Args[] = {SDValue(Lo0, 0), SDValue(Lo1, 0), Clamp};
1149 AddLo = CurDAG->getMachineNode(NoCarryOpc, DL, VTList, Args);
1150 } else {
1151 SDValue Args[] = {SDValue(Lo0, 0), SDValue(Lo1, 0)};
1152 AddLo = CurDAG->getMachineNode(NoCarryOpc, DL, VTList, Args);
1153 }
1154 } else {
1155 if (IsVALU) {
1156 SDValue Args[] = {SDValue(Lo0, 0), SDValue(Lo1, 0), N->getOperand(2),
1157 Clamp};
1158 AddLo = CurDAG->getMachineNode(CarryOpc, DL, VTList, Args);
1159 } else {
1160 SDValue Args[] = {SDValue(Lo0, 0), SDValue(Lo1, 0), N->getOperand(2)};
1161 AddLo = CurDAG->getMachineNode(CarryOpc, DL, VTList, Args);
1162 }
1163 }
1164
1165 SDNode *AddHi;
1166 if (IsVALU) {
1167 SDValue Args[] = {SDValue(Hi0, 0), SDValue(Hi1, 0), SDValue(AddLo, 1),
1168 Clamp};
1169 AddHi = CurDAG->getMachineNode(CarryOpc, DL, VTList, Args);
1170 } else {
1171 SDValue Args[] = {SDValue(Hi0, 0), SDValue(Hi1, 0), SDValue(AddLo, 1)};
1172 AddHi = CurDAG->getMachineNode(CarryOpc, DL, VTList, Args);
1173 }
1174
1175 unsigned RC = IsVALU ? AMDGPU::VReg_64RegClassID : AMDGPU::SReg_64RegClassID;
1176 SDValue RegSequenceArgs[] = {CurDAG->getTargetConstant(RC, DL, MVT::i32),
1177 SDValue(AddLo, 0), Sub0, SDValue(AddHi, 0),
1178 Sub1};
1179 SDNode *RegSequence = CurDAG->getMachineNode(AMDGPU::REG_SEQUENCE, DL,
1180 MVT::i64, RegSequenceArgs);
1181
1182 ReplaceUses(SDValue(N, 1), SDValue(AddHi, 1));
1183 ReplaceNode(N, RegSequence);
1184}
1185
1186void AMDGPUDAGToDAGISel::SelectUADDO_USUBO(SDNode *N) {
1187 // The name of the opcodes are misleading. v_add_i32/v_sub_i32 have unsigned
1188 // carry out despite the _i32 name. These were renamed in VI to _U32.
1189 // FIXME: We should probably rename the opcodes here.
1190 bool IsAdd = N->getOpcode() == ISD::UADDO;
1191 bool IsVALU = N->isDivergent();
1192
1193 for (SDNode::user_iterator UI = N->user_begin(), E = N->user_end(); UI != E;
1194 ++UI)
1195 if (UI.getUse().getResNo() == 1) {
1196 if (UI->isMachineOpcode()) {
1197 if (UI->getMachineOpcode() !=
1198 (IsAdd ? AMDGPU::S_ADD_CO_PSEUDO : AMDGPU::S_SUB_CO_PSEUDO)) {
1199 IsVALU = true;
1200 break;
1201 }
1202 } else {
1203 if (UI->getOpcode() != (IsAdd ? ISD::UADDO_CARRY : ISD::USUBO_CARRY)) {
1204 IsVALU = true;
1205 break;
1206 }
1207 }
1208 }
1209
1210 if (IsVALU) {
1211 unsigned Opc = IsAdd ? AMDGPU::V_ADD_CO_U32_e64 : AMDGPU::V_SUB_CO_U32_e64;
1212
1213 CurDAG->SelectNodeTo(
1214 N, Opc, N->getVTList(),
1215 {N->getOperand(0), N->getOperand(1),
1216 CurDAG->getTargetConstant(0, {}, MVT::i1) /*clamp bit*/});
1217 } else {
1218 unsigned Opc = IsAdd ? AMDGPU::S_UADDO_PSEUDO : AMDGPU::S_USUBO_PSEUDO;
1219
1220 CurDAG->SelectNodeTo(N, Opc, N->getVTList(),
1221 {N->getOperand(0), N->getOperand(1)});
1222 }
1223}
1224
1225void AMDGPUDAGToDAGISel::SelectFMA_W_CHAIN(SDNode *N) {
1226 // src0_modifiers, src0, src1_modifiers, src1, src2_modifiers, src2, clamp, omod
1227 SDValue Ops[10];
1228
1229 SelectVOP3Mods0(N->getOperand(1), Ops[1], Ops[0], Ops[6], Ops[7]);
1230 SelectVOP3Mods(N->getOperand(2), Ops[3], Ops[2]);
1231 SelectVOP3Mods(N->getOperand(3), Ops[5], Ops[4]);
1232 Ops[8] = N->getOperand(0);
1233 Ops[9] = N->getOperand(4);
1234
1235 // If there are no source modifiers, prefer fmac over fma because it can use
1236 // the smaller VOP2 encoding.
1237 bool UseFMAC = Subtarget->hasDLInsts() &&
1238 cast<ConstantSDNode>(Ops[0])->isZero() &&
1239 cast<ConstantSDNode>(Ops[2])->isZero() &&
1240 cast<ConstantSDNode>(Ops[4])->isZero();
1241 unsigned Opcode = UseFMAC ? AMDGPU::V_FMAC_F32_e64 : AMDGPU::V_FMA_F32_e64;
1242 CurDAG->SelectNodeTo(N, Opcode, N->getVTList(), Ops);
1243}
1244
1245void AMDGPUDAGToDAGISel::SelectFMUL_W_CHAIN(SDNode *N) {
1246 // src0_modifiers, src0, src1_modifiers, src1, clamp, omod
1247 SDValue Ops[8];
1248
1249 SelectVOP3Mods0(N->getOperand(1), Ops[1], Ops[0], Ops[4], Ops[5]);
1250 SelectVOP3Mods(N->getOperand(2), Ops[3], Ops[2]);
1251 Ops[6] = N->getOperand(0);
1252 Ops[7] = N->getOperand(3);
1253
1254 CurDAG->SelectNodeTo(N, AMDGPU::V_MUL_F32_e64, N->getVTList(), Ops);
1255}
1256
1257// We need to handle this here because tablegen doesn't support matching
1258// instructions with multiple outputs.
1259void AMDGPUDAGToDAGISel::SelectDIV_SCALE(SDNode *N) {
1260 EVT VT = N->getValueType(0);
1261
1262 assert(VT == MVT::f32 || VT == MVT::f64);
1263
1264 unsigned Opc
1265 = (VT == MVT::f64) ? AMDGPU::V_DIV_SCALE_F64_e64 : AMDGPU::V_DIV_SCALE_F32_e64;
1266
1267 // src0_modifiers, src0, src1_modifiers, src1, src2_modifiers, src2, clamp,
1268 // omod
1269 SDValue Ops[8];
1270 SelectVOP3BMods0(N->getOperand(0), Ops[1], Ops[0], Ops[6], Ops[7]);
1271 SelectVOP3BMods(N->getOperand(1), Ops[3], Ops[2]);
1272 SelectVOP3BMods(N->getOperand(2), Ops[5], Ops[4]);
1273 CurDAG->SelectNodeTo(N, Opc, N->getVTList(), Ops);
1274}
1275
1276// We need to handle this here because tablegen doesn't support matching
1277// instructions with multiple outputs.
1278void AMDGPUDAGToDAGISel::SelectMAD_64_32(SDNode *N) {
1279 SDLoc SL(N);
1280 bool Signed = N->getOpcode() == AMDGPUISD::MAD_I64_I32;
1281 unsigned Opc;
1282 bool UseNoCarry = Subtarget->hasMadNC64_32Insts() && !N->hasAnyUseOfValue(1);
1283 if (Subtarget->hasMADIntraFwdBug())
1284 Opc = Signed ? AMDGPU::V_MAD_I64_I32_gfx11_e64
1285 : AMDGPU::V_MAD_U64_U32_gfx11_e64;
1286 else if (UseNoCarry)
1287 Opc = Signed ? AMDGPU::V_MAD_NC_I64_I32_e64 : AMDGPU::V_MAD_NC_U64_U32_e64;
1288 else
1289 Opc = Signed ? AMDGPU::V_MAD_I64_I32_e64 : AMDGPU::V_MAD_U64_U32_e64;
1290
1291 SDValue Clamp = CurDAG->getTargetConstant(0, SL, MVT::i1);
1292 SDValue Ops[] = { N->getOperand(0), N->getOperand(1), N->getOperand(2),
1293 Clamp };
1294
1295 if (UseNoCarry) {
1296 MachineSDNode *Mad = CurDAG->getMachineNode(Opc, SL, MVT::i64, Ops);
1297 ReplaceUses(SDValue(N, 0), SDValue(Mad, 0));
1298 CurDAG->RemoveDeadNode(N);
1299 return;
1300 }
1301
1302 CurDAG->SelectNodeTo(N, Opc, N->getVTList(), Ops);
1303}
1304
1305// We need to handle this here because tablegen doesn't support matching
1306// instructions with multiple outputs.
1307void AMDGPUDAGToDAGISel::SelectMUL_LOHI(SDNode *N) {
1308 SDLoc SL(N);
1309 bool Signed = N->getOpcode() == ISD::SMUL_LOHI;
1310 SDVTList VTList;
1311 unsigned Opc;
1312 if (Subtarget->hasMadNC64_32Insts()) {
1313 VTList = CurDAG->getVTList(MVT::i64);
1314 Opc = Signed ? AMDGPU::V_MAD_NC_I64_I32_e64 : AMDGPU::V_MAD_NC_U64_U32_e64;
1315 } else {
1316 VTList = CurDAG->getVTList(MVT::i64, MVT::i1);
1317 if (Subtarget->hasMADIntraFwdBug()) {
1318 Opc = Signed ? AMDGPU::V_MAD_I64_I32_gfx11_e64
1319 : AMDGPU::V_MAD_U64_U32_gfx11_e64;
1320 } else {
1321 Opc = Signed ? AMDGPU::V_MAD_I64_I32_e64 : AMDGPU::V_MAD_U64_U32_e64;
1322 }
1323 }
1324
1325 SDValue Zero = CurDAG->getTargetConstant(0, SL, MVT::i64);
1326 SDValue Clamp = CurDAG->getTargetConstant(0, SL, MVT::i1);
1327 SDValue Ops[] = {N->getOperand(0), N->getOperand(1), Zero, Clamp};
1328 SDNode *Mad = CurDAG->getMachineNode(Opc, SL, VTList, Ops);
1329 if (!SDValue(N, 0).use_empty()) {
1330 SDValue Sub0 = CurDAG->getTargetConstant(AMDGPU::sub0, SL, MVT::i32);
1331 SDNode *Lo = CurDAG->getMachineNode(TargetOpcode::EXTRACT_SUBREG, SL,
1332 MVT::i32, SDValue(Mad, 0), Sub0);
1333 ReplaceUses(SDValue(N, 0), SDValue(Lo, 0));
1334 }
1335 if (!SDValue(N, 1).use_empty()) {
1336 SDValue Sub1 = CurDAG->getTargetConstant(AMDGPU::sub1, SL, MVT::i32);
1337 SDNode *Hi = CurDAG->getMachineNode(TargetOpcode::EXTRACT_SUBREG, SL,
1338 MVT::i32, SDValue(Mad, 0), Sub1);
1339 ReplaceUses(SDValue(N, 1), SDValue(Hi, 0));
1340 }
1341 CurDAG->RemoveDeadNode(N);
1342}
1343
1344bool AMDGPUDAGToDAGISel::isDSOffsetLegal(SDValue Base, unsigned Offset) const {
1345 if (!isUInt<16>(Offset))
1346 return false;
1347
1348 if (!Base || Subtarget->hasUsableDSOffset() ||
1349 Subtarget->unsafeDSOffsetFoldingEnabled())
1350 return true;
1351
1352 // On Southern Islands instruction with a negative base value and an offset
1353 // don't seem to work.
1354 return CurDAG->SignBitIsZero(Base);
1355}
1356
1357bool AMDGPUDAGToDAGISel::SelectDS1Addr1Offset(SDValue Addr, SDValue &Base,
1358 SDValue &Offset) const {
1359 SDLoc DL(Addr);
1360 if (CurDAG->isBaseWithConstantOffset(Addr)) {
1361 SDValue N0 = Addr.getOperand(0);
1362 SDValue N1 = Addr.getOperand(1);
1363 ConstantSDNode *C1 = cast<ConstantSDNode>(N1);
1364 if (isDSOffsetLegal(N0, C1->getSExtValue())) {
1365 // (add n0, c0)
1366 Base = N0;
1367 Offset = CurDAG->getTargetConstant(C1->getZExtValue(), DL, MVT::i16);
1368 return true;
1369 }
1370 } else if (Addr.getOpcode() == ISD::SUB) {
1371 // sub C, x -> add (sub 0, x), C
1372 if (const ConstantSDNode *C = dyn_cast<ConstantSDNode>(Addr.getOperand(0))) {
1373 int64_t ByteOffset = C->getSExtValue();
1374 if (isDSOffsetLegal(SDValue(), ByteOffset)) {
1375 SDValue Zero = CurDAG->getTargetConstant(0, DL, MVT::i32);
1376
1377 // XXX - This is kind of hacky. Create a dummy sub node so we can check
1378 // the known bits in isDSOffsetLegal. We need to emit the selected node
1379 // here, so this is thrown away.
1380 SDValue Sub = CurDAG->getNode(ISD::SUB, DL, MVT::i32,
1381 Zero, Addr.getOperand(1));
1382
1383 if (isDSOffsetLegal(Sub, ByteOffset)) {
1385 Opnds.push_back(Zero);
1386 Opnds.push_back(Addr.getOperand(1));
1387
1388 // FIXME: Select to VOP3 version for with-carry.
1389 unsigned SubOp = AMDGPU::V_SUB_CO_U32_e32;
1390 if (Subtarget->hasAddNoCarryInsts()) {
1391 SubOp = AMDGPU::V_SUB_U32_e64;
1392 Opnds.push_back(
1393 CurDAG->getTargetConstant(0, {}, MVT::i1)); // clamp bit
1394 }
1395
1396 MachineSDNode *MachineSub =
1397 CurDAG->getMachineNode(SubOp, DL, MVT::i32, Opnds);
1398
1399 Base = SDValue(MachineSub, 0);
1400 Offset = CurDAG->getTargetConstant(ByteOffset, DL, MVT::i16);
1401 return true;
1402 }
1403 }
1404 }
1405 } else if (const ConstantSDNode *CAddr = dyn_cast<ConstantSDNode>(Addr)) {
1406 // If we have a constant address, prefer to put the constant into the
1407 // offset. This can save moves to load the constant address since multiple
1408 // operations can share the zero base address register, and enables merging
1409 // into read2 / write2 instructions.
1410
1411 SDLoc DL(Addr);
1412
1413 if (isDSOffsetLegal(SDValue(), CAddr->getZExtValue())) {
1414 SDValue Zero = CurDAG->getTargetConstant(0, DL, MVT::i32);
1415 MachineSDNode *MovZero = CurDAG->getMachineNode(AMDGPU::V_MOV_B32_e32,
1416 DL, MVT::i32, Zero);
1417 Base = SDValue(MovZero, 0);
1418 Offset = CurDAG->getTargetConstant(CAddr->getZExtValue(), DL, MVT::i16);
1419 return true;
1420 }
1421 }
1422
1423 // default case
1424 Base = Addr;
1425 Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i16);
1426 return true;
1427}
1428
1429bool AMDGPUDAGToDAGISel::isDSOffset2Legal(SDValue Base, unsigned Offset0,
1430 unsigned Offset1,
1431 unsigned Size) const {
1432 if (Offset0 % Size != 0 || Offset1 % Size != 0)
1433 return false;
1434 if (!isUInt<8>(Offset0 / Size) || !isUInt<8>(Offset1 / Size))
1435 return false;
1436
1437 if (!Base || Subtarget->hasUsableDSOffset() ||
1438 Subtarget->unsafeDSOffsetFoldingEnabled())
1439 return true;
1440
1441 // On Southern Islands instruction with a negative base value and an offset
1442 // don't seem to work.
1443 return CurDAG->SignBitIsZero(Base);
1444}
1445
1446// Return whether the operation has NoUnsignedWrap property.
1447static bool isNoUnsignedWrap(SDValue Addr) {
1448 return (Addr.getOpcode() == ISD::ADD &&
1449 Addr->getFlags().hasNoUnsignedWrap()) ||
1450 Addr->getOpcode() == ISD::OR;
1451}
1452
1453// Check that the base address of flat scratch load/store in the form of `base +
1454// offset` is legal to be put in SGPR/VGPR (i.e. unsigned per hardware
1455// requirement). We always treat the first operand as the base address here.
1456bool AMDGPUDAGToDAGISel::isFlatScratchBaseLegal(SDValue Addr) const {
1457 if (isNoUnsignedWrap(Addr))
1458 return true;
1459
1460 // Starting with GFX12, VADDR and SADDR fields in VSCRATCH can use negative
1461 // values.
1462 if (Subtarget->hasSignedScratchOffsets())
1463 return true;
1464
1465 auto LHS = Addr.getOperand(0);
1466 auto RHS = Addr.getOperand(1);
1467
1468 // If the immediate offset is negative and within certain range, the base
1469 // address cannot also be negative. If the base is also negative, the sum
1470 // would be either negative or much larger than the valid range of scratch
1471 // memory a thread can access.
1472 ConstantSDNode *ImmOp = nullptr;
1473 if (Addr.getOpcode() == ISD::ADD && (ImmOp = dyn_cast<ConstantSDNode>(RHS))) {
1474 if (ImmOp->getSExtValue() < 0 && ImmOp->getSExtValue() > -0x40000000)
1475 return true;
1476 }
1477
1478 return CurDAG->SignBitIsZero(LHS);
1479}
1480
1481// Check address value in SGPR/VGPR are legal for flat scratch in the form
1482// of: SGPR + VGPR.
1483bool AMDGPUDAGToDAGISel::isFlatScratchBaseLegalSV(SDValue Addr) const {
1484 if (isNoUnsignedWrap(Addr))
1485 return true;
1486
1487 // Starting with GFX12, VADDR and SADDR fields in VSCRATCH can use negative
1488 // values.
1489 if (Subtarget->hasSignedScratchOffsets())
1490 return true;
1491
1492 auto LHS = Addr.getOperand(0);
1493 auto RHS = Addr.getOperand(1);
1494 return CurDAG->SignBitIsZero(RHS) && CurDAG->SignBitIsZero(LHS);
1495}
1496
1497// Check address value in SGPR/VGPR are legal for flat scratch in the form
1498// of: SGPR + VGPR + Imm.
1499bool AMDGPUDAGToDAGISel::isFlatScratchBaseLegalSVImm(SDValue Addr) const {
1500 // Starting with GFX12, VADDR and SADDR fields in VSCRATCH can use negative
1501 // values.
1502 if (AMDGPU::isGFX12Plus(*Subtarget))
1503 return true;
1504
1505 auto Base = Addr.getOperand(0);
1506 auto *RHSImm = cast<ConstantSDNode>(Addr.getOperand(1));
1507 // If the immediate offset is negative and within certain range, the base
1508 // address cannot also be negative. If the base is also negative, the sum
1509 // would be either negative or much larger than the valid range of scratch
1510 // memory a thread can access.
1511 if (isNoUnsignedWrap(Base) &&
1512 (isNoUnsignedWrap(Addr) ||
1513 (RHSImm->getSExtValue() < 0 && RHSImm->getSExtValue() > -0x40000000)))
1514 return true;
1515
1516 auto LHS = Base.getOperand(0);
1517 auto RHS = Base.getOperand(1);
1518 return CurDAG->SignBitIsZero(RHS) && CurDAG->SignBitIsZero(LHS);
1519}
1520
1521// TODO: If offset is too big, put low 16-bit into offset.
1522bool AMDGPUDAGToDAGISel::SelectDS64Bit4ByteAligned(SDValue Addr, SDValue &Base,
1523 SDValue &Offset0,
1524 SDValue &Offset1) const {
1525 return SelectDSReadWrite2(Addr, Base, Offset0, Offset1, 4);
1526}
1527
1528bool AMDGPUDAGToDAGISel::SelectDS128Bit8ByteAligned(SDValue Addr, SDValue &Base,
1529 SDValue &Offset0,
1530 SDValue &Offset1) const {
1531 return SelectDSReadWrite2(Addr, Base, Offset0, Offset1, 8);
1532}
1533
1534bool AMDGPUDAGToDAGISel::SelectDSReadWrite2(SDValue Addr, SDValue &Base,
1535 SDValue &Offset0, SDValue &Offset1,
1536 unsigned Size) const {
1537 SDLoc DL(Addr);
1538
1539 if (CurDAG->isBaseWithConstantOffset(Addr)) {
1540 SDValue N0 = Addr.getOperand(0);
1541 SDValue N1 = Addr.getOperand(1);
1542 ConstantSDNode *C1 = cast<ConstantSDNode>(N1);
1543 unsigned OffsetValue0 = C1->getZExtValue();
1544 unsigned OffsetValue1 = OffsetValue0 + Size;
1545
1546 // (add n0, c0)
1547 if (isDSOffset2Legal(N0, OffsetValue0, OffsetValue1, Size)) {
1548 Base = N0;
1549 Offset0 = CurDAG->getTargetConstant(OffsetValue0 / Size, DL, MVT::i32);
1550 Offset1 = CurDAG->getTargetConstant(OffsetValue1 / Size, DL, MVT::i32);
1551 return true;
1552 }
1553 } else if (Addr.getOpcode() == ISD::SUB) {
1554 // sub C, x -> add (sub 0, x), C
1555 if (const ConstantSDNode *C =
1557 unsigned OffsetValue0 = C->getZExtValue();
1558 unsigned OffsetValue1 = OffsetValue0 + Size;
1559
1560 if (isDSOffset2Legal(SDValue(), OffsetValue0, OffsetValue1, Size)) {
1561 SDLoc DL(Addr);
1562 SDValue Zero = CurDAG->getTargetConstant(0, DL, MVT::i32);
1563
1564 // XXX - This is kind of hacky. Create a dummy sub node so we can check
1565 // the known bits in isDSOffsetLegal. We need to emit the selected node
1566 // here, so this is thrown away.
1567 SDValue Sub =
1568 CurDAG->getNode(ISD::SUB, DL, MVT::i32, Zero, Addr.getOperand(1));
1569
1570 if (isDSOffset2Legal(Sub, OffsetValue0, OffsetValue1, Size)) {
1572 Opnds.push_back(Zero);
1573 Opnds.push_back(Addr.getOperand(1));
1574 unsigned SubOp = AMDGPU::V_SUB_CO_U32_e32;
1575 if (Subtarget->hasAddNoCarryInsts()) {
1576 SubOp = AMDGPU::V_SUB_U32_e64;
1577 Opnds.push_back(
1578 CurDAG->getTargetConstant(0, {}, MVT::i1)); // clamp bit
1579 }
1580
1581 MachineSDNode *MachineSub = CurDAG->getMachineNode(
1582 SubOp, DL, MVT::getIntegerVT(Size * 8), Opnds);
1583
1584 Base = SDValue(MachineSub, 0);
1585 Offset0 =
1586 CurDAG->getTargetConstant(OffsetValue0 / Size, DL, MVT::i32);
1587 Offset1 =
1588 CurDAG->getTargetConstant(OffsetValue1 / Size, DL, MVT::i32);
1589 return true;
1590 }
1591 }
1592 }
1593 } else if (const ConstantSDNode *CAddr = dyn_cast<ConstantSDNode>(Addr)) {
1594 unsigned OffsetValue0 = CAddr->getZExtValue();
1595 unsigned OffsetValue1 = OffsetValue0 + Size;
1596
1597 if (isDSOffset2Legal(SDValue(), OffsetValue0, OffsetValue1, Size)) {
1598 SDValue Zero = CurDAG->getTargetConstant(0, DL, MVT::i32);
1599 MachineSDNode *MovZero =
1600 CurDAG->getMachineNode(AMDGPU::V_MOV_B32_e32, DL, MVT::i32, Zero);
1601 Base = SDValue(MovZero, 0);
1602 Offset0 = CurDAG->getTargetConstant(OffsetValue0 / Size, DL, MVT::i32);
1603 Offset1 = CurDAG->getTargetConstant(OffsetValue1 / Size, DL, MVT::i32);
1604 return true;
1605 }
1606 }
1607
1608 // default case
1609
1610 Base = Addr;
1611 Offset0 = CurDAG->getTargetConstant(0, DL, MVT::i32);
1612 Offset1 = CurDAG->getTargetConstant(1, DL, MVT::i32);
1613 return true;
1614}
1615
1616bool AMDGPUDAGToDAGISel::SelectMUBUF(SDValue Addr, SDValue &Ptr, SDValue &VAddr,
1617 SDValue &SOffset, SDValue &Offset,
1618 SDValue &Offen, SDValue &Idxen,
1619 SDValue &Addr64) const {
1620 // Subtarget prefers to use flat instruction
1621 // FIXME: This should be a pattern predicate and not reach here
1622 if (Subtarget->useFlatForGlobal())
1623 return false;
1624
1625 SDLoc DL(Addr);
1626
1627 Idxen = CurDAG->getTargetConstant(0, DL, MVT::i1);
1628 Offen = CurDAG->getTargetConstant(0, DL, MVT::i1);
1629 Addr64 = CurDAG->getTargetConstant(0, DL, MVT::i1);
1630 SOffset = Subtarget->hasRestrictedSOffset()
1631 ? CurDAG->getRegister(AMDGPU::SGPR_NULL, MVT::i32)
1632 : CurDAG->getTargetConstant(0, DL, MVT::i32);
1633
1634 ConstantSDNode *C1 = nullptr;
1635 SDValue N0 = Addr;
1636 if (CurDAG->isBaseWithConstantOffset(Addr)) {
1637 C1 = cast<ConstantSDNode>(Addr.getOperand(1));
1638 if (isUInt<32>(C1->getZExtValue()))
1639 N0 = Addr.getOperand(0);
1640 else
1641 C1 = nullptr;
1642 }
1643
1644 if (N0->isAnyAdd()) {
1645 // (add N2, N3) -> addr64, or
1646 // (add (add N2, N3), C1) -> addr64
1647 SDValue N2 = N0.getOperand(0);
1648 SDValue N3 = N0.getOperand(1);
1649 Addr64 = CurDAG->getTargetConstant(1, DL, MVT::i1);
1650
1651 if (N2->isDivergent()) {
1652 if (N3->isDivergent()) {
1653 // Both N2 and N3 are divergent. Use N0 (the result of the add) as the
1654 // addr64, and construct the resource from a 0 address.
1655 Ptr = SDValue(buildSMovImm64(DL, 0, MVT::v2i32), 0);
1656 VAddr = N0;
1657 } else {
1658 // N2 is divergent, N3 is not.
1659 Ptr = N3;
1660 VAddr = N2;
1661 }
1662 } else {
1663 // N2 is not divergent.
1664 Ptr = N2;
1665 VAddr = N3;
1666 }
1667 Offset = CurDAG->getTargetConstant(0, DL, MVT::i32);
1668 } else if (N0->isDivergent()) {
1669 // N0 is divergent. Use it as the addr64, and construct the resource from a
1670 // 0 address.
1671 Ptr = SDValue(buildSMovImm64(DL, 0, MVT::v2i32), 0);
1672 VAddr = N0;
1673 Addr64 = CurDAG->getTargetConstant(1, DL, MVT::i1);
1674 } else {
1675 // N0 -> offset, or
1676 // (N0 + C1) -> offset
1677 VAddr = CurDAG->getTargetConstant(0, DL, MVT::i32);
1678 Ptr = N0;
1679 }
1680
1681 if (!C1) {
1682 // No offset.
1683 Offset = CurDAG->getTargetConstant(0, DL, MVT::i32);
1684 return true;
1685 }
1686
1687 const SIInstrInfo *TII = Subtarget->getInstrInfo();
1688 if (TII->isLegalMUBUFImmOffset(C1->getZExtValue())) {
1689 // Legal offset for instruction.
1690 Offset = CurDAG->getTargetConstant(C1->getZExtValue(), DL, MVT::i32);
1691 return true;
1692 }
1693
1694 // Illegal offset, store it in soffset.
1695 Offset = CurDAG->getTargetConstant(0, DL, MVT::i32);
1696 SOffset =
1697 SDValue(CurDAG->getMachineNode(
1698 AMDGPU::S_MOV_B32, DL, MVT::i32,
1699 CurDAG->getTargetConstant(C1->getZExtValue(), DL, MVT::i32)),
1700 0);
1701 return true;
1702}
1703
1704bool AMDGPUDAGToDAGISel::SelectMUBUFAddr64(SDValue Addr, SDValue &SRsrc,
1705 SDValue &VAddr, SDValue &SOffset,
1706 SDValue &Offset) const {
1707 SDValue Ptr, Offen, Idxen, Addr64;
1708
1709 // addr64 bit was removed for volcanic islands.
1710 // FIXME: This should be a pattern predicate and not reach here
1711 if (!Subtarget->hasAddr64())
1712 return false;
1713
1714 if (!SelectMUBUF(Addr, Ptr, VAddr, SOffset, Offset, Offen, Idxen, Addr64))
1715 return false;
1716
1717 ConstantSDNode *C = cast<ConstantSDNode>(Addr64);
1718 if (C->getSExtValue()) {
1719 SDLoc DL(Addr);
1720
1721 const SITargetLowering& Lowering =
1722 *static_cast<const SITargetLowering*>(getTargetLowering());
1723
1724 SRsrc = SDValue(Lowering.wrapAddr64Rsrc(*CurDAG, DL, Ptr), 0);
1725 return true;
1726 }
1727
1728 return false;
1729}
1730
1731std::pair<SDValue, SDValue> AMDGPUDAGToDAGISel::foldFrameIndex(SDValue N) const {
1732 SDLoc DL(N);
1733
1734 auto *FI = dyn_cast<FrameIndexSDNode>(N);
1735 SDValue TFI =
1736 FI ? CurDAG->getTargetFrameIndex(FI->getIndex(), FI->getValueType(0)) : N;
1737
1738 // We rebase the base address into an absolute stack address and hence
1739 // use constant 0 for soffset. This value must be retained until
1740 // frame elimination and eliminateFrameIndex will choose the appropriate
1741 // frame register if need be.
1742 return std::pair(TFI, CurDAG->getTargetConstant(0, DL, MVT::i32));
1743}
1744
1745bool AMDGPUDAGToDAGISel::SelectMUBUFScratchOffen(SDNode *Parent,
1746 SDValue Addr, SDValue &Rsrc,
1747 SDValue &VAddr, SDValue &SOffset,
1748 SDValue &ImmOffset) const {
1749
1750 SDLoc DL(Addr);
1751 MachineFunction &MF = CurDAG->getMachineFunction();
1752 const SIMachineFunctionInfo *Info = MF.getInfo<SIMachineFunctionInfo>();
1753
1754 Rsrc = CurDAG->getRegister(Info->getScratchRSrcReg(), MVT::v4i32);
1755
1756 if (ConstantSDNode *CAddr = dyn_cast<ConstantSDNode>(Addr)) {
1757 int64_t Imm = CAddr->getSExtValue();
1758 const int64_t NullPtr =
1760 // Don't fold null pointer.
1761 if (Imm != NullPtr) {
1762 const int64_t MaxOffset = SIInstrInfo::getMaxMUBUFImmOffset(*Subtarget);
1763 SDValue HighBits =
1764 CurDAG->getTargetConstant(Imm & ~MaxOffset, DL, MVT::i32);
1765 MachineSDNode *MovHighBits = CurDAG->getMachineNode(
1766 AMDGPU::V_MOV_B32_e32, DL, MVT::i32, HighBits);
1767 VAddr = SDValue(MovHighBits, 0);
1768
1769 SOffset = CurDAG->getTargetConstant(0, DL, MVT::i32);
1770 ImmOffset = CurDAG->getTargetConstant(Imm & MaxOffset, DL, MVT::i32);
1771 return true;
1772 }
1773 }
1774
1775 if (CurDAG->isBaseWithConstantOffset(Addr)) {
1776 // (add n0, c1)
1777
1778 SDValue N0 = Addr.getOperand(0);
1779 uint64_t C1 = Addr.getConstantOperandVal(1);
1780
1781 // Offsets in vaddr must be positive if range checking is enabled.
1782 //
1783 // The total computation of vaddr + soffset + offset must not overflow. If
1784 // vaddr is negative, even if offset is 0 the sgpr offset add will end up
1785 // overflowing.
1786 //
1787 // Prior to gfx9, MUBUF instructions with the vaddr offset enabled would
1788 // always perform a range check. If a negative vaddr base index was used,
1789 // this would fail the range check. The overall address computation would
1790 // compute a valid address, but this doesn't happen due to the range
1791 // check. For out-of-bounds MUBUF loads, a 0 is returned.
1792 //
1793 // Therefore it should be safe to fold any VGPR offset on gfx9 into the
1794 // MUBUF vaddr, but not on older subtargets which can only do this if the
1795 // sign bit is known 0.
1796 const SIInstrInfo *TII = Subtarget->getInstrInfo();
1797 if (TII->isLegalMUBUFImmOffset(C1) &&
1798 (!Subtarget->privateMemoryResourceIsRangeChecked() ||
1799 CurDAG->SignBitIsZero(N0))) {
1800 std::tie(VAddr, SOffset) = foldFrameIndex(N0);
1801 ImmOffset = CurDAG->getTargetConstant(C1, DL, MVT::i32);
1802 return true;
1803 }
1804 }
1805
1806 // (node)
1807 std::tie(VAddr, SOffset) = foldFrameIndex(Addr);
1808 ImmOffset = CurDAG->getTargetConstant(0, DL, MVT::i32);
1809 return true;
1810}
1811
1812static bool IsCopyFromSGPR(const SIRegisterInfo &TRI, SDValue Val) {
1813 if (Val.getOpcode() != ISD::CopyFromReg)
1814 return false;
1815 auto Reg = cast<RegisterSDNode>(Val.getOperand(1))->getReg();
1816 if (!Reg.isPhysical())
1817 return false;
1818 const auto *RC = TRI.getPhysRegBaseClass(Reg);
1819 return RC && TRI.isSGPRClass(RC);
1820}
1821
1822bool AMDGPUDAGToDAGISel::SelectMUBUFScratchOffset(SDNode *Parent,
1823 SDValue Addr,
1824 SDValue &SRsrc,
1825 SDValue &SOffset,
1826 SDValue &Offset) const {
1827 const SIRegisterInfo *TRI = Subtarget->getRegisterInfo();
1828 const SIInstrInfo *TII = Subtarget->getInstrInfo();
1829 MachineFunction &MF = CurDAG->getMachineFunction();
1830 const SIMachineFunctionInfo *Info = MF.getInfo<SIMachineFunctionInfo>();
1831 SDLoc DL(Addr);
1832
1833 // CopyFromReg <sgpr>
1834 if (IsCopyFromSGPR(*TRI, Addr)) {
1835 SRsrc = CurDAG->getRegister(Info->getScratchRSrcReg(), MVT::v4i32);
1836 SOffset = Addr;
1837 Offset = CurDAG->getTargetConstant(0, DL, MVT::i32);
1838 return true;
1839 }
1840
1841 ConstantSDNode *CAddr;
1842 if (Addr.getOpcode() == ISD::ADD) {
1843 // Add (CopyFromReg <sgpr>) <constant>
1844 CAddr = dyn_cast<ConstantSDNode>(Addr.getOperand(1));
1845 if (!CAddr || !TII->isLegalMUBUFImmOffset(CAddr->getZExtValue()))
1846 return false;
1847 if (!IsCopyFromSGPR(*TRI, Addr.getOperand(0)))
1848 return false;
1849
1850 SOffset = Addr.getOperand(0);
1851 } else if ((CAddr = dyn_cast<ConstantSDNode>(Addr)) &&
1852 TII->isLegalMUBUFImmOffset(CAddr->getZExtValue())) {
1853 // <constant>
1854 SOffset = CurDAG->getTargetConstant(0, DL, MVT::i32);
1855 } else {
1856 return false;
1857 }
1858
1859 SRsrc = CurDAG->getRegister(Info->getScratchRSrcReg(), MVT::v4i32);
1860
1861 Offset = CurDAG->getTargetConstant(CAddr->getZExtValue(), DL, MVT::i32);
1862 return true;
1863}
1864
1865bool AMDGPUDAGToDAGISel::SelectMUBUFOffset(SDValue Addr, SDValue &SRsrc,
1866 SDValue &SOffset, SDValue &Offset
1867 ) const {
1868 SDValue Ptr, VAddr, Offen, Idxen, Addr64;
1869 const SIInstrInfo *TII = Subtarget->getInstrInfo();
1870
1871 if (!SelectMUBUF(Addr, Ptr, VAddr, SOffset, Offset, Offen, Idxen, Addr64))
1872 return false;
1873
1874 if (!cast<ConstantSDNode>(Offen)->getSExtValue() &&
1875 !cast<ConstantSDNode>(Idxen)->getSExtValue() &&
1876 !cast<ConstantSDNode>(Addr64)->getSExtValue()) {
1877 uint64_t Rsrc = TII->getDefaultRsrcDataFormat() |
1878 maskTrailingOnes<uint64_t>(32); // Size
1879 SDLoc DL(Addr);
1880
1881 const SITargetLowering& Lowering =
1882 *static_cast<const SITargetLowering*>(getTargetLowering());
1883
1884 SRsrc = SDValue(Lowering.buildRSRC(*CurDAG, DL, Ptr, 0, Rsrc), 0);
1885 return true;
1886 }
1887 return false;
1888}
1889
1890bool AMDGPUDAGToDAGISel::SelectBUFSOffset(SDValue ByteOffsetNode,
1891 SDValue &SOffset) const {
1892 if (Subtarget->hasRestrictedSOffset() && isNullConstant(ByteOffsetNode)) {
1893 SOffset = CurDAG->getRegister(AMDGPU::SGPR_NULL, MVT::i32);
1894 return true;
1895 }
1896
1897 SOffset = ByteOffsetNode;
1898 return true;
1899}
1900
1901// Find a load or store from corresponding pattern root.
1902// Roots may be build_vector, bitconvert or their combinations.
1905 if (MemSDNode *MN = dyn_cast<MemSDNode>(N))
1906 return MN;
1908 for (SDValue V : N->op_values())
1909 if (MemSDNode *MN =
1911 return MN;
1912 llvm_unreachable("cannot find MemSDNode in the pattern!");
1913}
1914
1915bool AMDGPUDAGToDAGISel::SelectFlatOffsetImpl(
1916 SDNode *N, SDValue Addr, SDValue &VAddr, SDValue &Offset,
1917 AMDGPU::FlatAddrSpace FlatVariant) const {
1919 int64_t OffsetVal = 0;
1920
1921 unsigned AS = findMemSDNode(N)->getAddressSpace();
1922
1923 bool CanHaveFlatSegmentOffsetBug =
1924 Subtarget->hasFlatSegmentOffsetBug() &&
1925 FlatVariant == FlatAddrSpace::FLAT &&
1927
1928 if (Subtarget->hasFlatInstOffsets() && !CanHaveFlatSegmentOffsetBug) {
1929 SDValue N0, N1;
1930 if (isBaseWithConstantOffset64(Addr, N0, N1) &&
1931 (FlatVariant != FlatAddrSpace::FlatScratch ||
1932 isFlatScratchBaseLegal(Addr))) {
1933 int64_t COffsetVal = cast<ConstantSDNode>(N1)->getSExtValue();
1934
1935 // Adding the offset to the base address in a FLAT instruction must not
1936 // change the memory aperture in which the address falls. Therefore we can
1937 // only fold offsets from inbounds GEPs into FLAT instructions.
1938 bool IsInBounds =
1939 Addr.getOpcode() == ISD::PTRADD && Addr->getFlags().hasInBounds();
1940 if (COffsetVal == 0 || FlatVariant != FlatAddrSpace::FLAT || IsInBounds) {
1941 const SIInstrInfo *TII = Subtarget->getInstrInfo();
1942 if (TII->isLegalFLATOffset(COffsetVal, AS, FlatVariant)) {
1943 Addr = N0;
1944 OffsetVal = COffsetVal;
1945 } else {
1946 // If the offset doesn't fit, put the low bits into the offset field
1947 // and add the rest.
1948 //
1949 // For a FLAT instruction the hardware decides whether to access
1950 // global/scratch/shared memory based on the high bits of vaddr,
1951 // ignoring the offset field, so we have to ensure that when we add
1952 // remainder to vaddr it still points into the same underlying object.
1953 // The easiest way to do that is to make sure that we split the offset
1954 // into two pieces that are both >= 0 or both <= 0.
1955
1956 SDLoc DL(N);
1957 uint64_t RemainderOffset;
1958
1959 std::tie(OffsetVal, RemainderOffset) =
1960 TII->splitFlatOffset(COffsetVal, AS, FlatVariant);
1961
1962 SDValue AddOffsetLo =
1963 getMaterializedScalarImm32(Lo_32(RemainderOffset), DL);
1964 SDValue Clamp = CurDAG->getTargetConstant(0, DL, MVT::i1);
1965
1966 if (Addr.getValueType().getSizeInBits() == 32) {
1968 Opnds.push_back(N0);
1969 Opnds.push_back(AddOffsetLo);
1970 unsigned AddOp = AMDGPU::V_ADD_CO_U32_e32;
1971 if (Subtarget->hasAddNoCarryInsts()) {
1972 AddOp = AMDGPU::V_ADD_U32_e64;
1973 Opnds.push_back(Clamp);
1974 }
1975 Addr =
1976 SDValue(CurDAG->getMachineNode(AddOp, DL, MVT::i32, Opnds), 0);
1977 } else {
1978 // TODO: Should this try to use a scalar add pseudo if the base
1979 // address is uniform and saddr is usable?
1980 SDValue Sub0 =
1981 CurDAG->getTargetConstant(AMDGPU::sub0, DL, MVT::i32);
1982 SDValue Sub1 =
1983 CurDAG->getTargetConstant(AMDGPU::sub1, DL, MVT::i32);
1984
1985 SDNode *N0Lo = CurDAG->getMachineNode(TargetOpcode::EXTRACT_SUBREG,
1986 DL, MVT::i32, N0, Sub0);
1987 SDNode *N0Hi = CurDAG->getMachineNode(TargetOpcode::EXTRACT_SUBREG,
1988 DL, MVT::i32, N0, Sub1);
1989
1990 SDValue AddOffsetHi =
1991 getMaterializedScalarImm32(Hi_32(RemainderOffset), DL);
1992
1993 SDVTList VTs = CurDAG->getVTList(MVT::i32, MVT::i1);
1994
1995 SDNode *Add =
1996 CurDAG->getMachineNode(AMDGPU::V_ADD_CO_U32_e64, DL, VTs,
1997 {AddOffsetLo, SDValue(N0Lo, 0), Clamp});
1998
1999 SDNode *Addc = CurDAG->getMachineNode(
2000 AMDGPU::V_ADDC_U32_e64, DL, VTs,
2001 {AddOffsetHi, SDValue(N0Hi, 0), SDValue(Add, 1), Clamp});
2002
2003 SDValue RegSequenceArgs[] = {
2004 CurDAG->getTargetConstant(AMDGPU::VReg_64RegClassID, DL,
2005 MVT::i32),
2006 SDValue(Add, 0), Sub0, SDValue(Addc, 0), Sub1};
2007
2008 Addr = SDValue(CurDAG->getMachineNode(AMDGPU::REG_SEQUENCE, DL,
2009 MVT::i64, RegSequenceArgs),
2010 0);
2011 }
2012 }
2013 }
2014 }
2015 }
2016
2017 VAddr = Addr;
2018 Offset = CurDAG->getSignedTargetConstant(OffsetVal, SDLoc(), MVT::i32);
2019 return true;
2020}
2021
2022bool AMDGPUDAGToDAGISel::SelectFlatOffset(SDNode *N, SDValue Addr,
2023 SDValue &VAddr,
2024 SDValue &Offset) const {
2025 return SelectFlatOffsetImpl(N, Addr, VAddr, Offset,
2027}
2028
2029bool AMDGPUDAGToDAGISel::SelectGlobalOffset(SDNode *N, SDValue Addr,
2030 SDValue &VAddr,
2031 SDValue &Offset) const {
2032 return SelectFlatOffsetImpl(N, Addr, VAddr, Offset,
2034}
2035
2036bool AMDGPUDAGToDAGISel::SelectScratchOffset(SDNode *N, SDValue Addr,
2037 SDValue &VAddr,
2038 SDValue &Offset) const {
2039 return SelectFlatOffsetImpl(N, Addr, VAddr, Offset,
2041}
2042
2043// If this matches *_extend i32:x, return x
2044// Otherwise if the value is I32 returns x.
2046 const SelectionDAG *DAG) {
2047 if (Op.getValueType() == MVT::i32)
2048 return Op;
2049
2050 if (Op.getOpcode() != (IsSigned ? ISD::SIGN_EXTEND : ISD::ZERO_EXTEND) &&
2051 Op.getOpcode() != ISD::ANY_EXTEND &&
2052 !(Op.getOpcode() == (IsSigned ? ISD::ZERO_EXTEND : ISD::SIGN_EXTEND) &&
2053 DAG->SignBitIsZero(Op.getOperand(0))))
2054 return SDValue();
2055
2056 SDValue ExtSrc = Op.getOperand(0);
2057 return (ExtSrc.getValueType() == MVT::i32) ? ExtSrc : SDValue();
2058}
2059
2060// Match (64-bit SGPR base) + (zext vgpr offset) + sext(imm offset)
2061// or (64-bit SGPR base) + (sext vgpr offset) + sext(imm offset)
2062bool AMDGPUDAGToDAGISel::SelectGlobalSAddr(SDNode *N, SDValue Addr,
2063 SDValue &SAddr, SDValue &VOffset,
2064 SDValue &Offset, bool &ScaleOffset,
2065 bool NeedIOffset) const {
2067 int64_t ImmOffset = 0;
2068 ScaleOffset = false;
2069
2070 // Match the immediate offset first, which canonically is moved as low as
2071 // possible.
2072
2073 SDValue LHS, RHS;
2074 if (isBaseWithConstantOffset64(Addr, LHS, RHS)) {
2075 int64_t COffsetVal = cast<ConstantSDNode>(RHS)->getSExtValue();
2076 const SIInstrInfo *TII = Subtarget->getInstrInfo();
2077
2078 if (NeedIOffset &&
2079 TII->isLegalFLATOffset(COffsetVal, AMDGPUAS::GLOBAL_ADDRESS,
2080 FlatAddrSpace::FlatGlobal)) {
2081 Addr = LHS;
2082 ImmOffset = COffsetVal;
2083 } else if (!LHS->isDivergent()) {
2084 if (COffsetVal != 0) {
2085 SDLoc SL(N);
2086 // saddr + large_offset -> saddr +
2087 // (voffset = large_offset & ~MaxOffset) +
2088 // (large_offset & MaxOffset);
2089 int64_t SplitImmOffset = 0, RemainderOffset = COffsetVal;
2090 if (NeedIOffset) {
2091 std::tie(SplitImmOffset, RemainderOffset) = TII->splitFlatOffset(
2092 COffsetVal, AMDGPUAS::GLOBAL_ADDRESS, FlatAddrSpace::FlatGlobal);
2093 }
2094
2095 if (Subtarget->hasSignedGVSOffset() ? isInt<32>(RemainderOffset)
2096 : isUInt<32>(RemainderOffset)) {
2097 SDNode *VMov = CurDAG->getMachineNode(
2098 AMDGPU::V_MOV_B32_e32, SL, MVT::i32,
2099 CurDAG->getTargetConstant(Lo_32(RemainderOffset), SDLoc(),
2100 MVT::i32));
2101 VOffset = SDValue(VMov, 0);
2102 SAddr = LHS;
2103 Offset = CurDAG->getSignedTargetConstant(SplitImmOffset, SDLoc(),
2104 MVT::i32);
2105 return true;
2106 }
2107 }
2108
2109 // We are adding a 64 bit SGPR and a constant. If constant bus limit
2110 // is 1 we would need to perform 1 or 2 extra moves for each half of
2111 // the constant and it is better to do a scalar add and then issue a
2112 // single VALU instruction to materialize zero. Otherwise it is less
2113 // instructions to perform VALU adds with immediates or inline literals.
2114 unsigned NumLiterals =
2115 !TII->isInlineConstant(APInt(32, Lo_32(COffsetVal))) +
2116 !TII->isInlineConstant(APInt(32, Hi_32(COffsetVal)));
2117 if (Subtarget->getConstantBusLimit(AMDGPU::V_ADD_U32_e64) > NumLiterals)
2118 return false;
2119 }
2120 }
2121
2122 // Match the variable offset.
2123 if (Addr->isAnyAdd()) {
2124 LHS = Addr.getOperand(0);
2125
2126 if (!LHS->isDivergent()) {
2127 // add (i64 sgpr), (*_extend (i32 vgpr))
2128 RHS = Addr.getOperand(1);
2129 ScaleOffset = SelectScaleOffset(N, RHS, Subtarget->hasSignedGVSOffset());
2130 if (SDValue ExtRHS = matchExtFromI32orI32(
2131 RHS, Subtarget->hasSignedGVSOffset(), CurDAG)) {
2132 SAddr = LHS;
2133 VOffset = ExtRHS;
2134 }
2135 }
2136
2137 RHS = Addr.getOperand(1);
2138 if (!SAddr && !RHS->isDivergent()) {
2139 // add (*_extend (i32 vgpr)), (i64 sgpr)
2140 ScaleOffset = SelectScaleOffset(N, LHS, Subtarget->hasSignedGVSOffset());
2141 if (SDValue ExtLHS = matchExtFromI32orI32(
2142 LHS, Subtarget->hasSignedGVSOffset(), CurDAG)) {
2143 SAddr = RHS;
2144 VOffset = ExtLHS;
2145 }
2146 }
2147
2148 if (SAddr) {
2149 Offset = CurDAG->getSignedTargetConstant(ImmOffset, SDLoc(), MVT::i32);
2150 return true;
2151 }
2152 }
2153
2154 if (Subtarget->hasScaleOffset() &&
2155 (Addr.getOpcode() == (Subtarget->hasSignedGVSOffset()
2158 (Addr.getOpcode() == AMDGPUISD::MAD_U64_U32 &&
2159 CurDAG->SignBitIsZero(Addr.getOperand(0)))) &&
2160 Addr.getOperand(0)->isDivergent() &&
2162 !Addr.getOperand(2)->isDivergent()) {
2163 // mad_u64_u32 (i32 vgpr), (i32 c), (i64 sgpr)
2164 unsigned Size =
2165 (unsigned)cast<MemSDNode>(N)->getMemoryVT().getFixedSizeInBits() / 8;
2166 ScaleOffset = Addr.getConstantOperandVal(1) == Size;
2167 if (ScaleOffset) {
2168 SAddr = Addr.getOperand(2);
2169 VOffset = Addr.getOperand(0);
2170 Offset = CurDAG->getTargetConstant(ImmOffset, SDLoc(), MVT::i32);
2171 return true;
2172 }
2173 }
2174
2175 if (Addr->isDivergent() || Addr.isUndef() || isa<ConstantSDNode>(Addr))
2176 return false;
2177
2178 // It's cheaper to materialize a single 32-bit zero for vaddr than the two
2179 // moves required to copy a 64-bit SGPR to VGPR.
2180 SAddr = Addr;
2181 SDNode *VMov =
2182 CurDAG->getMachineNode(AMDGPU::V_MOV_B32_e32, SDLoc(Addr), MVT::i32,
2183 CurDAG->getTargetConstant(0, SDLoc(), MVT::i32));
2184 VOffset = SDValue(VMov, 0);
2185 Offset = CurDAG->getSignedTargetConstant(ImmOffset, SDLoc(), MVT::i32);
2186 return true;
2187}
2188
2189bool AMDGPUDAGToDAGISel::SelectGlobalSAddr(SDNode *N, SDValue Addr,
2190 SDValue &SAddr, SDValue &VOffset,
2191 SDValue &Offset,
2192 SDValue &CPol) const {
2193 bool ScaleOffset;
2194 if (!SelectGlobalSAddr(N, Addr, SAddr, VOffset, Offset, ScaleOffset))
2195 return false;
2196
2197 CPol = CurDAG->getTargetConstant(ScaleOffset ? AMDGPU::CPol::SCAL : 0,
2198 SDLoc(), MVT::i32);
2199 return true;
2200}
2201
2202bool AMDGPUDAGToDAGISel::SelectGlobalSAddrCPol(SDNode *N, SDValue Addr,
2203 SDValue &SAddr, SDValue &VOffset,
2204 SDValue &Offset,
2205 SDValue &CPol) const {
2206 bool ScaleOffset;
2207 if (!SelectGlobalSAddr(N, Addr, SAddr, VOffset, Offset, ScaleOffset))
2208 return false;
2209
2210 // We are assuming CPol is always the last operand of the intrinsic.
2211 auto PassedCPol =
2212 N->getConstantOperandVal(N->getNumOperands() - 1) & ~AMDGPU::CPol::SCAL;
2213 CPol = CurDAG->getTargetConstant(
2214 (ScaleOffset ? AMDGPU::CPol::SCAL : 0) | PassedCPol, SDLoc(), MVT::i32);
2215 return true;
2216}
2217
2218bool AMDGPUDAGToDAGISel::SelectGlobalSAddrCPolM0(SDNode *N, SDValue Addr,
2219 SDValue &SAddr,
2220 SDValue &VOffset,
2221 SDValue &Offset,
2222 SDValue &CPol) const {
2223 bool ScaleOffset;
2224 if (!SelectGlobalSAddr(N, Addr, SAddr, VOffset, Offset, ScaleOffset))
2225 return false;
2226
2227 // We are assuming CPol is second from last operand of the intrinsic.
2228 auto PassedCPol =
2229 N->getConstantOperandVal(N->getNumOperands() - 2) & ~AMDGPU::CPol::SCAL;
2230 CPol = CurDAG->getTargetConstant(
2231 (ScaleOffset ? AMDGPU::CPol::SCAL : 0) | PassedCPol, SDLoc(), MVT::i32);
2232 return true;
2233}
2234
2235bool AMDGPUDAGToDAGISel::SelectGlobalSAddrGLC(SDNode *N, SDValue Addr,
2236 SDValue &SAddr, SDValue &VOffset,
2237 SDValue &Offset,
2238 SDValue &CPol) const {
2239 bool ScaleOffset;
2240 if (!SelectGlobalSAddr(N, Addr, SAddr, VOffset, Offset, ScaleOffset))
2241 return false;
2242
2243 unsigned CPolVal = (ScaleOffset ? AMDGPU::CPol::SCAL : 0) | AMDGPU::CPol::GLC;
2244 CPol = CurDAG->getTargetConstant(CPolVal, SDLoc(), MVT::i32);
2245 return true;
2246}
2247
2248bool AMDGPUDAGToDAGISel::SelectGlobalSAddrNoIOffset(SDNode *N, SDValue Addr,
2249 SDValue &SAddr,
2250 SDValue &VOffset,
2251 SDValue &CPol) const {
2252 bool ScaleOffset;
2253 SDValue DummyOffset;
2254 if (!SelectGlobalSAddr(N, Addr, SAddr, VOffset, DummyOffset, ScaleOffset,
2255 false))
2256 return false;
2257
2258 // We are assuming CPol is always the last operand of the intrinsic.
2259 auto PassedCPol =
2260 N->getConstantOperandVal(N->getNumOperands() - 1) & ~AMDGPU::CPol::SCAL;
2261 CPol = CurDAG->getTargetConstant(
2262 (ScaleOffset ? AMDGPU::CPol::SCAL : 0) | PassedCPol, SDLoc(), MVT::i32);
2263 return true;
2264}
2265
2266bool AMDGPUDAGToDAGISel::SelectGlobalSAddrNoIOffsetM0(SDNode *N, SDValue Addr,
2267 SDValue &SAddr,
2268 SDValue &VOffset,
2269 SDValue &CPol) const {
2270 bool ScaleOffset;
2271 SDValue DummyOffset;
2272 if (!SelectGlobalSAddr(N, Addr, SAddr, VOffset, DummyOffset, ScaleOffset,
2273 false))
2274 return false;
2275
2276 // We are assuming CPol is second from last operand of the intrinsic.
2277 auto PassedCPol =
2278 N->getConstantOperandVal(N->getNumOperands() - 2) & ~AMDGPU::CPol::SCAL;
2279 CPol = CurDAG->getTargetConstant(
2280 (ScaleOffset ? AMDGPU::CPol::SCAL : 0) | PassedCPol, SDLoc(), MVT::i32);
2281 return true;
2282}
2283
2285 if (auto *FI = dyn_cast<FrameIndexSDNode>(SAddr)) {
2286 SAddr = CurDAG->getTargetFrameIndex(FI->getIndex(), FI->getValueType(0));
2287 } else if (SAddr.getOpcode() == ISD::ADD &&
2289 // Materialize this into a scalar move for scalar address to avoid
2290 // readfirstlane.
2291 auto *FI = cast<FrameIndexSDNode>(SAddr.getOperand(0));
2292 SDValue TFI = CurDAG->getTargetFrameIndex(FI->getIndex(),
2293 FI->getValueType(0));
2294 SAddr = SDValue(CurDAG->getMachineNode(AMDGPU::S_ADD_I32, SDLoc(SAddr),
2295 MVT::i32, TFI, SAddr.getOperand(1)),
2296 0);
2297 }
2298
2299 return SAddr;
2300}
2301
2302// Match (32-bit SGPR base) + sext(imm offset)
2303bool AMDGPUDAGToDAGISel::SelectScratchSAddr(SDNode *Parent, SDValue Addr,
2304 SDValue &SAddr,
2305 SDValue &Offset) const {
2307 if (Addr->isDivergent())
2308 return false;
2309
2310 SDLoc DL(Addr);
2311
2312 int64_t COffsetVal = 0;
2313
2314 if (CurDAG->isBaseWithConstantOffset(Addr) && isFlatScratchBaseLegal(Addr)) {
2315 COffsetVal = cast<ConstantSDNode>(Addr.getOperand(1))->getSExtValue();
2316 SAddr = Addr.getOperand(0);
2317 } else {
2318 SAddr = Addr;
2319 }
2320
2321 SAddr = SelectSAddrFI(CurDAG, SAddr);
2322
2323 const SIInstrInfo *TII = Subtarget->getInstrInfo();
2324
2325 if (!TII->isLegalFLATOffset(COffsetVal, AMDGPUAS::PRIVATE_ADDRESS,
2326 FlatAddrSpace::FlatScratch)) {
2327 int64_t SplitImmOffset, RemainderOffset;
2328 std::tie(SplitImmOffset, RemainderOffset) = TII->splitFlatOffset(
2329 COffsetVal, AMDGPUAS::PRIVATE_ADDRESS, FlatAddrSpace::FlatScratch);
2330
2331 COffsetVal = SplitImmOffset;
2332
2333 SDValue AddOffset =
2335 ? getMaterializedScalarImm32(Lo_32(RemainderOffset), DL)
2336 : CurDAG->getSignedTargetConstant(RemainderOffset, DL, MVT::i32);
2337 SAddr = SDValue(CurDAG->getMachineNode(AMDGPU::S_ADD_I32, DL, MVT::i32,
2338 SAddr, AddOffset),
2339 0);
2340 }
2341
2342 Offset = CurDAG->getSignedTargetConstant(COffsetVal, DL, MVT::i32);
2343
2344 return true;
2345}
2346
2347// Check whether the flat scratch SVS swizzle bug affects this access.
2348bool AMDGPUDAGToDAGISel::checkFlatScratchSVSSwizzleBug(
2349 SDValue VAddr, SDValue SAddr, uint64_t ImmOffset) const {
2350 if (!Subtarget->hasFlatScratchSVSSwizzleBug())
2351 return false;
2352
2353 // The bug affects the swizzling of SVS accesses if there is any carry out
2354 // from the two low order bits (i.e. from bit 1 into bit 2) when adding
2355 // voffset to (soffset + inst_offset).
2356 KnownBits VKnown = CurDAG->computeKnownBits(VAddr);
2357 KnownBits SKnown =
2358 KnownBits::add(CurDAG->computeKnownBits(SAddr),
2359 KnownBits::makeConstant(APInt(32, ImmOffset,
2360 /*isSigned=*/true)));
2361 uint64_t VMax = VKnown.getMaxValue().getZExtValue();
2363 return (VMax & 3) + (SMax & 3) >= 4;
2364}
2365
2366bool AMDGPUDAGToDAGISel::SelectScratchSVAddr(SDNode *N, SDValue Addr,
2367 SDValue &VAddr, SDValue &SAddr,
2368 SDValue &Offset,
2369 SDValue &CPol) const {
2370 int64_t ImmOffset = 0;
2371
2372 SDValue LHS, RHS;
2373 SDValue OrigAddr = Addr;
2374 if (isBaseWithConstantOffset64(Addr, LHS, RHS)) {
2375 int64_t COffsetVal = cast<ConstantSDNode>(RHS)->getSExtValue();
2376 const SIInstrInfo *TII = Subtarget->getInstrInfo();
2377
2378 if (TII->isLegalFLATOffset(COffsetVal, AMDGPUAS::PRIVATE_ADDRESS,
2380 Addr = LHS;
2381 ImmOffset = COffsetVal;
2382 } else if (!LHS->isDivergent() && COffsetVal > 0) {
2383 SDLoc SL(N);
2384 // saddr + large_offset -> saddr + (vaddr = large_offset & ~MaxOffset) +
2385 // (large_offset & MaxOffset);
2386 int64_t SplitImmOffset, RemainderOffset;
2387 std::tie(SplitImmOffset, RemainderOffset) =
2388 TII->splitFlatOffset(COffsetVal, AMDGPUAS::PRIVATE_ADDRESS,
2390
2391 if (isUInt<32>(RemainderOffset)) {
2392 SDNode *VMov = CurDAG->getMachineNode(
2393 AMDGPU::V_MOV_B32_e32, SL, MVT::i32,
2394 CurDAG->getTargetConstant(RemainderOffset, SDLoc(), MVT::i32));
2395 VAddr = SDValue(VMov, 0);
2396 SAddr = LHS;
2397 if (!isFlatScratchBaseLegal(Addr))
2398 return false;
2399 if (checkFlatScratchSVSSwizzleBug(VAddr, SAddr, SplitImmOffset))
2400 return false;
2401 Offset = CurDAG->getTargetConstant(SplitImmOffset, SDLoc(), MVT::i32);
2402 CPol = CurDAG->getTargetConstant(0, SDLoc(), MVT::i32);
2403 return true;
2404 }
2405 }
2406 }
2407
2408 if (Addr.getOpcode() != ISD::ADD)
2409 return false;
2410
2411 LHS = Addr.getOperand(0);
2412 RHS = Addr.getOperand(1);
2413
2414 if (!LHS->isDivergent() && RHS->isDivergent()) {
2415 SAddr = LHS;
2416 VAddr = RHS;
2417 } else if (!RHS->isDivergent() && LHS->isDivergent()) {
2418 SAddr = RHS;
2419 VAddr = LHS;
2420 } else {
2421 return false;
2422 }
2423
2424 if (OrigAddr != Addr) {
2425 if (!isFlatScratchBaseLegalSVImm(OrigAddr))
2426 return false;
2427 } else {
2428 if (!isFlatScratchBaseLegalSV(OrigAddr))
2429 return false;
2430 }
2431
2432 if (checkFlatScratchSVSSwizzleBug(VAddr, SAddr, ImmOffset))
2433 return false;
2434 SAddr = SelectSAddrFI(CurDAG, SAddr);
2435 Offset = CurDAG->getSignedTargetConstant(ImmOffset, SDLoc(), MVT::i32);
2436
2437 bool ScaleOffset = SelectScaleOffset(N, VAddr, true /* IsSigned */);
2438 CPol = CurDAG->getTargetConstant(ScaleOffset ? AMDGPU::CPol::SCAL : 0,
2439 SDLoc(), MVT::i32);
2440 return true;
2441}
2442
2443// For unbuffered smem loads, it is illegal for the Immediate Offset to be
2444// negative if the resulting (Offset + (M0 or SOffset or zero) is negative.
2445// Handle the case where the Immediate Offset + SOffset is negative.
2446bool AMDGPUDAGToDAGISel::isSOffsetLegalWithImmOffset(SDValue *SOffset,
2447 bool Imm32Only,
2448 bool IsBuffer,
2449 int64_t ImmOffset) const {
2450 if (!IsBuffer && !Imm32Only && ImmOffset < 0 &&
2451 AMDGPU::hasSMRDSignedImmOffset(*Subtarget)) {
2452 KnownBits SKnown = CurDAG->computeKnownBits(*SOffset);
2453 if (ImmOffset + SKnown.getMinValue().getSExtValue() < 0)
2454 return false;
2455 }
2456
2457 return true;
2458}
2459
2460// Given \p Offset and load node \p N check if an \p Offset is a multiple of
2461// the load byte size. If it is update \p Offset to a pre-scaled value and
2462// return true.
2463bool AMDGPUDAGToDAGISel::SelectScaleOffset(SDNode *N, SDValue &Offset,
2464 bool IsSigned) const {
2465 bool ScaleOffset = false;
2466 if (!Subtarget->hasScaleOffset() || !Offset)
2467 return false;
2468
2469 unsigned Size =
2470 (unsigned)cast<MemSDNode>(N)->getMemoryVT().getFixedSizeInBits() / 8;
2471
2472 SDValue Off = Offset;
2473 if (SDValue Ext = matchExtFromI32orI32(Offset, IsSigned, CurDAG))
2474 Off = Ext;
2475
2476 if (isPowerOf2_32(Size) && Off.getOpcode() == ISD::SHL) {
2477 if (auto *C = dyn_cast<ConstantSDNode>(Off.getOperand(1)))
2478 ScaleOffset = C->getZExtValue() == Log2_32(Size);
2479 } else if (Offset.getOpcode() == ISD::MUL ||
2480 (IsSigned && Offset.getOpcode() == AMDGPUISD::MUL_I24) ||
2481 Offset.getOpcode() == AMDGPUISD::MUL_U24 ||
2482 (Offset.isMachineOpcode() &&
2483 Offset.getMachineOpcode() ==
2484 (IsSigned ? AMDGPU::S_MUL_I64_I32_PSEUDO
2485 : AMDGPU::S_MUL_U64_U32_PSEUDO))) {
2486 if (auto *C = dyn_cast<ConstantSDNode>(Offset.getOperand(1)))
2487 ScaleOffset = C->getZExtValue() == Size;
2488 }
2489
2490 if (ScaleOffset)
2491 Offset = Off.getOperand(0);
2492
2493 return ScaleOffset;
2494}
2495
2496// Match an immediate (if Offset is not null) or an SGPR (if SOffset is
2497// not null) offset. If Imm32Only is true, match only 32-bit immediate
2498// offsets available on CI.
2499bool AMDGPUDAGToDAGISel::SelectSMRDOffset(SDNode *N, SDValue ByteOffsetNode,
2500 SDValue *SOffset, SDValue *Offset,
2501 bool Imm32Only, bool IsBuffer,
2502 bool HasSOffset, int64_t ImmOffset,
2503 bool *ScaleOffset) const {
2504 assert((!SOffset || !Offset) &&
2505 "Cannot match both soffset and offset at the same time!");
2506
2507 if (ScaleOffset) {
2508 assert(N && SOffset);
2509
2510 *ScaleOffset = SelectScaleOffset(N, ByteOffsetNode, false /* IsSigned */);
2511 }
2512
2513 ConstantSDNode *C = dyn_cast<ConstantSDNode>(ByteOffsetNode);
2514 if (!C) {
2515 if (!SOffset)
2516 return false;
2517
2518 if (ByteOffsetNode.getValueType().isScalarInteger() &&
2519 ByteOffsetNode.getValueType().getSizeInBits() == 32) {
2520 *SOffset = ByteOffsetNode;
2521 return isSOffsetLegalWithImmOffset(SOffset, Imm32Only, IsBuffer,
2522 ImmOffset);
2523 }
2524 if (ByteOffsetNode.getOpcode() == ISD::ZERO_EXTEND) {
2525 if (ByteOffsetNode.getOperand(0).getValueType().getSizeInBits() == 32) {
2526 *SOffset = ByteOffsetNode.getOperand(0);
2527 return isSOffsetLegalWithImmOffset(SOffset, Imm32Only, IsBuffer,
2528 ImmOffset);
2529 }
2530 }
2531 return false;
2532 }
2533
2534 SDLoc SL(ByteOffsetNode);
2535
2536 // GFX9 and GFX10 have signed byte immediate offsets. The immediate
2537 // offset for S_BUFFER instructions is unsigned.
2538 int64_t ByteOffset = IsBuffer ? C->getZExtValue() : C->getSExtValue();
2539 std::optional<int64_t> EncodedOffset = AMDGPU::getSMRDEncodedOffset(
2540 *Subtarget, ByteOffset, IsBuffer, HasSOffset);
2541 if (EncodedOffset && Offset && !Imm32Only) {
2542 *Offset = CurDAG->getSignedTargetConstant(*EncodedOffset, SL, MVT::i32);
2543 return true;
2544 }
2545
2546 // SGPR and literal offsets are unsigned.
2547 if (ByteOffset < 0)
2548 return false;
2549
2550 EncodedOffset = AMDGPU::getSMRDEncodedLiteralOffset32(*Subtarget, ByteOffset);
2551 if (EncodedOffset && Offset && Imm32Only) {
2552 *Offset = CurDAG->getTargetConstant(*EncodedOffset, SL, MVT::i32);
2553 return true;
2554 }
2555
2556 if (!isUInt<32>(ByteOffset) && !isInt<32>(ByteOffset))
2557 return false;
2558
2559 if (SOffset) {
2560 SDValue C32Bit = CurDAG->getTargetConstant(ByteOffset, SL, MVT::i32);
2561 *SOffset = SDValue(
2562 CurDAG->getMachineNode(AMDGPU::S_MOV_B32, SL, MVT::i32, C32Bit), 0);
2563 return true;
2564 }
2565
2566 return false;
2567}
2568
2569SDValue AMDGPUDAGToDAGISel::Expand32BitAddress(SDValue Addr) const {
2570 if (Addr.getValueType() != MVT::i32)
2571 return Addr;
2572
2573 // Zero-extend a 32-bit address.
2574 SDLoc SL(Addr);
2575
2576 const MachineFunction &MF = CurDAG->getMachineFunction();
2577 const SIMachineFunctionInfo *Info = MF.getInfo<SIMachineFunctionInfo>();
2578 unsigned AddrHiVal = Info->get32BitAddressHighBits();
2579 SDValue AddrHi = CurDAG->getTargetConstant(AddrHiVal, SL, MVT::i32);
2580
2581 const SDValue Ops[] = {
2582 CurDAG->getTargetConstant(AMDGPU::SReg_64_XEXECRegClassID, SL, MVT::i32),
2583 Addr,
2584 CurDAG->getTargetConstant(AMDGPU::sub0, SL, MVT::i32),
2585 SDValue(CurDAG->getMachineNode(AMDGPU::S_MOV_B32, SL, MVT::i32, AddrHi),
2586 0),
2587 CurDAG->getTargetConstant(AMDGPU::sub1, SL, MVT::i32),
2588 };
2589
2590 return SDValue(CurDAG->getMachineNode(AMDGPU::REG_SEQUENCE, SL, MVT::i64,
2591 Ops), 0);
2592}
2593
2594// Match a base and an immediate (if Offset is not null) or an SGPR (if
2595// SOffset is not null) or an immediate+SGPR offset. If Imm32Only is
2596// true, match only 32-bit immediate offsets available on CI.
2597bool AMDGPUDAGToDAGISel::SelectSMRDBaseOffset(SDNode *N, SDValue Addr,
2598 SDValue &SBase, SDValue *SOffset,
2599 SDValue *Offset, bool Imm32Only,
2600 bool IsBuffer, bool HasSOffset,
2601 int64_t ImmOffset,
2602 bool *ScaleOffset) const {
2603 if (SOffset && Offset) {
2604 assert(!Imm32Only && !IsBuffer);
2605 SDValue B;
2606
2607 if (!SelectSMRDBaseOffset(N, Addr, B, nullptr, Offset, false, false, true))
2608 return false;
2609
2610 int64_t ImmOff = 0;
2611 if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(*Offset))
2612 ImmOff = C->getSExtValue();
2613
2614 return SelectSMRDBaseOffset(N, B, SBase, SOffset, nullptr, false, false,
2615 true, ImmOff, ScaleOffset);
2616 }
2617
2618 // A 32-bit (address + offset) should not cause unsigned 32-bit integer
2619 // wraparound, because s_load instructions perform the addition in 64 bits.
2620 if (Addr.getValueType() == MVT::i32 && Addr.getOpcode() == ISD::ADD &&
2621 !Addr->getFlags().hasNoUnsignedWrap())
2622 return false;
2623
2624 SDValue N0, N1;
2625 // Extract the base and offset if possible.
2626 if (Addr->isAnyAdd() || CurDAG->isADDLike(Addr)) {
2627 N0 = Addr.getOperand(0);
2628 N1 = Addr.getOperand(1);
2629 } else if (getBaseWithOffsetUsingSplitOR(*CurDAG, Addr, N0, N1)) {
2630 assert(N0 && N1 && isa<ConstantSDNode>(N1));
2631 }
2632 if (!N0 || !N1)
2633 return false;
2634
2635 if (SelectSMRDOffset(N, N1, SOffset, Offset, Imm32Only, IsBuffer, HasSOffset,
2636 ImmOffset, ScaleOffset)) {
2637 SBase = N0;
2638 return true;
2639 }
2640 if (SelectSMRDOffset(N, N0, SOffset, Offset, Imm32Only, IsBuffer, HasSOffset,
2641 ImmOffset, ScaleOffset)) {
2642 SBase = N1;
2643 return true;
2644 }
2645 return false;
2646}
2647
2648bool AMDGPUDAGToDAGISel::SelectSMRD(SDNode *N, SDValue Addr, SDValue &SBase,
2649 SDValue *SOffset, SDValue *Offset,
2650 bool Imm32Only, bool *ScaleOffset) const {
2651 if (SelectSMRDBaseOffset(N, Addr, SBase, SOffset, Offset, Imm32Only,
2652 /* IsBuffer */ false, /* HasSOffset */ false,
2653 /* ImmOffset */ 0, ScaleOffset)) {
2654 SBase = Expand32BitAddress(SBase);
2655 return true;
2656 }
2657
2658 if (Addr.getValueType() == MVT::i32 && Offset && !SOffset) {
2659 SBase = Expand32BitAddress(Addr);
2660 *Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32);
2661 return true;
2662 }
2663
2664 return false;
2665}
2666
2667bool AMDGPUDAGToDAGISel::SelectSMRDImm(SDValue Addr, SDValue &SBase,
2668 SDValue &Offset) const {
2669 return SelectSMRD(/* N */ nullptr, Addr, SBase, /* SOffset */ nullptr,
2670 &Offset);
2671}
2672
2673bool AMDGPUDAGToDAGISel::SelectSMRDImm32(SDValue Addr, SDValue &SBase,
2674 SDValue &Offset) const {
2675 assert(Subtarget->getGeneration() == AMDGPUSubtarget::SEA_ISLANDS);
2676 return SelectSMRD(/* N */ nullptr, Addr, SBase, /* SOffset */ nullptr,
2677 &Offset, /* Imm32Only */ true);
2678}
2679
2680bool AMDGPUDAGToDAGISel::SelectSMRDSgpr(SDNode *N, SDValue Addr, SDValue &SBase,
2681 SDValue &SOffset, SDValue &CPol) const {
2682 bool ScaleOffset;
2683 if (!SelectSMRD(N, Addr, SBase, &SOffset, /* Offset */ nullptr,
2684 /* Imm32Only */ false, &ScaleOffset))
2685 return false;
2686
2687 CPol = CurDAG->getTargetConstant(ScaleOffset ? AMDGPU::CPol::SCAL : 0,
2688 SDLoc(N), MVT::i32);
2689 return true;
2690}
2691
2692bool AMDGPUDAGToDAGISel::SelectSMRDSgprImm(SDNode *N, SDValue Addr,
2693 SDValue &SBase, SDValue &SOffset,
2694 SDValue &Offset,
2695 SDValue &CPol) const {
2696 bool ScaleOffset;
2697 if (!SelectSMRD(N, Addr, SBase, &SOffset, &Offset, false, &ScaleOffset))
2698 return false;
2699
2700 CPol = CurDAG->getTargetConstant(ScaleOffset ? AMDGPU::CPol::SCAL : 0,
2701 SDLoc(N), MVT::i32);
2702 return true;
2703}
2704
2705bool AMDGPUDAGToDAGISel::SelectSMRDBufferImm(SDValue N, SDValue &Offset) const {
2706 return SelectSMRDOffset(/* N */ nullptr, N, /* SOffset */ nullptr, &Offset,
2707 /* Imm32Only */ false, /* IsBuffer */ true);
2708}
2709
2710bool AMDGPUDAGToDAGISel::SelectSMRDBufferImm32(SDValue N,
2711 SDValue &Offset) const {
2712 assert(Subtarget->getGeneration() == AMDGPUSubtarget::SEA_ISLANDS);
2713 return SelectSMRDOffset(/* N */ nullptr, N, /* SOffset */ nullptr, &Offset,
2714 /* Imm32Only */ true, /* IsBuffer */ true);
2715}
2716
2717bool AMDGPUDAGToDAGISel::SelectSMRDBufferSgprImm(SDValue N, SDValue &SOffset,
2718 SDValue &Offset) const {
2719 // Match the (soffset + offset) pair as a 32-bit register base and
2720 // an immediate offset.
2721 return N.getValueType() == MVT::i32 &&
2722 SelectSMRDBaseOffset(/* N */ nullptr, N, /* SBase */ SOffset,
2723 /* SOffset*/ nullptr, &Offset,
2724 /* Imm32Only */ false, /* IsBuffer */ true);
2725}
2726
2727bool AMDGPUDAGToDAGISel::SelectMOVRELOffset(SDValue Index,
2728 SDValue &Base,
2729 SDValue &Offset) const {
2730 SDLoc DL(Index);
2731
2732 if (CurDAG->isBaseWithConstantOffset(Index)) {
2733 SDValue N0 = Index.getOperand(0);
2734 SDValue N1 = Index.getOperand(1);
2735 ConstantSDNode *C1 = cast<ConstantSDNode>(N1);
2736
2737 // (add n0, c0)
2738 // Don't peel off the offset (c0) if doing so could possibly lead
2739 // the base (n0) to be negative.
2740 // (or n0, |c0|) can never change a sign given isBaseWithConstantOffset.
2741 if (C1->getSExtValue() <= 0 || CurDAG->SignBitIsZero(N0) ||
2742 (Index->getOpcode() == ISD::OR && C1->getSExtValue() >= 0)) {
2743 Base = N0;
2744 Offset = CurDAG->getTargetConstant(C1->getZExtValue(), DL, MVT::i32);
2745 return true;
2746 }
2747 }
2748
2749 if (isa<ConstantSDNode>(Index))
2750 return false;
2751
2752 Base = Index;
2753 Offset = CurDAG->getTargetConstant(0, DL, MVT::i32);
2754 return true;
2755}
2756
2757SDNode *AMDGPUDAGToDAGISel::getBFE32(bool IsSigned, const SDLoc &DL,
2758 SDValue Val, uint32_t Offset,
2759 uint32_t Width) {
2760 if (Val->isDivergent()) {
2761 unsigned Opcode = IsSigned ? AMDGPU::V_BFE_I32_e64 : AMDGPU::V_BFE_U32_e64;
2762 SDValue Off = CurDAG->getTargetConstant(Offset, DL, MVT::i32);
2763 SDValue W = CurDAG->getTargetConstant(Width, DL, MVT::i32);
2764
2765 return CurDAG->getMachineNode(Opcode, DL, MVT::i32, Val, Off, W);
2766 }
2767 unsigned Opcode = IsSigned ? AMDGPU::S_BFE_I32 : AMDGPU::S_BFE_U32;
2768 // Transformation function, pack the offset and width of a BFE into
2769 // the format expected by the S_BFE_I32 / S_BFE_U32. In the second
2770 // source, bits [5:0] contain the offset and bits [22:16] the width.
2771 uint32_t PackedVal = Offset | (Width << 16);
2772 SDValue PackedConst = CurDAG->getTargetConstant(PackedVal, DL, MVT::i32);
2773
2774 return CurDAG->getMachineNode(Opcode, DL, MVT::i32, Val, PackedConst);
2775}
2776
2777void AMDGPUDAGToDAGISel::SelectS_BFEFromShifts(SDNode *N) {
2778 // "(a << b) srl c)" ---> "BFE_U32 a, (c-b), (32-c)
2779 // "(a << b) sra c)" ---> "BFE_I32 a, (c-b), (32-c)
2780 // Predicate: 0 < b <= c < 32
2781
2782 const SDValue &Shl = N->getOperand(0);
2783 ConstantSDNode *B = dyn_cast<ConstantSDNode>(Shl->getOperand(1));
2784 ConstantSDNode *C = dyn_cast<ConstantSDNode>(N->getOperand(1));
2785
2786 if (B && C) {
2787 uint32_t BVal = B->getZExtValue();
2788 uint32_t CVal = C->getZExtValue();
2789
2790 if (0 < BVal && BVal <= CVal && CVal < 32) {
2791 bool Signed = N->getOpcode() == ISD::SRA;
2792 ReplaceNode(N, getBFE32(Signed, SDLoc(N), Shl.getOperand(0), CVal - BVal,
2793 32 - CVal));
2794 return;
2795 }
2796 }
2797 SelectCode(N);
2798}
2799
2800void AMDGPUDAGToDAGISel::SelectS_BFE(SDNode *N) {
2801 switch (N->getOpcode()) {
2802 case ISD::AND:
2803 if (N->getOperand(0).getOpcode() == ISD::SRL) {
2804 // "(a srl b) & mask" ---> "BFE_U32 a, b, popcount(mask)"
2805 // Predicate: isMask(mask)
2806 const SDValue &Srl = N->getOperand(0);
2807 ConstantSDNode *Shift = dyn_cast<ConstantSDNode>(Srl.getOperand(1));
2808 ConstantSDNode *Mask = dyn_cast<ConstantSDNode>(N->getOperand(1));
2809
2810 if (Shift && Mask) {
2811 uint32_t ShiftVal = Shift->getZExtValue();
2812 uint32_t MaskVal = Mask->getZExtValue();
2813
2814 if (isMask_32(MaskVal)) {
2815 uint32_t WidthVal = llvm::popcount(MaskVal);
2816 ReplaceNode(N, getBFE32(false, SDLoc(N), Srl.getOperand(0), ShiftVal,
2817 WidthVal));
2818 return;
2819 }
2820 }
2821 }
2822 break;
2823 case ISD::SRL:
2824 if (N->getOperand(0).getOpcode() == ISD::AND) {
2825 // "(a & mask) srl b)" ---> "BFE_U32 a, b, popcount(mask >> b)"
2826 // Predicate: isMask(mask >> b)
2827 const SDValue &And = N->getOperand(0);
2828 ConstantSDNode *Shift = dyn_cast<ConstantSDNode>(N->getOperand(1));
2829 ConstantSDNode *Mask = dyn_cast<ConstantSDNode>(And->getOperand(1));
2830
2831 if (Shift && Mask) {
2832 uint32_t ShiftVal = Shift->getZExtValue();
2833 uint32_t MaskVal = Mask->getZExtValue() >> ShiftVal;
2834
2835 if (isMask_32(MaskVal)) {
2836 uint32_t WidthVal = llvm::popcount(MaskVal);
2837 ReplaceNode(N, getBFE32(false, SDLoc(N), And.getOperand(0), ShiftVal,
2838 WidthVal));
2839 return;
2840 }
2841 }
2842 } else if (N->getOperand(0).getOpcode() == ISD::SHL) {
2843 SelectS_BFEFromShifts(N);
2844 return;
2845 }
2846 break;
2847 case ISD::SRA:
2848 if (N->getOperand(0).getOpcode() == ISD::SHL) {
2849 SelectS_BFEFromShifts(N);
2850 return;
2851 }
2852 break;
2853
2855 // sext_inreg (srl x, 16), i8 -> bfe_i32 x, 16, 8
2856 SDValue Src = N->getOperand(0);
2857 if (Src.getOpcode() != ISD::SRL)
2858 break;
2859
2860 const ConstantSDNode *Amt = dyn_cast<ConstantSDNode>(Src.getOperand(1));
2861 if (!Amt)
2862 break;
2863
2864 unsigned Width = cast<VTSDNode>(N->getOperand(1))->getVT().getSizeInBits();
2865 ReplaceNode(N, getBFE32(true, SDLoc(N), Src.getOperand(0),
2866 Amt->getZExtValue(), Width));
2867 return;
2868 }
2869 }
2870
2871 SelectCode(N);
2872}
2873
2874bool AMDGPUDAGToDAGISel::isCBranchSCC(const SDNode *N) const {
2875 assert(N->getOpcode() == ISD::BRCOND);
2876 if (!N->hasOneUse())
2877 return false;
2878
2879 SDValue Cond = N->getOperand(1);
2880 if (Cond.getOpcode() == ISD::CopyToReg)
2881 Cond = Cond.getOperand(2);
2882
2883 if (Cond.getOpcode() != ISD::SETCC || !Cond.hasOneUse())
2884 return false;
2885
2886 MVT VT = Cond.getOperand(0).getSimpleValueType();
2887 if (VT == MVT::i32)
2888 return true;
2889
2890 if (VT == MVT::i64) {
2891 ISD::CondCode CC = cast<CondCodeSDNode>(Cond.getOperand(2))->get();
2892 return (CC == ISD::SETEQ || CC == ISD::SETNE) &&
2893 Subtarget->hasScalarCompareEq64();
2894 }
2895
2896 if ((VT == MVT::f16 || VT == MVT::f32) && Subtarget->hasSALUFloatInsts())
2897 return true;
2898
2899 return false;
2900}
2901
2902static SDValue combineBallotPattern(SDValue VCMP, bool &Negate) {
2903 assert(VCMP->getOpcode() == AMDGPUISD::SETCC);
2904 // Special case for amdgcn.ballot:
2905 // %Cond = i1 (and/or combination of i1 ISD::SETCCs)
2906 // %VCMP = i(WaveSize) AMDGPUISD::SETCC (ext %Cond), 0, setne/seteq
2907 // =>
2908 // Use i1 %Cond value instead of i(WaveSize) %VCMP.
2909 // This is possible because divergent ISD::SETCC is selected as V_CMP and
2910 // Cond becomes a i(WaveSize) full mask value.
2911 // Note that ballot doesn't use SETEQ condition but its easy to support it
2912 // here for completeness, so in this case Negate is set true on return.
2913 auto VCMP_CC = cast<CondCodeSDNode>(VCMP.getOperand(2))->get();
2914 if ((VCMP_CC == ISD::SETEQ || VCMP_CC == ISD::SETNE) &&
2915 isNullConstant(VCMP.getOperand(1))) {
2916
2917 auto Cond = VCMP.getOperand(0);
2918 if (ISD::isExtOpcode(Cond->getOpcode())) // Skip extension.
2919 Cond = Cond.getOperand(0);
2920
2921 if (isBoolSGPR(Cond)) {
2922 Negate = VCMP_CC == ISD::SETEQ;
2923 return Cond;
2924 }
2925 }
2926 return SDValue();
2927}
2928
2929void AMDGPUDAGToDAGISel::SelectBRCOND(SDNode *N) {
2930 SDValue Cond = N->getOperand(1);
2931
2932 if (Cond.isUndef()) {
2933 CurDAG->SelectNodeTo(N, AMDGPU::SI_BR_UNDEF, MVT::Other,
2934 N->getOperand(2), N->getOperand(0));
2935 return;
2936 }
2937
2938 const SIRegisterInfo *TRI = Subtarget->getRegisterInfo();
2939
2940 bool UseSCCBr = isCBranchSCC(N) && isUniformBr(N);
2941 bool AndExec = !UseSCCBr;
2942 bool Negate = false;
2943
2944 if (Cond.getOpcode() == ISD::SETCC &&
2945 Cond->getOperand(0)->getOpcode() == AMDGPUISD::SETCC) {
2946 SDValue VCMP = Cond->getOperand(0);
2947 auto CC = cast<CondCodeSDNode>(Cond->getOperand(2))->get();
2948 if ((CC == ISD::SETEQ || CC == ISD::SETNE) &&
2949 isNullConstant(Cond->getOperand(1)) &&
2950 // We may encounter ballot.i64 in wave32 mode on -O0.
2951 VCMP.getValueType().getSizeInBits() == Subtarget->getWavefrontSize()) {
2952 // %VCMP = i(WaveSize) AMDGPUISD::SETCC ...
2953 // %C = i1 ISD::SETCC %VCMP, 0, setne/seteq
2954 // BRCOND i1 %C, %BB
2955 // =>
2956 // %VCMP = i(WaveSize) AMDGPUISD::SETCC ...
2957 // VCC = COPY i(WaveSize) %VCMP
2958 // S_CBRANCH_VCCNZ/VCCZ %BB
2959 Negate = CC == ISD::SETEQ;
2960 bool NegatedBallot = false;
2961 if (auto BallotCond = combineBallotPattern(VCMP, NegatedBallot)) {
2962 Cond = BallotCond;
2963 UseSCCBr = !BallotCond->isDivergent();
2964 Negate = Negate ^ NegatedBallot;
2965 } else {
2966 // TODO: don't use SCC here assuming that AMDGPUISD::SETCC is always
2967 // selected as V_CMP, but this may change for uniform condition.
2968 Cond = VCMP;
2969 UseSCCBr = false;
2970 }
2971 }
2972 // Cond is either V_CMP resulted from AMDGPUISD::SETCC or a combination of
2973 // V_CMPs resulted from ballot or ballot has uniform condition and SCC is
2974 // used.
2975 AndExec = false;
2976 }
2977
2978 unsigned BrOp =
2979 UseSCCBr ? (Negate ? AMDGPU::S_CBRANCH_SCC0 : AMDGPU::S_CBRANCH_SCC1)
2980 : (Negate ? AMDGPU::S_CBRANCH_VCCZ : AMDGPU::S_CBRANCH_VCCNZ);
2981 Register CondReg = UseSCCBr ? AMDGPU::SCC : TRI->getVCC();
2982 SDLoc SL(N);
2983
2984 if (AndExec) {
2985 // This is the case that we are selecting to S_CBRANCH_VCCNZ. We have not
2986 // analyzed what generates the vcc value, so we do not know whether vcc
2987 // bits for disabled lanes are 0. Thus we need to mask out bits for
2988 // disabled lanes.
2989 //
2990 // For the case that we select S_CBRANCH_SCC1 and it gets
2991 // changed to S_CBRANCH_VCCNZ in SIFixSGPRCopies, SIFixSGPRCopies calls
2992 // SIInstrInfo::moveToVALU which inserts the S_AND).
2993 //
2994 // We could add an analysis of what generates the vcc value here and omit
2995 // the S_AND when is unnecessary. But it would be better to add a separate
2996 // pass after SIFixSGPRCopies to do the unnecessary S_AND removal, so it
2997 // catches both cases.
2998 Cond = SDValue(
2999 CurDAG->getMachineNode(
3000 Subtarget->isWave32() ? AMDGPU::S_AND_B32 : AMDGPU::S_AND_B64, SL,
3001 MVT::i1,
3002 CurDAG->getRegister(Subtarget->isWave32() ? AMDGPU::EXEC_LO
3003 : AMDGPU::EXEC,
3004 MVT::i1),
3005 Cond),
3006 0);
3007 }
3008
3009 SDValue VCC = CurDAG->getCopyToReg(N->getOperand(0), SL, CondReg, Cond);
3010 CurDAG->SelectNodeTo(N, BrOp, MVT::Other,
3011 N->getOperand(2), // Basic Block
3012 VCC.getValue(0));
3013}
3014
3015void AMDGPUDAGToDAGISel::SelectFP_EXTEND(SDNode *N) {
3016 if (Subtarget->hasSALUFloatInsts() && N->getValueType(0) == MVT::f32 &&
3017 !N->isDivergent()) {
3018 SDValue Src = N->getOperand(0);
3019 if (Src.getValueType() == MVT::f16) {
3020 if (isExtractHiElt(Src, Src)) {
3021 CurDAG->SelectNodeTo(N, AMDGPU::S_CVT_HI_F32_F16, N->getVTList(),
3022 {Src});
3023 return;
3024 }
3025 }
3026 }
3027
3028 SelectCode(N);
3029}
3030
3031void AMDGPUDAGToDAGISel::SelectDSAppendConsume(SDNode *N, unsigned IntrID) {
3032 // The address is assumed to be uniform, so if it ends up in a VGPR, it will
3033 // be copied to an SGPR with readfirstlane.
3034 unsigned Opc = IntrID == Intrinsic::amdgcn_ds_append ?
3035 AMDGPU::DS_APPEND : AMDGPU::DS_CONSUME;
3036
3037 SDValue Chain = N->getOperand(0);
3038 SDValue Ptr = N->getOperand(2);
3039 MemIntrinsicSDNode *M = cast<MemIntrinsicSDNode>(N);
3040 MachineMemOperand *MMO = M->getMemOperand();
3041 bool IsGDS = M->getAddressSpace() == AMDGPUAS::REGION_ADDRESS;
3042
3043 SDValue Offset;
3044 if (CurDAG->isBaseWithConstantOffset(Ptr)) {
3045 SDValue PtrBase = Ptr.getOperand(0);
3046 SDValue PtrOffset = Ptr.getOperand(1);
3047
3048 const APInt &OffsetVal = PtrOffset->getAsAPIntVal();
3049 if (isDSOffsetLegal(PtrBase, OffsetVal.getZExtValue())) {
3050 N = glueCopyToM0(N, PtrBase);
3051 Offset = CurDAG->getTargetConstant(OffsetVal, SDLoc(), MVT::i32);
3052 }
3053 }
3054
3055 if (!Offset) {
3056 N = glueCopyToM0(N, Ptr);
3057 Offset = CurDAG->getTargetConstant(0, SDLoc(), MVT::i32);
3058 }
3059
3060 SDValue Ops[] = {
3061 Offset,
3062 CurDAG->getTargetConstant(IsGDS, SDLoc(), MVT::i32),
3063 Chain,
3064 N->getOperand(N->getNumOperands() - 1) // New glue
3065 };
3066
3067 SDNode *Selected = CurDAG->SelectNodeTo(N, Opc, N->getVTList(), Ops);
3068 CurDAG->setNodeMemRefs(cast<MachineSDNode>(Selected), {MMO});
3069}
3070
3071// We need to handle this here because tablegen doesn't support matching
3072// instructions with multiple outputs.
3073void AMDGPUDAGToDAGISel::SelectDSBvhStackIntrinsic(SDNode *N, unsigned IntrID) {
3074 unsigned Opc;
3075 switch (IntrID) {
3076 case Intrinsic::amdgcn_ds_bvh_stack_rtn:
3077 case Intrinsic::amdgcn_ds_bvh_stack_push4_pop1_rtn:
3078 Opc = AMDGPU::DS_BVH_STACK_RTN_B32;
3079 break;
3080 case Intrinsic::amdgcn_ds_bvh_stack_push8_pop1_rtn:
3081 Opc = AMDGPU::DS_BVH_STACK_PUSH8_POP1_RTN_B32;
3082 break;
3083 case Intrinsic::amdgcn_ds_bvh_stack_push8_pop2_rtn:
3084 Opc = AMDGPU::DS_BVH_STACK_PUSH8_POP2_RTN_B64;
3085 break;
3086 }
3087 SDValue Ops[] = {N->getOperand(2), N->getOperand(3), N->getOperand(4),
3088 N->getOperand(5), N->getOperand(0)};
3089
3090 MemIntrinsicSDNode *M = cast<MemIntrinsicSDNode>(N);
3091 MachineMemOperand *MMO = M->getMemOperand();
3092 SDNode *Selected = CurDAG->SelectNodeTo(N, Opc, N->getVTList(), Ops);
3093 CurDAG->setNodeMemRefs(cast<MachineSDNode>(Selected), {MMO});
3094}
3095
3096void AMDGPUDAGToDAGISel::SelectTensorLoadStore(SDNode *N, unsigned IntrID) {
3097 bool IsLoad = IntrID == Intrinsic::amdgcn_tensor_load_to_lds;
3098 unsigned Opc =
3099 IsLoad ? AMDGPU::TENSOR_LOAD_TO_LDS_d4 : AMDGPU::TENSOR_STORE_FROM_LDS_d4;
3100
3101 SmallVector<SDValue, 7> TensorOps;
3102 // First two groups
3103 TensorOps.push_back(N->getOperand(2)); // D# group 0
3104 TensorOps.push_back(N->getOperand(3)); // D# group 1
3105
3106 // Use _D2 version if both group 2 and 3 are zero-initialized.
3107 SDValue Group2 = N->getOperand(4);
3108 SDValue Group3 = N->getOperand(5);
3109 if (ISD::isBuildVectorAllZeros(Group2.getNode()) &&
3111 Opc = IsLoad ? AMDGPU::TENSOR_LOAD_TO_LDS_d2
3112 : AMDGPU::TENSOR_STORE_FROM_LDS_d2;
3113 } else { // Has at least 4 groups
3114 TensorOps.push_back(Group2); // D# group 2
3115 TensorOps.push_back(Group3); // D# group 3
3116 }
3117
3118 // TODO: Handle the fifth group: N->getOperand(6), which is silently ignored
3119 // for now because all existing targets only support up to 4 groups.
3120 TensorOps.push_back(CurDAG->getTargetConstant(0, SDLoc(N), MVT::i1)); // r128
3121 TensorOps.push_back(N->getOperand(7)); // cache policy
3122 TensorOps.push_back(N->getOperand(0)); // chain
3123
3124 (void)CurDAG->SelectNodeTo(N, Opc, MVT::Other, TensorOps);
3125}
3126
3127static unsigned gwsIntrinToOpcode(unsigned IntrID) {
3128 switch (IntrID) {
3129 case Intrinsic::amdgcn_ds_gws_init:
3130 return AMDGPU::DS_GWS_INIT;
3131 case Intrinsic::amdgcn_ds_gws_barrier:
3132 return AMDGPU::DS_GWS_BARRIER;
3133 case Intrinsic::amdgcn_ds_gws_sema_v:
3134 return AMDGPU::DS_GWS_SEMA_V;
3135 case Intrinsic::amdgcn_ds_gws_sema_br:
3136 return AMDGPU::DS_GWS_SEMA_BR;
3137 case Intrinsic::amdgcn_ds_gws_sema_p:
3138 return AMDGPU::DS_GWS_SEMA_P;
3139 case Intrinsic::amdgcn_ds_gws_sema_release_all:
3140 return AMDGPU::DS_GWS_SEMA_RELEASE_ALL;
3141 default:
3142 llvm_unreachable("not a gws intrinsic");
3143 }
3144}
3145
3146void AMDGPUDAGToDAGISel::SelectDS_GWS(SDNode *N, unsigned IntrID) {
3147 if (!Subtarget->hasGWS() ||
3148 (IntrID == Intrinsic::amdgcn_ds_gws_sema_release_all &&
3149 !Subtarget->hasGWSSemaReleaseAll())) {
3150 // Let this error.
3151 SelectCode(N);
3152 return;
3153 }
3154
3155 // Chain, intrinsic ID, vsrc, offset
3156 const bool HasVSrc = N->getNumOperands() == 4;
3157 assert(HasVSrc || N->getNumOperands() == 3);
3158
3159 SDLoc SL(N);
3160 SDValue BaseOffset = N->getOperand(HasVSrc ? 3 : 2);
3161 int ImmOffset = 0;
3162 MemIntrinsicSDNode *M = cast<MemIntrinsicSDNode>(N);
3163 MachineMemOperand *MMO = M->getMemOperand();
3164
3165 // Don't worry if the offset ends up in a VGPR. Only one lane will have
3166 // effect, so SIFixSGPRCopies will validly insert readfirstlane.
3167
3168 // The resource id offset is computed as (<isa opaque base> + M0[21:16] +
3169 // offset field) % 64. Some versions of the programming guide omit the m0
3170 // part, or claim it's from offset 0.
3171 if (ConstantSDNode *ConstOffset = dyn_cast<ConstantSDNode>(BaseOffset)) {
3172 // If we have a constant offset, try to use the 0 in m0 as the base.
3173 // TODO: Look into changing the default m0 initialization value. If the
3174 // default -1 only set the low 16-bits, we could leave it as-is and add 1 to
3175 // the immediate offset.
3176 glueCopyToM0(N, CurDAG->getTargetConstant(0, SL, MVT::i32));
3177 ImmOffset = ConstOffset->getZExtValue();
3178 } else {
3179 if (CurDAG->isBaseWithConstantOffset(BaseOffset)) {
3180 ImmOffset = BaseOffset.getConstantOperandVal(1);
3181 BaseOffset = BaseOffset.getOperand(0);
3182 }
3183
3184 // Prefer to do the shift in an SGPR since it should be possible to use m0
3185 // as the result directly. If it's already an SGPR, it will be eliminated
3186 // later.
3187 SDNode *SGPROffset
3188 = CurDAG->getMachineNode(AMDGPU::V_READFIRSTLANE_B32, SL, MVT::i32,
3189 BaseOffset);
3190 // Shift to offset in m0
3191 SDNode *M0Base
3192 = CurDAG->getMachineNode(AMDGPU::S_LSHL_B32, SL, MVT::i32,
3193 SDValue(SGPROffset, 0),
3194 CurDAG->getTargetConstant(16, SL, MVT::i32));
3195 glueCopyToM0(N, SDValue(M0Base, 0));
3196 }
3197
3198 SDValue Chain = N->getOperand(0);
3199 SDValue OffsetField = CurDAG->getTargetConstant(ImmOffset, SL, MVT::i32);
3200
3201 const unsigned Opc = gwsIntrinToOpcode(IntrID);
3202
3203 const MCInstrDesc &InstrDesc = TII->get(Opc);
3204 int Data0Idx = AMDGPU::getNamedOperandIdx(Opc, AMDGPU::OpName::data0);
3205
3206 const TargetRegisterClass *DataRC = TII->getRegClass(InstrDesc, Data0Idx);
3207
3209 if (HasVSrc) {
3210 const SIRegisterInfo *TRI = Subtarget->getRegisterInfo();
3211
3212 SDValue Data = N->getOperand(2);
3213 MVT DataVT = Data.getValueType().getSimpleVT();
3214 if (TRI->isTypeLegalForClass(*DataRC, DataVT)) {
3215 // Normal 32-bit case.
3216 Ops.push_back(N->getOperand(2));
3217 } else {
3218 // Operand is really 32-bits, but requires 64-bit alignment, so use the
3219 // even aligned 64-bit register class.
3220 const SDValue RegSeqOps[] = {
3221 CurDAG->getTargetConstant(DataRC->getID(), SL, MVT::i32), Data,
3222 CurDAG->getTargetConstant(AMDGPU::sub0, SL, MVT::i32),
3223 SDValue(
3224 CurDAG->getMachineNode(TargetOpcode::IMPLICIT_DEF, SL, MVT::i32),
3225 0),
3226 CurDAG->getTargetConstant(AMDGPU::sub1, SL, MVT::i32)};
3227
3228 Ops.push_back(SDValue(CurDAG->getMachineNode(TargetOpcode::REG_SEQUENCE,
3229 SL, MVT::v2i32, RegSeqOps),
3230 0));
3231 }
3232 }
3233
3234 Ops.push_back(OffsetField);
3235 Ops.push_back(Chain);
3236
3237 SDNode *Selected = CurDAG->SelectNodeTo(N, Opc, N->getVTList(), Ops);
3238 CurDAG->setNodeMemRefs(cast<MachineSDNode>(Selected), {MMO});
3239}
3240
3241void AMDGPUDAGToDAGISel::SelectInterpP1F16(SDNode *N) {
3242 if (Subtarget->getLDSBankCount() != 16) {
3243 // This is a single instruction with a pattern.
3244 SelectCode(N);
3245 return;
3246 }
3247
3248 SDLoc DL(N);
3249
3250 // This requires 2 instructions. It is possible to write a pattern to support
3251 // this, but the generated isel emitter doesn't correctly deal with multiple
3252 // output instructions using the same physical register input. The copy to m0
3253 // is incorrectly placed before the second instruction.
3254 //
3255 // TODO: Match source modifiers.
3256 //
3257 // def : Pat <
3258 // (int_amdgcn_interp_p1_f16
3259 // (VOP3Mods f32:$src0, i32:$src0_modifiers),
3260 // (i32 timm:$attrchan), (i32 timm:$attr),
3261 // (i1 timm:$high), M0),
3262 // (V_INTERP_P1LV_F16 $src0_modifiers, VGPR_32:$src0, timm:$attr,
3263 // timm:$attrchan, 0,
3264 // (V_INTERP_MOV_F32 2, timm:$attr, timm:$attrchan), timm:$high)> {
3265 // let Predicates = [has16BankLDS];
3266 // }
3267
3268 // 16 bank LDS
3269 SDValue ToM0 = CurDAG->getCopyToReg(CurDAG->getEntryNode(), DL, AMDGPU::M0,
3270 N->getOperand(5), SDValue());
3271
3272 SDVTList VTs = CurDAG->getVTList(MVT::f32, MVT::Other);
3273
3274 SDNode *InterpMov =
3275 CurDAG->getMachineNode(AMDGPU::V_INTERP_MOV_F32, DL, VTs, {
3276 CurDAG->getTargetConstant(2, DL, MVT::i32), // P0
3277 N->getOperand(3), // Attr
3278 N->getOperand(2), // Attrchan
3279 ToM0.getValue(1) // In glue
3280 });
3281
3282 SDNode *InterpP1LV =
3283 CurDAG->getMachineNode(AMDGPU::V_INTERP_P1LV_F16, DL, MVT::f32, {
3284 CurDAG->getTargetConstant(0, DL, MVT::i32), // $src0_modifiers
3285 N->getOperand(1), // Src0
3286 N->getOperand(3), // Attr
3287 N->getOperand(2), // Attrchan
3288 CurDAG->getTargetConstant(0, DL, MVT::i32), // $src2_modifiers
3289 SDValue(InterpMov, 0), // Src2 - holds two f16 values selected by high
3290 N->getOperand(4), // high
3291 CurDAG->getTargetConstant(0, DL, MVT::i1), // $clamp
3292 CurDAG->getTargetConstant(0, DL, MVT::i32), // $omod
3293 SDValue(InterpMov, 1)
3294 });
3295
3296 CurDAG->ReplaceAllUsesOfValueWith(SDValue(N, 0), SDValue(InterpP1LV, 0));
3297}
3298
3299void AMDGPUDAGToDAGISel::SelectINTRINSIC_W_CHAIN(SDNode *N) {
3300 unsigned IntrID = N->getConstantOperandVal(1);
3301 switch (IntrID) {
3302 case Intrinsic::amdgcn_ds_append:
3303 case Intrinsic::amdgcn_ds_consume: {
3304 if (N->getValueType(0) != MVT::i32)
3305 break;
3306 SelectDSAppendConsume(N, IntrID);
3307 return;
3308 }
3309 case Intrinsic::amdgcn_ds_bvh_stack_rtn:
3310 case Intrinsic::amdgcn_ds_bvh_stack_push4_pop1_rtn:
3311 case Intrinsic::amdgcn_ds_bvh_stack_push8_pop1_rtn:
3312 case Intrinsic::amdgcn_ds_bvh_stack_push8_pop2_rtn:
3313 SelectDSBvhStackIntrinsic(N, IntrID);
3314 return;
3315 case Intrinsic::amdgcn_init_whole_wave:
3316 CurDAG->getMachineFunction()
3317 .getInfo<SIMachineFunctionInfo>()
3318 ->setInitWholeWave();
3319 break;
3320 }
3321
3322 SelectCode(N);
3323}
3324
3325void AMDGPUDAGToDAGISel::SelectINTRINSIC_WO_CHAIN(SDNode *N) {
3326 unsigned IntrID = N->getConstantOperandVal(0);
3327 unsigned Opcode = AMDGPU::INSTRUCTION_LIST_END;
3328 SDNode *ConvGlueNode = N->getGluedNode();
3329 if (ConvGlueNode) {
3330 // FIXME: Possibly iterate over multiple glue nodes?
3331 assert(ConvGlueNode->getOpcode() == ISD::CONVERGENCECTRL_GLUE);
3332 ConvGlueNode = ConvGlueNode->getOperand(0).getNode();
3333 ConvGlueNode =
3334 CurDAG->getMachineNode(TargetOpcode::CONVERGENCECTRL_GLUE, {},
3335 MVT::Glue, SDValue(ConvGlueNode, 0));
3336 } else {
3337 ConvGlueNode = nullptr;
3338 }
3339 switch (IntrID) {
3340 case Intrinsic::amdgcn_wqm:
3341 Opcode = AMDGPU::WQM;
3342 break;
3343 case Intrinsic::amdgcn_softwqm:
3344 Opcode = AMDGPU::SOFT_WQM;
3345 break;
3346 case Intrinsic::amdgcn_wwm:
3347 case Intrinsic::amdgcn_strict_wwm:
3348 Opcode = AMDGPU::STRICT_WWM;
3349 break;
3350 case Intrinsic::amdgcn_strict_wqm:
3351 Opcode = AMDGPU::STRICT_WQM;
3352 break;
3353 case Intrinsic::amdgcn_interp_p1_f16:
3354 SelectInterpP1F16(N);
3355 return;
3356 case Intrinsic::amdgcn_permlane16_swap:
3357 case Intrinsic::amdgcn_permlane32_swap: {
3358 if ((IntrID == Intrinsic::amdgcn_permlane16_swap &&
3359 !Subtarget->hasPermlane16Swap()) ||
3360 (IntrID == Intrinsic::amdgcn_permlane32_swap &&
3361 !Subtarget->hasPermlane32Swap())) {
3362 SelectCode(N); // Hit the default error
3363 return;
3364 }
3365
3366 Opcode = IntrID == Intrinsic::amdgcn_permlane16_swap
3367 ? AMDGPU::V_PERMLANE16_SWAP_B32_e64
3368 : AMDGPU::V_PERMLANE32_SWAP_B32_e64;
3369
3370 SmallVector<SDValue, 4> NewOps(N->op_begin() + 1, N->op_end());
3371 if (ConvGlueNode)
3372 NewOps.push_back(SDValue(ConvGlueNode, 0));
3373
3374 bool FI = N->getConstantOperandVal(3);
3375 NewOps[2] = CurDAG->getTargetConstant(
3376 FI ? AMDGPU::DPP::DPP_FI_1 : AMDGPU::DPP::DPP_FI_0, SDLoc(), MVT::i32);
3377
3378 CurDAG->SelectNodeTo(N, Opcode, N->getVTList(), NewOps);
3379 return;
3380 }
3381 default:
3382 SelectCode(N);
3383 break;
3384 }
3385
3386 if (Opcode != AMDGPU::INSTRUCTION_LIST_END) {
3387 SDValue Src = N->getOperand(1);
3388 CurDAG->SelectNodeTo(N, Opcode, N->getVTList(), {Src});
3389 }
3390
3391 if (ConvGlueNode) {
3392 SmallVector<SDValue, 4> NewOps(N->ops());
3393 NewOps.push_back(SDValue(ConvGlueNode, 0));
3394 CurDAG->MorphNodeTo(N, N->getOpcode(), N->getVTList(), NewOps);
3395 }
3396}
3397
3398void AMDGPUDAGToDAGISel::SelectINTRINSIC_VOID(SDNode *N) {
3399 unsigned IntrID = N->getConstantOperandVal(1);
3400 switch (IntrID) {
3401 case Intrinsic::amdgcn_ds_gws_init:
3402 case Intrinsic::amdgcn_ds_gws_barrier:
3403 case Intrinsic::amdgcn_ds_gws_sema_v:
3404 case Intrinsic::amdgcn_ds_gws_sema_br:
3405 case Intrinsic::amdgcn_ds_gws_sema_p:
3406 case Intrinsic::amdgcn_ds_gws_sema_release_all:
3407 SelectDS_GWS(N, IntrID);
3408 return;
3409 case Intrinsic::amdgcn_tensor_load_to_lds:
3410 case Intrinsic::amdgcn_tensor_store_from_lds:
3411 SelectTensorLoadStore(N, IntrID);
3412 return;
3413 default:
3414 break;
3415 }
3416
3417 SelectCode(N);
3418}
3419
3420void AMDGPUDAGToDAGISel::SelectWAVE_ADDRESS(SDNode *N) {
3421 SDValue Log2WaveSize =
3422 CurDAG->getTargetConstant(Subtarget->getWavefrontSizeLog2(), SDLoc(N), MVT::i32);
3423 CurDAG->SelectNodeTo(N, AMDGPU::S_LSHR_B32, N->getVTList(),
3424 {N->getOperand(0), Log2WaveSize});
3425}
3426
3427void AMDGPUDAGToDAGISel::SelectSTACKRESTORE(SDNode *N) {
3428 SDValue SrcVal = N->getOperand(1);
3429 if (SrcVal.getValueType() != MVT::i32) {
3430 SelectCode(N); // Emit default error
3431 return;
3432 }
3433
3434 SDValue CopyVal;
3435 Register SP = TLI->getStackPointerRegisterToSaveRestore();
3436 SDLoc SL(N);
3437
3438 if (SrcVal.getOpcode() == AMDGPUISD::WAVE_ADDRESS) {
3439 CopyVal = SrcVal.getOperand(0);
3440 } else {
3441 SDValue Log2WaveSize = CurDAG->getTargetConstant(
3442 Subtarget->getWavefrontSizeLog2(), SL, MVT::i32);
3443
3444 if (N->isDivergent()) {
3445 SrcVal = SDValue(CurDAG->getMachineNode(AMDGPU::V_READFIRSTLANE_B32, SL,
3446 MVT::i32, SrcVal),
3447 0);
3448 }
3449
3450 CopyVal = SDValue(CurDAG->getMachineNode(AMDGPU::S_LSHL_B32, SL, MVT::i32,
3451 {SrcVal, Log2WaveSize}),
3452 0);
3453 }
3454
3455 SDValue CopyToSP = CurDAG->getCopyToReg(N->getOperand(0), SL, SP, CopyVal);
3456 CurDAG->ReplaceAllUsesOfValueWith(SDValue(N, 0), CopyToSP);
3457}
3458
3459void AMDGPUDAGToDAGISel::SelectWRITE_REGISTER(SDNode *N) {
3460 const MDString *RegStr = cast<MDString>(
3461 cast<MDNodeSDNode>(N->getOperand(1))->getMD()->getOperand(0));
3462 SDValue SrcVal = N->getOperand(2);
3463 EVT VT = SrcVal.getValueType();
3464 Register Reg = TLI->getRegisterByName(RegStr->getString().data(),
3466 CurDAG->getMachineFunction());
3467 if (!Reg) {
3468 const Function &Fn = CurDAG->getMachineFunction().getFunction();
3469 Fn.getContext().diagnose(DiagnosticInfoGenericWithLoc(
3470 "invalid register \"" + Twine(RegStr->getString()) +
3471 "\" for llvm.write_register",
3472 Fn, N->getDebugLoc()));
3473 ReplaceUses(SDValue(N, 0), N->getOperand(0));
3474 CurDAG->RemoveDeadNode(N);
3475 return;
3476 }
3477
3478 // Speculatively insert a readfirstlane in case the source value ends up in a
3479 // VGPR, which hopefully will fold away if not.
3480 SDLoc SL(N);
3481 SDValue CopyVal;
3482 if (isa<ConstantSDNode>(SrcVal)) {
3483 CopyVal = SrcVal;
3484 } else if (VT == MVT::i32) {
3485 CopyVal = SDValue(CurDAG->getMachineNode(AMDGPU::V_READFIRSTLANE_B32, SL,
3486 MVT::i32, SrcVal),
3487 0);
3488 } else {
3489 assert(VT == MVT::i64);
3490 SDValue Lo =
3491 CurDAG->getTargetExtractSubreg(AMDGPU::sub0, SL, MVT::i32, SrcVal);
3492 SDValue Hi =
3493 CurDAG->getTargetExtractSubreg(AMDGPU::sub1, SL, MVT::i32, SrcVal);
3494 Lo = SDValue(
3495 CurDAG->getMachineNode(AMDGPU::V_READFIRSTLANE_B32, SL, MVT::i32, Lo),
3496 0);
3497 Hi = SDValue(
3498 CurDAG->getMachineNode(AMDGPU::V_READFIRSTLANE_B32, SL, MVT::i32, Hi),
3499 0);
3500 CopyVal = emitRegSequence(*CurDAG, AMDGPU::SReg_64RegClassID, VT, {Lo, Hi},
3501 {AMDGPU::sub0, AMDGPU::sub1}, SL);
3502 }
3503
3504 SDValue CopyToReg = CurDAG->getCopyToReg(N->getOperand(0), SL, Reg, CopyVal);
3505 CurDAG->ReplaceAllUsesOfValueWith(SDValue(N, 0), CopyToReg);
3506}
3507
3508bool AMDGPUDAGToDAGISel::SelectVOP3ModsImpl(SDValue In, SDValue &Src,
3509 unsigned &Mods,
3510 bool IsCanonicalizing,
3511 bool AllowAbs) const {
3512 Mods = SISrcMods::NONE;
3513 Src = In;
3514
3515 if (Src.getOpcode() == ISD::FNEG) {
3516 Mods |= SISrcMods::NEG;
3517 Src = Src.getOperand(0);
3518 } else if (Src.getOpcode() == ISD::FSUB && IsCanonicalizing) {
3519 // Fold fsub [+-]0 into fneg. This may not have folded depending on the
3520 // denormal mode, but we're implicitly canonicalizing in a source operand.
3521 auto *LHS = dyn_cast<ConstantFPSDNode>(Src.getOperand(0));
3522 if (LHS && LHS->isZero()) {
3523 Mods |= SISrcMods::NEG;
3524 Src = Src.getOperand(1);
3525 }
3526 }
3527
3528 if (AllowAbs && Src.getOpcode() == ISD::FABS) {
3529 Mods |= SISrcMods::ABS;
3530 Src = Src.getOperand(0);
3531 }
3532
3533 if (Mods != SISrcMods::NONE)
3534 return true;
3535
3536 // Convert various sign-bit masks on integers to src mods. Currently disabled
3537 // for 16-bit types as the codegen replaces the operand without adding a
3538 // srcmod. This is intentionally finding the cases where we are performing
3539 // float neg and abs on int types, the goal is not to obtain two's complement
3540 // neg or abs. Limit converison to select operands via the nonCanonalizing
3541 // pattern.
3542 // TODO: Add 16-bit support.
3543 if (IsCanonicalizing)
3544 return true;
3545
3546 // v2i32 xor/or/and are legal. A vselect using these instructions as operands
3547 // is scalarised into two selects with EXTRACT_VECTOR_ELT operands. Peek
3548 // through the extract to the bitwise op.
3549 SDValue PeekSrc =
3550 Src->getOpcode() == ISD::EXTRACT_VECTOR_ELT ? Src->getOperand(0) : Src;
3551 // Convert various sign-bit masks to src mods. Currently disabled for 16-bit
3552 // types as the codegen replaces the operand without adding a srcmod.
3553 // This is intentionally finding the cases where we are performing float neg
3554 // and abs on int types, the goal is not to obtain two's complement neg or
3555 // abs.
3556 // TODO: Add 16-bit support.
3557 unsigned Opc = PeekSrc.getOpcode();
3558 EVT VT = Src.getValueType();
3559 if ((Opc != ISD::AND && Opc != ISD::OR && Opc != ISD::XOR) ||
3560 (VT != MVT::i32 && VT != MVT::v2i32 && VT != MVT::i64))
3561 return true;
3562
3563 ConstantSDNode *CRHS = isConstOrConstSplat(PeekSrc->getOperand(1));
3564 if (!CRHS)
3565 return true;
3566
3567 auto ReplaceSrc = [&]() -> SDValue {
3568 if (Src->getOpcode() != ISD::EXTRACT_VECTOR_ELT)
3569 return Src.getOperand(0);
3570
3571 SDValue LHS = PeekSrc->getOperand(0);
3572 SDValue Index = Src->getOperand(1);
3573 return CurDAG->getNode(ISD::EXTRACT_VECTOR_ELT, SDLoc(Src),
3574 Src.getValueType(), LHS, Index);
3575 };
3576
3577 // Recognise Srcmods:
3578 // (xor a, 0x80000000) or v2i32 (xor a, {0x80000000,0x80000000}) as NEG.
3579 // (and a, 0x7fffffff) or v2i32 (and a, {0x7fffffff,0x7fffffff}) as ABS.
3580 // (or a, 0x80000000) or v2i32 (or a, {0x80000000,0x80000000}) as NEG+ABS
3581 // SrcModifiers.
3582 if (Opc == ISD::XOR && CRHS->getAPIntValue().isSignMask()) {
3583 Mods |= SISrcMods::NEG;
3584 Src = ReplaceSrc();
3585 } else if (Opc == ISD::AND && AllowAbs &&
3586 CRHS->getAPIntValue().isMaxSignedValue()) {
3587 Mods |= SISrcMods::ABS;
3588 Src = ReplaceSrc();
3589 } else if (Opc == ISD::OR && AllowAbs && CRHS->getAPIntValue().isSignMask()) {
3591 Src = ReplaceSrc();
3592 }
3593
3594 return true;
3595}
3596
3597bool AMDGPUDAGToDAGISel::SelectVOP3Mods(SDValue In, SDValue &Src,
3598 SDValue &SrcMods) const {
3599 unsigned Mods;
3600 if (SelectVOP3ModsImpl(In, Src, Mods, /*IsCanonicalizing=*/true,
3601 /*AllowAbs=*/true)) {
3602 SrcMods = CurDAG->getTargetConstant(Mods, SDLoc(In), MVT::i32);
3603 return true;
3604 }
3605
3606 return false;
3607}
3608
3609bool AMDGPUDAGToDAGISel::SelectVOP3ModsNonCanonicalizing(
3610 SDValue In, SDValue &Src, SDValue &SrcMods) const {
3611 unsigned Mods;
3612 if (SelectVOP3ModsImpl(In, Src, Mods, /*IsCanonicalizing=*/false,
3613 /*AllowAbs=*/true)) {
3614 SrcMods = CurDAG->getTargetConstant(Mods, SDLoc(In), MVT::i32);
3615 return true;
3616 }
3617
3618 return false;
3619}
3620
3621bool AMDGPUDAGToDAGISel::SelectVOP3BMods(SDValue In, SDValue &Src,
3622 SDValue &SrcMods) const {
3623 unsigned Mods;
3624 if (SelectVOP3ModsImpl(In, Src, Mods,
3625 /*IsCanonicalizing=*/true,
3626 /*AllowAbs=*/false)) {
3627 SrcMods = CurDAG->getTargetConstant(Mods, SDLoc(In), MVT::i32);
3628 return true;
3629 }
3630
3631 return false;
3632}
3633
3634bool AMDGPUDAGToDAGISel::SelectVOP3NoMods(SDValue In, SDValue &Src) const {
3635 if (In.getOpcode() == ISD::FABS || In.getOpcode() == ISD::FNEG)
3636 return false;
3637
3638 Src = In;
3639 return true;
3640}
3641
3642bool AMDGPUDAGToDAGISel::SelectVINTERPModsImpl(SDValue In, SDValue &Src,
3643 SDValue &SrcMods,
3644 bool OpSel) const {
3645 unsigned Mods;
3646 if (SelectVOP3ModsImpl(In, Src, Mods,
3647 /*IsCanonicalizing=*/true,
3648 /*AllowAbs=*/false)) {
3649 if (OpSel)
3650 Mods |= SISrcMods::OP_SEL_0;
3651 SrcMods = CurDAG->getTargetConstant(Mods, SDLoc(In), MVT::i32);
3652 return true;
3653 }
3654
3655 return false;
3656}
3657
3658bool AMDGPUDAGToDAGISel::SelectVINTERPMods(SDValue In, SDValue &Src,
3659 SDValue &SrcMods) const {
3660 return SelectVINTERPModsImpl(In, Src, SrcMods, /* OpSel */ false);
3661}
3662
3663bool AMDGPUDAGToDAGISel::SelectVINTERPModsHi(SDValue In, SDValue &Src,
3664 SDValue &SrcMods) const {
3665 return SelectVINTERPModsImpl(In, Src, SrcMods, /* OpSel */ true);
3666}
3667
3668bool AMDGPUDAGToDAGISel::SelectVOP3Mods0(SDValue In, SDValue &Src,
3669 SDValue &SrcMods, SDValue &Clamp,
3670 SDValue &Omod) const {
3671 SDLoc DL(In);
3672 Clamp = CurDAG->getTargetConstant(0, DL, MVT::i1);
3673 Omod = CurDAG->getTargetConstant(0, DL, MVT::i1);
3674
3675 return SelectVOP3Mods(In, Src, SrcMods);
3676}
3677
3678bool AMDGPUDAGToDAGISel::SelectVOP3BMods0(SDValue In, SDValue &Src,
3679 SDValue &SrcMods, SDValue &Clamp,
3680 SDValue &Omod) const {
3681 SDLoc DL(In);
3682 Clamp = CurDAG->getTargetConstant(0, DL, MVT::i1);
3683 Omod = CurDAG->getTargetConstant(0, DL, MVT::i1);
3684
3685 return SelectVOP3BMods(In, Src, SrcMods);
3686}
3687
3688bool AMDGPUDAGToDAGISel::SelectVOP3OMods(SDValue In, SDValue &Src,
3689 SDValue &Clamp, SDValue &Omod) const {
3690 Src = In;
3691
3692 SDLoc DL(In);
3693 Clamp = CurDAG->getTargetConstant(0, DL, MVT::i1);
3694 Omod = CurDAG->getTargetConstant(0, DL, MVT::i1);
3695
3696 return true;
3697}
3698
3699bool AMDGPUDAGToDAGISel::SelectVOP3PMods(SDValue In, SDValue &Src,
3700 SDValue &SrcMods, bool IsDOT) const {
3701 unsigned Mods = SISrcMods::NONE;
3702 Src = In;
3703
3704 // TODO: Handle G_FSUB 0 as fneg
3705 if (Src.getOpcode() == ISD::FNEG) {
3707 Src = Src.getOperand(0);
3708 }
3709
3710 // 64-bit VOP3P instructions do not have OPSEL or ABS.
3711 bool HasOpSel = Src.getValueSizeInBits() != 128;
3712
3713 if (Src.getOpcode() == ISD::BUILD_VECTOR && Src.getNumOperands() == 2 &&
3714 (!IsDOT || !Subtarget->hasDOTOpSelHazard())) {
3715 unsigned VecMods = Mods;
3716
3717 SDValue Lo = stripBitcast(Src.getOperand(0));
3718 SDValue Hi = stripBitcast(Src.getOperand(1));
3719
3720 if (Lo.getOpcode() == ISD::FNEG) {
3721 Lo = stripBitcast(Lo.getOperand(0));
3722 Mods ^= SISrcMods::NEG;
3723 }
3724
3725 if (Hi.getOpcode() == ISD::FNEG) {
3726 Hi = stripBitcast(Hi.getOperand(0));
3727 Mods ^= SISrcMods::NEG_HI;
3728 }
3729
3730 if (HasOpSel) {
3731 if (isExtractHiElt(Lo, Lo))
3732 Mods |= SISrcMods::OP_SEL_0;
3733
3734 if (isExtractHiElt(Hi, Hi))
3735 Mods |= SISrcMods::OP_SEL_1;
3736 }
3737
3738 unsigned VecSize = Src.getValueSizeInBits();
3739 Lo = stripExtractLoElt(Lo);
3740 Hi = stripExtractLoElt(Hi);
3741
3742 if (Lo.getValueSizeInBits() > VecSize) {
3743 Lo = CurDAG->getTargetExtractSubreg(
3744 (VecSize > 32) ? AMDGPU::sub0_sub1 : AMDGPU::sub0, SDLoc(In),
3745 MVT::getIntegerVT(VecSize), Lo);
3746 }
3747
3748 if (Hi.getValueSizeInBits() > VecSize) {
3749 Hi = CurDAG->getTargetExtractSubreg(
3750 (VecSize > 32) ? AMDGPU::sub0_sub1 : AMDGPU::sub0, SDLoc(In),
3751 MVT::getIntegerVT(VecSize), Hi);
3752 }
3753
3754 assert(Lo.getValueSizeInBits() <= VecSize &&
3755 Hi.getValueSizeInBits() <= VecSize);
3756
3757 if (Lo == Hi && !isInlineImmediate(Lo.getNode())) {
3758 // Really a scalar input. Just select from the low half of the register to
3759 // avoid packing.
3760
3761 if (VecSize == Lo.getValueSizeInBits()) {
3762 Src = Lo;
3763 } else if (VecSize == 32) {
3764 Src = createVOP3PSrc32FromLo16(Lo, Src, CurDAG, Subtarget);
3765 } else {
3766 assert((Lo.getValueSizeInBits() == 32 && VecSize == 64) ||
3767 (Lo.getValueSizeInBits() == 64 && VecSize == 128));
3768
3769 SDLoc SL(In);
3770 SDValue Undef = SDValue(
3771 CurDAG->getMachineNode(TargetOpcode::IMPLICIT_DEF, SL,
3772 Lo.getValueType()), 0);
3773 const SIRegisterInfo *TRI = Subtarget->getRegisterInfo();
3774 // <2 x 64> instructions do not have OPSEL and also replicate low 64
3775 // bits of a scalar input into high 64 bits. Use VGPRs in this case.
3776 // TODO: This fact can be exploited but we need to set proper OPSEL for
3777 // codegen folding purposes. It will not affect a final instruction.
3778 auto RC = Lo->isDivergent() ? TRI->getVGPRClassForBitWidth(VecSize)
3779 : TRI->getSGPRClassForBitWidth(VecSize);
3780 unsigned NumRegs = Lo.getValueSizeInBits() == 32 ? 1 : 2;
3781 const SDValue Ops[] = {
3782 CurDAG->getTargetConstant(RC->getID(), SL, MVT::i32), Lo,
3783 CurDAG->getTargetConstant(TRI->getSubRegFromChannel(0, NumRegs), SL,
3784 MVT::i32),
3785 // For packed 64-bit ops without OPSEL support, a later pass will
3786 // optimize the splat sgpr patterns to save registers.
3787 HasOpSel ? Undef : Lo,
3788 CurDAG->getTargetConstant(
3789 TRI->getSubRegFromChannel(NumRegs, NumRegs), SL, MVT::i32)};
3790
3791 Src = SDValue(CurDAG->getMachineNode(TargetOpcode::REG_SEQUENCE, SL,
3792 Src.getValueType(), Ops), 0);
3793 // Check that both op_sel_0 and op_sel_1 are zero.
3795 }
3796 SrcMods = CurDAG->getTargetConstant(Mods, SDLoc(In), MVT::i32);
3797 return true;
3798 }
3799
3800 if (VecSize == 64 && Lo == Hi && isa<ConstantFPSDNode>(Lo)) {
3801 uint64_t Lit = cast<ConstantFPSDNode>(Lo)->getValueAPF()
3802 .bitcastToAPInt().getZExtValue();
3803 if (AMDGPU::isInlinableLiteral32(Lit, Subtarget->hasInv2PiInlineImm())) {
3804 Src = CurDAG->getTargetConstant(Lit, SDLoc(In), MVT::i64);
3805 SrcMods = CurDAG->getTargetConstant(Mods, SDLoc(In), MVT::i32);
3806 return true;
3807 }
3808 }
3809
3810 Mods = VecMods;
3811 } else if (Src.getOpcode() == ISD::VECTOR_SHUFFLE &&
3812 Src.getNumOperands() == 2) {
3813
3814 // TODO: We should repeat the build_vector source check above for the
3815 // vector_shuffle for negates and casts of individual elements.
3816
3817 assert(Src.getValueSizeInBits() != 128 &&
3818 "<2 x 64> VECTOR_SHUFFLE should not be legal.");
3819
3820 auto *SVN = cast<ShuffleVectorSDNode>(Src);
3821 ArrayRef<int> Mask = SVN->getMask();
3822
3823 if (Mask[0] < 2 && Mask[1] < 2) {
3824 // src1 should be undef.
3825 SDValue ShuffleSrc = SVN->getOperand(0);
3826
3827 if (ShuffleSrc.getOpcode() == ISD::FNEG) {
3828 ShuffleSrc = ShuffleSrc.getOperand(0);
3830 }
3831
3832 if (Mask[0] == 1)
3833 Mods |= SISrcMods::OP_SEL_0;
3834 if (Mask[1] == 1)
3835 Mods |= SISrcMods::OP_SEL_1;
3836
3837 Src = ShuffleSrc;
3838 SrcMods = CurDAG->getTargetConstant(Mods, SDLoc(In), MVT::i32);
3839 return true;
3840 }
3841 }
3842
3843 // Packed instructions do not have abs modifiers.
3844 Mods |= SISrcMods::OP_SEL_1;
3845
3846 SrcMods = CurDAG->getTargetConstant(Mods, SDLoc(In), MVT::i32);
3847 return true;
3848}
3849
3850bool AMDGPUDAGToDAGISel::SelectVOP3PModsDOT(SDValue In, SDValue &Src,
3851 SDValue &SrcMods) const {
3852 return SelectVOP3PMods(In, Src, SrcMods, true);
3853}
3854
3855bool AMDGPUDAGToDAGISel::SelectVOP3PNoModsDOT(SDValue In, SDValue &Src) const {
3856 SDValue SrcTmp, SrcModsTmp;
3857 SelectVOP3PMods(In, SrcTmp, SrcModsTmp, true);
3858 if (cast<ConstantSDNode>(SrcModsTmp)->getZExtValue() == SISrcMods::OP_SEL_1) {
3859 Src = SrcTmp;
3860 return true;
3861 }
3862
3863 return false;
3864}
3865
3866bool AMDGPUDAGToDAGISel::SelectVOP3PModsF32(SDValue In, SDValue &Src,
3867 SDValue &SrcMods) const {
3868 SelectVOP3Mods(In, Src, SrcMods);
3869 unsigned Mods = SISrcMods::OP_SEL_1;
3870 Mods |= cast<ConstantSDNode>(SrcMods)->getZExtValue();
3871 SrcMods = CurDAG->getTargetConstant(Mods, SDLoc(In), MVT::i32);
3872 return true;
3873}
3874
3875bool AMDGPUDAGToDAGISel::SelectVOP3PNoModsF32(SDValue In, SDValue &Src) const {
3876 SDValue SrcTmp, SrcModsTmp;
3877 SelectVOP3PModsF32(In, SrcTmp, SrcModsTmp);
3878 if (cast<ConstantSDNode>(SrcModsTmp)->getZExtValue() == SISrcMods::OP_SEL_1) {
3879 Src = SrcTmp;
3880 return true;
3881 }
3882
3883 return false;
3884}
3885
3886bool AMDGPUDAGToDAGISel::SelectWMMAOpSelVOP3PMods(SDValue In,
3887 SDValue &Src) const {
3888 const ConstantSDNode *C = cast<ConstantSDNode>(In);
3889 assert(C->getAPIntValue().getBitWidth() == 1 && "expected i1 value");
3890
3891 unsigned Mods = SISrcMods::OP_SEL_1;
3892 unsigned SrcVal = C->getZExtValue();
3893 if (SrcVal == 1)
3894 Mods |= SISrcMods::OP_SEL_0;
3895
3896 Src = CurDAG->getTargetConstant(Mods, SDLoc(In), MVT::i32);
3897 return true;
3898}
3899
3901AMDGPUDAGToDAGISel::buildRegSequence32(SmallVectorImpl<SDValue> &Elts,
3902 const SDLoc &DL) const {
3903 unsigned DstRegClass;
3904 EVT DstTy;
3905 switch (Elts.size()) {
3906 case 8:
3907 DstRegClass = AMDGPU::VReg_256RegClassID;
3908 DstTy = MVT::v8i32;
3909 break;
3910 case 4:
3911 DstRegClass = AMDGPU::VReg_128RegClassID;
3912 DstTy = MVT::v4i32;
3913 break;
3914 case 2:
3915 DstRegClass = AMDGPU::VReg_64RegClassID;
3916 DstTy = MVT::v2i32;
3917 break;
3918 default:
3919 llvm_unreachable("unhandled Reg sequence size");
3920 }
3921
3923 Ops.push_back(CurDAG->getTargetConstant(DstRegClass, DL, MVT::i32));
3924 for (unsigned i = 0; i < Elts.size(); ++i) {
3925 Ops.push_back(Elts[i]);
3926 Ops.push_back(CurDAG->getTargetConstant(
3928 }
3929 return CurDAG->getMachineNode(TargetOpcode::REG_SEQUENCE, DL, DstTy, Ops);
3930}
3931
3933AMDGPUDAGToDAGISel::buildRegSequence16(SmallVectorImpl<SDValue> &Elts,
3934 const SDLoc &DL) const {
3935 SmallVector<SDValue, 8> PackedElts;
3936 assert("unhandled Reg sequence size" &&
3937 (Elts.size() == 8 || Elts.size() == 16));
3938
3939 // Pack 16-bit elements in pairs into 32-bit register. If both elements are
3940 // unpacked from 32-bit source use it, otherwise pack them using v_perm.
3941 for (unsigned i = 0; i < Elts.size(); i += 2) {
3942 SDValue LoSrc = stripExtractLoElt(stripBitcast(Elts[i]));
3943 SDValue HiSrc;
3944 if (isExtractHiElt(Elts[i + 1], HiSrc) && LoSrc == HiSrc) {
3945 PackedElts.push_back(HiSrc);
3946 } else {
3947 if (Subtarget->useRealTrue16Insts()) {
3948 // FIXME-TRUE16. For now pack VGPR_32 for 16-bit source before
3949 // passing to v_perm_b32. Eventually we should use replace v_perm_b32
3950 // by reg_sequence.
3951 SDValue Undef = SDValue(
3952 CurDAG->getMachineNode(TargetOpcode::IMPLICIT_DEF, DL, MVT::i16),
3953 0);
3954 Elts[i] =
3955 emitRegSequence(*CurDAG, AMDGPU::VGPR_32RegClassID, MVT::i32,
3956 {Elts[i], Undef}, {AMDGPU::lo16, AMDGPU::hi16}, DL);
3957 Elts[i + 1] = emitRegSequence(*CurDAG, AMDGPU::VGPR_32RegClassID,
3958 MVT::i32, {Elts[i + 1], Undef},
3959 {AMDGPU::lo16, AMDGPU::hi16}, DL);
3960 }
3961 SDValue PackLoLo = CurDAG->getTargetConstant(0x05040100, DL, MVT::i32);
3962 MachineSDNode *Packed =
3963 CurDAG->getMachineNode(AMDGPU::V_PERM_B32_e64, DL, MVT::i32,
3964 {Elts[i + 1], Elts[i], PackLoLo});
3965 PackedElts.push_back(SDValue(Packed, 0));
3966 }
3967 }
3968 return buildRegSequence32(PackedElts, DL);
3969}
3970
3972AMDGPUDAGToDAGISel::buildRegSequence(SmallVectorImpl<SDValue> &Elts,
3973 const SDLoc &DL,
3974 unsigned ElementSize) const {
3975 if (ElementSize == 16)
3976 return buildRegSequence16(Elts, DL);
3977 if (ElementSize == 32)
3978 return buildRegSequence32(Elts, DL);
3979 llvm_unreachable("Unhandled element size");
3980}
3981
3982void AMDGPUDAGToDAGISel::selectWMMAModsNegAbs(unsigned ModOpcode,
3983 unsigned &Mods,
3985 SDValue &Src, const SDLoc &DL,
3986 unsigned ElementSize) const {
3987 if (ModOpcode == ISD::FNEG) {
3988 Mods |= SISrcMods::NEG;
3989 // Check if all elements also have abs modifier
3990 SmallVector<SDValue, 8> NegAbsElts;
3991 for (auto El : Elts) {
3992 if (El.getOpcode() != ISD::FABS)
3993 break;
3994 NegAbsElts.push_back(El->getOperand(0));
3995 }
3996 if (Elts.size() != NegAbsElts.size()) {
3997 // Neg
3998 Src = SDValue(buildRegSequence(Elts, DL, ElementSize), 0);
3999 } else {
4000 // Neg and Abs
4001 Mods |= SISrcMods::NEG_HI;
4002 Src = SDValue(buildRegSequence(NegAbsElts, DL, ElementSize), 0);
4003 }
4004 } else {
4005 assert(ModOpcode == ISD::FABS);
4006 // Abs
4007 Mods |= SISrcMods::NEG_HI;
4008 Src = SDValue(buildRegSequence(Elts, DL, ElementSize), 0);
4009 }
4010}
4011
4012// Check all f16 elements for modifiers while looking through b32 and v2b16
4013// build vector, stop if element does not satisfy ModifierCheck.
4014static void
4016 std::function<bool(SDValue)> ModifierCheck) {
4017 for (unsigned i = 0; i < BV->getNumOperands(); ++i) {
4018 if (auto *F16Pair =
4019 dyn_cast<BuildVectorSDNode>(stripBitcast(BV->getOperand(i)))) {
4020 for (unsigned i = 0; i < F16Pair->getNumOperands(); ++i) {
4021 SDValue ElF16 = stripBitcast(F16Pair->getOperand(i));
4022 if (!ModifierCheck(ElF16))
4023 break;
4024 }
4025 }
4026 }
4027}
4028
4029bool AMDGPUDAGToDAGISel::SelectWMMAModsF16Neg(SDValue In, SDValue &Src,
4030 SDValue &SrcMods) const {
4031 Src = In;
4032 unsigned Mods = SISrcMods::OP_SEL_1;
4033
4034 // mods are on f16 elements
4035 if (auto *BV = dyn_cast<BuildVectorSDNode>(stripBitcast(In))) {
4037
4038 checkWMMAElementsModifiersF16(BV, [&](SDValue Element) -> bool {
4039 if (Element.getOpcode() != ISD::FNEG)
4040 return false;
4041 EltsF16.push_back(Element.getOperand(0));
4042 return true;
4043 });
4044
4045 // All elements have neg modifier
4046 if (BV->getNumOperands() * 2 == EltsF16.size()) {
4047 Src = SDValue(buildRegSequence16(EltsF16, SDLoc(In)), 0);
4048 Mods |= SISrcMods::NEG;
4049 Mods |= SISrcMods::NEG_HI;
4050 }
4051 }
4052
4053 // mods are on v2f16 elements
4054 if (auto *BV = dyn_cast<BuildVectorSDNode>(stripBitcast(In))) {
4055 SmallVector<SDValue, 8> EltsV2F16;
4056 for (unsigned i = 0; i < BV->getNumOperands(); ++i) {
4057 SDValue ElV2f16 = stripBitcast(BV->getOperand(i));
4058 // Based on first element decide which mod we match, neg or abs
4059 if (ElV2f16.getOpcode() != ISD::FNEG)
4060 break;
4061 EltsV2F16.push_back(ElV2f16.getOperand(0));
4062 }
4063
4064 // All pairs of elements have neg modifier
4065 if (BV->getNumOperands() == EltsV2F16.size()) {
4066 Src = SDValue(buildRegSequence32(EltsV2F16, SDLoc(In)), 0);
4067 Mods |= SISrcMods::NEG;
4068 Mods |= SISrcMods::NEG_HI;
4069 }
4070 }
4071
4072 SrcMods = CurDAG->getTargetConstant(Mods, SDLoc(In), MVT::i32);
4073 return true;
4074}
4075
4076bool AMDGPUDAGToDAGISel::SelectWMMAModsF16NegAbs(SDValue In, SDValue &Src,
4077 SDValue &SrcMods) const {
4078 Src = In;
4079 unsigned Mods = SISrcMods::OP_SEL_1;
4080 unsigned ModOpcode;
4081
4082 // mods are on f16 elements
4083 if (auto *BV = dyn_cast<BuildVectorSDNode>(stripBitcast(In))) {
4085 checkWMMAElementsModifiersF16(BV, [&](SDValue ElF16) -> bool {
4086 // Based on first element decide which mod we match, neg or abs
4087 if (EltsF16.empty())
4088 ModOpcode = (ElF16.getOpcode() == ISD::FNEG) ? ISD::FNEG : ISD::FABS;
4089 if (ElF16.getOpcode() != ModOpcode)
4090 return false;
4091 EltsF16.push_back(ElF16.getOperand(0));
4092 return true;
4093 });
4094
4095 // All elements have ModOpcode modifier
4096 if (BV->getNumOperands() * 2 == EltsF16.size())
4097 selectWMMAModsNegAbs(ModOpcode, Mods, EltsF16, Src, SDLoc(In), 16);
4098 }
4099
4100 // mods are on v2f16 elements
4101 if (auto *BV = dyn_cast<BuildVectorSDNode>(stripBitcast(In))) {
4102 SmallVector<SDValue, 8> EltsV2F16;
4103
4104 for (unsigned i = 0; i < BV->getNumOperands(); ++i) {
4105 SDValue ElV2f16 = stripBitcast(BV->getOperand(i));
4106 // Based on first element decide which mod we match, neg or abs
4107 if (EltsV2F16.empty())
4108 ModOpcode = (ElV2f16.getOpcode() == ISD::FNEG) ? ISD::FNEG : ISD::FABS;
4109 if (ElV2f16->getOpcode() != ModOpcode)
4110 break;
4111 EltsV2F16.push_back(ElV2f16->getOperand(0));
4112 }
4113
4114 // All elements have ModOpcode modifier
4115 if (BV->getNumOperands() == EltsV2F16.size())
4116 selectWMMAModsNegAbs(ModOpcode, Mods, EltsV2F16, Src, SDLoc(In), 32);
4117 }
4118
4119 SrcMods = CurDAG->getTargetConstant(Mods, SDLoc(In), MVT::i32);
4120 return true;
4121}
4122
4123bool AMDGPUDAGToDAGISel::SelectWMMAModsF32NegAbs(SDValue In, SDValue &Src,
4124 SDValue &SrcMods) const {
4125 Src = In;
4126 unsigned Mods = SISrcMods::OP_SEL_1;
4128
4129 if (auto *BV = dyn_cast<BuildVectorSDNode>(stripBitcast(In))) {
4130 assert(BV->getNumOperands() > 0);
4131 // Based on first element decide which mod we match, neg or abs
4132 SDValue ElF32 = stripBitcast(BV->getOperand(0));
4133 unsigned ModOpcode =
4134 (ElF32.getOpcode() == ISD::FNEG) ? ISD::FNEG : ISD::FABS;
4135 for (unsigned i = 0; i < BV->getNumOperands(); ++i) {
4136 SDValue ElF32 = stripBitcast(BV->getOperand(i));
4137 if (ElF32.getOpcode() != ModOpcode)
4138 break;
4139 EltsF32.push_back(ElF32.getOperand(0));
4140 }
4141
4142 // All elements had ModOpcode modifier
4143 if (BV->getNumOperands() == EltsF32.size())
4144 selectWMMAModsNegAbs(ModOpcode, Mods, EltsF32, Src, SDLoc(In), 32);
4145 }
4146
4147 SrcMods = CurDAG->getTargetConstant(Mods, SDLoc(In), MVT::i32);
4148 return true;
4149}
4150
4151bool AMDGPUDAGToDAGISel::SelectWMMAVISrc(SDValue In, SDValue &Src) const {
4152 if (auto *BV = dyn_cast<BuildVectorSDNode>(In)) {
4153 BitVector UndefElements;
4154 if (SDValue Splat = BV->getSplatValue(&UndefElements))
4155 if (isInlineImmediate(Splat.getNode())) {
4156 if (const ConstantSDNode *C = dyn_cast<ConstantSDNode>(Splat)) {
4157 unsigned Imm = C->getAPIntValue().getSExtValue();
4158 Src = CurDAG->getTargetConstant(Imm, SDLoc(In), MVT::i32);
4159 return true;
4160 }
4161 if (const ConstantFPSDNode *C = dyn_cast<ConstantFPSDNode>(Splat)) {
4162 unsigned Imm = C->getValueAPF().bitcastToAPInt().getSExtValue();
4163 Src = CurDAG->getTargetConstant(Imm, SDLoc(In), MVT::i32);
4164 return true;
4165 }
4166 llvm_unreachable("unhandled Constant node");
4167 }
4168 }
4169
4170 // 16 bit splat
4171 SDValue SplatSrc32 = stripBitcast(In);
4172 if (auto *SplatSrc32BV = dyn_cast<BuildVectorSDNode>(SplatSrc32))
4173 if (SDValue Splat32 = SplatSrc32BV->getSplatValue()) {
4174 SDValue SplatSrc16 = stripBitcast(Splat32);
4175 if (auto *SplatSrc16BV = dyn_cast<BuildVectorSDNode>(SplatSrc16))
4176 if (SDValue Splat = SplatSrc16BV->getSplatValue()) {
4177 const SIInstrInfo *TII = Subtarget->getInstrInfo();
4178 std::optional<APInt> RawValue;
4179 if (const ConstantFPSDNode *C = dyn_cast<ConstantFPSDNode>(Splat))
4180 RawValue = C->getValueAPF().bitcastToAPInt();
4181 else if (const ConstantSDNode *C = dyn_cast<ConstantSDNode>(Splat))
4182 RawValue = C->getAPIntValue();
4183
4184 if (RawValue.has_value()) {
4185 EVT VT = In.getValueType().getScalarType();
4186 if (VT.getSimpleVT() == MVT::f16 || VT.getSimpleVT() == MVT::bf16) {
4187 APFloat FloatVal(VT.getSimpleVT() == MVT::f16
4190 RawValue.value());
4191 if (TII->isInlineConstant(FloatVal)) {
4192 Src = CurDAG->getTargetConstant(RawValue.value(), SDLoc(In),
4193 MVT::i16);
4194 return true;
4195 }
4196 } else if (VT.getSimpleVT() == MVT::i16) {
4197 if (TII->isInlineConstant(RawValue.value())) {
4198 Src = CurDAG->getTargetConstant(RawValue.value(), SDLoc(In),
4199 MVT::i16);
4200 return true;
4201 }
4202 } else
4203 llvm_unreachable("unknown 16-bit type");
4204 }
4205 }
4206 }
4207
4208 // Currently f64 immediate vectors are represented as vectors of v2i32, with
4209 // different lo and hi 32-bit values even though double values are splated.
4210 // So we have to manually compare to determine whether it is splated.
4211 if (CurDAG->isConstantIntBuildVectorOrConstantInt(SplatSrc32)) {
4212 int64_t Imm64 = 0;
4213 for (unsigned i = 0; i < SplatSrc32->getNumOperands(); i += 2) {
4214 auto Lo32 = cast<ConstantSDNode>(SplatSrc32->getOperand(i));
4215 auto Hi32 = cast<ConstantSDNode>(SplatSrc32->getOperand(i + 1));
4216 int64_t LoImm = Lo32->getAPIntValue().getSExtValue();
4217 int64_t HiImm = Hi32->getAPIntValue().getSExtValue();
4218 int64_t Imm64I = (HiImm << 32) + LoImm;
4219 if (i == 0) {
4220 if (!isInlineImmediate(APInt(64, Imm64I)))
4221 return false;
4222 Imm64 = Imm64I;
4223 } else if (Imm64I != Imm64)
4224 return false;
4225 } // end for
4226
4227 Src = CurDAG->getTargetConstant(Imm64, SDLoc(In), MVT::i64);
4228 return true;
4229 }
4230
4231 return false;
4232}
4233
4234bool AMDGPUDAGToDAGISel::SelectSWMMACIndex8(SDValue In, SDValue &Src,
4235 SDValue &IndexKey) const {
4236 unsigned Key = 0;
4237 Src = In;
4238
4239 if (In.getOpcode() == ISD::SRL) {
4240 const llvm::SDValue &ShiftSrc = In.getOperand(0);
4241 ConstantSDNode *ShiftAmt = dyn_cast<ConstantSDNode>(In.getOperand(1));
4242 if (ShiftSrc.getValueType().getSizeInBits() == 32 && ShiftAmt &&
4243 ShiftAmt->getZExtValue() % 8 == 0) {
4244 Key = ShiftAmt->getZExtValue() / 8;
4245 Src = ShiftSrc;
4246 }
4247 }
4248
4249 IndexKey = CurDAG->getTargetConstant(Key, SDLoc(In), MVT::i32);
4250 return true;
4251}
4252
4253bool AMDGPUDAGToDAGISel::SelectSWMMACIndex16(SDValue In, SDValue &Src,
4254 SDValue &IndexKey) const {
4255 unsigned Key = 0;
4256 Src = In;
4257
4258 if (In.getOpcode() == ISD::SRL) {
4259 const llvm::SDValue &ShiftSrc = In.getOperand(0);
4260 ConstantSDNode *ShiftAmt = dyn_cast<ConstantSDNode>(In.getOperand(1));
4261 if (ShiftSrc.getValueType().getSizeInBits() == 32 && ShiftAmt &&
4262 ShiftAmt->getZExtValue() == 16) {
4263 Key = 1;
4264 Src = ShiftSrc;
4265 }
4266 }
4267
4268 IndexKey = CurDAG->getTargetConstant(Key, SDLoc(In), MVT::i32);
4269 return true;
4270}
4271
4272bool AMDGPUDAGToDAGISel::SelectSWMMACIndex32(SDValue In, SDValue &Src,
4273 SDValue &IndexKey) const {
4274 unsigned Key = 0;
4275 Src = In;
4276
4277 SDValue InI32;
4278
4279 if (In.getOpcode() == ISD::ANY_EXTEND || In.getOpcode() == ISD::ZERO_EXTEND) {
4280 const SDValue &ExtendSrc = In.getOperand(0);
4281 if (ExtendSrc.getValueSizeInBits() == 32)
4282 InI32 = ExtendSrc;
4283 } else if (In->getOpcode() == ISD::BITCAST) {
4284 const SDValue &CastSrc = In.getOperand(0);
4285 if (CastSrc.getOpcode() == ISD::BUILD_VECTOR &&
4286 CastSrc.getOperand(0).getValueSizeInBits() == 32) {
4287 ConstantSDNode *Zero = dyn_cast<ConstantSDNode>(CastSrc.getOperand(1));
4288 if (Zero && Zero->getZExtValue() == 0)
4289 InI32 = CastSrc.getOperand(0);
4290 }
4291 }
4292
4293 if (InI32 && InI32.getOpcode() == ISD::EXTRACT_VECTOR_ELT) {
4294 const SDValue &ExtractVecEltSrc = InI32.getOperand(0);
4295 ConstantSDNode *EltIdx = dyn_cast<ConstantSDNode>(InI32.getOperand(1));
4296 if (ExtractVecEltSrc.getValueSizeInBits() == 64 && EltIdx &&
4297 EltIdx->getZExtValue() == 1) {
4298 Key = 1;
4299 Src = ExtractVecEltSrc;
4300 }
4301 }
4302
4303 IndexKey = CurDAG->getTargetConstant(Key, SDLoc(In), MVT::i32);
4304 return true;
4305}
4306
4307bool AMDGPUDAGToDAGISel::SelectVOP3OpSel(SDValue In, SDValue &Src,
4308 SDValue &SrcMods) const {
4309 unsigned Mods = SISrcMods::NONE;
4310 Src = In;
4311 if (!Subtarget->useRealTrue16Insts() && In.getValueSizeInBits() == 16 &&
4312 isExtractHiElt(Src, Src))
4313 Mods |= SISrcMods::OP_SEL_0;
4314 SrcMods = CurDAG->getTargetConstant(Mods, SDLoc(In), MVT::i32);
4315 return true;
4316}
4317
4318bool AMDGPUDAGToDAGISel::SelectVOP3OpSelMods(SDValue In, SDValue &Src,
4319 SDValue &SrcMods) const {
4320 unsigned Mods;
4321 if (!SelectVOP3ModsImpl(In, Src, Mods, /*IsCanonicalizing=*/true,
4322 /*AllowAbs=*/true))
4323 return false;
4324
4325 if (!Subtarget->useRealTrue16Insts() && In.getValueSizeInBits() == 16 &&
4326 isExtractHiElt(Src, Src))
4327 Mods |= SISrcMods::OP_SEL_0;
4328
4329 SrcMods = CurDAG->getTargetConstant(Mods, SDLoc(In), MVT::i32);
4330 return true;
4331}
4332
4333// Match lowered fpext from bf16 to f32. This is a bit operation extending
4334// a 16-bit value with 16-bit of zeroes at LSB:
4335//
4336// 1. (f32 (bitcast (build_vector (i16 0), (i16 (bitcast bf16:val)))))
4337// 2. (f32 (bitcast (and i32:val, 0xffff0000))) -> IsExtractHigh = true
4338// 3. (f32 (bitcast (shl i32:va, 16) -> IsExtractHigh = false
4339static SDValue matchBF16FPExtendLike(SDValue Op, bool &IsExtractHigh) {
4340 if (Op.getValueType() != MVT::f32 || Op.getOpcode() != ISD::BITCAST)
4341 return SDValue();
4342 Op = Op.getOperand(0);
4343
4344 IsExtractHigh = false;
4345 if (Op.getValueType() == MVT::v2i16 && Op.getOpcode() == ISD::BUILD_VECTOR) {
4346 auto Low16 = dyn_cast<ConstantSDNode>(Op.getOperand(0));
4347 if (!Low16 || !Low16->isZero())
4348 return SDValue();
4349 Op = stripBitcast(Op.getOperand(1));
4350 if (Op.getValueType() != MVT::bf16)
4351 return SDValue();
4352 return Op;
4353 }
4354
4355 if (Op.getValueType() != MVT::i32)
4356 return SDValue();
4357
4358 if (Op.getOpcode() == ISD::AND) {
4359 if (auto Mask = dyn_cast<ConstantSDNode>(Op.getOperand(1))) {
4360 if (Mask->getZExtValue() == 0xffff0000) {
4361 IsExtractHigh = true;
4362 return Op.getOperand(0);
4363 }
4364 }
4365 return SDValue();
4366 }
4367
4368 if (Op.getOpcode() == ISD::SHL) {
4369 if (auto Amt = dyn_cast<ConstantSDNode>(Op.getOperand(1))) {
4370 if (Amt->getZExtValue() == 16)
4371 return Op.getOperand(0);
4372 }
4373 }
4374
4375 return SDValue();
4376}
4377
4378// The return value is not whether the match is possible (which it always is),
4379// but whether or not it a conversion is really used.
4380bool AMDGPUDAGToDAGISel::SelectVOP3PMadMixModsImpl(SDValue In, SDValue &Src,
4381 unsigned &Mods,
4382 MVT VT) const {
4383 Mods = 0;
4384 SelectVOP3ModsImpl(In, Src, Mods);
4385
4386 bool IsExtractHigh = false;
4387 if (Src.getOpcode() == ISD::FP_EXTEND &&
4388 Src.getOperand(0).getValueType() == VT) {
4389 Src = Src.getOperand(0);
4390 } else if (VT == MVT::bf16) {
4391 SDValue B16 = matchBF16FPExtendLike(Src, IsExtractHigh);
4392 if (!B16)
4393 return false;
4394 Src = B16;
4395 } else
4396 return false;
4397
4398 if (Src.getValueType() != VT &&
4399 (VT != MVT::bf16 || Src.getValueType() != MVT::i32))
4400 return false;
4401
4402 Src = stripBitcast(Src);
4403
4404 // Be careful about folding modifiers if we already have an abs. fneg is
4405 // applied last, so we don't want to apply an earlier fneg.
4406 if ((Mods & SISrcMods::ABS) == 0) {
4407 unsigned ModsTmp;
4408 SelectVOP3ModsImpl(Src, Src, ModsTmp);
4409
4410 if ((ModsTmp & SISrcMods::NEG) != 0)
4411 Mods ^= SISrcMods::NEG;
4412
4413 if ((ModsTmp & SISrcMods::ABS) != 0)
4414 Mods |= SISrcMods::ABS;
4415 }
4416
4417 // op_sel/op_sel_hi decide the source type and source.
4418 // If the source's op_sel_hi is set, it indicates to do a conversion from
4419 // fp16. If the sources's op_sel is set, it picks the high half of the source
4420 // register.
4421
4422 Mods |= SISrcMods::OP_SEL_1;
4423 if (Src.getValueSizeInBits() == 16) {
4424 if (isExtractHiElt(Src, Src)) {
4425 Mods |= SISrcMods::OP_SEL_0;
4426
4427 // TODO: Should we try to look for neg/abs here?
4428 return true;
4429 }
4430
4431 if (Src.getOpcode() == ISD::TRUNCATE &&
4432 Src.getOperand(0).getValueType() == MVT::i32) {
4433 Src = Src.getOperand(0);
4434 return true;
4435 }
4436
4437 if (Subtarget->useRealTrue16Insts())
4438 // In true16 mode, pack src to a 32bit
4439 Src = createVOP3PSrc32FromLo16(Src, In, CurDAG, Subtarget);
4440 } else if (IsExtractHigh)
4441 Mods |= SISrcMods::OP_SEL_0;
4442
4443 return true;
4444}
4445
4446bool AMDGPUDAGToDAGISel::SelectVOP3PMadMixModsExt(SDValue In, SDValue &Src,
4447 SDValue &SrcMods) const {
4448 unsigned Mods = 0;
4449 if (!SelectVOP3PMadMixModsImpl(In, Src, Mods, MVT::f16))
4450 return false;
4451 SrcMods = CurDAG->getTargetConstant(Mods, SDLoc(In), MVT::i32);
4452 return true;
4453}
4454
4455bool AMDGPUDAGToDAGISel::SelectVOP3PMadMixMods(SDValue In, SDValue &Src,
4456 SDValue &SrcMods) const {
4457 unsigned Mods = 0;
4458 SelectVOP3PMadMixModsImpl(In, Src, Mods, MVT::f16);
4459 SrcMods = CurDAG->getTargetConstant(Mods, SDLoc(In), MVT::i32);
4460 return true;
4461}
4462
4463bool AMDGPUDAGToDAGISel::SelectVOP3PMadMixModsExtNeg(SDValue In, SDValue &Src,
4464 SDValue &SrcMods) const {
4465 unsigned Mods = 0;
4466 if (!SelectVOP3PMadMixModsImpl(In, Src, Mods, MVT::f16))
4467 return false;
4468 SrcMods =
4469 CurDAG->getTargetConstant(Mods ^ SISrcMods::NEG, SDLoc(In), MVT::i32);
4470 return true;
4471}
4472
4473bool AMDGPUDAGToDAGISel::SelectVOP3PMadMixModsNeg(SDValue In, SDValue &Src,
4474 SDValue &SrcMods) const {
4475 unsigned Mods = 0;
4476 SelectVOP3PMadMixModsImpl(In, Src, Mods, MVT::f16);
4477 SrcMods =
4478 CurDAG->getTargetConstant(Mods ^ SISrcMods::NEG, SDLoc(In), MVT::i32);
4479 return true;
4480}
4481
4482bool AMDGPUDAGToDAGISel::SelectVOP3PMadMixBF16ModsExt(SDValue In, SDValue &Src,
4483 SDValue &SrcMods) const {
4484 unsigned Mods = 0;
4485 if (!SelectVOP3PMadMixModsImpl(In, Src, Mods, MVT::bf16))
4486 return false;
4487 SrcMods = CurDAG->getTargetConstant(Mods, SDLoc(In), MVT::i32);
4488 return true;
4489}
4490
4491bool AMDGPUDAGToDAGISel::SelectVOP3PMadMixBF16Mods(SDValue In, SDValue &Src,
4492 SDValue &SrcMods) const {
4493 unsigned Mods = 0;
4494 SelectVOP3PMadMixModsImpl(In, Src, Mods, MVT::bf16);
4495 SrcMods = CurDAG->getTargetConstant(Mods, SDLoc(In), MVT::i32);
4496 return true;
4497}
4498
4499bool AMDGPUDAGToDAGISel::SelectVOP3PMadMixBF16ModsExtNeg(
4500 SDValue In, SDValue &Src, SDValue &SrcMods) const {
4501 unsigned Mods = 0;
4502 if (!SelectVOP3PMadMixModsImpl(In, Src, Mods, MVT::bf16))
4503 return false;
4504 SrcMods =
4505 CurDAG->getTargetConstant(Mods ^ SISrcMods::NEG, SDLoc(In), MVT::i32);
4506 return true;
4507}
4508
4509bool AMDGPUDAGToDAGISel::SelectVOP3PMadMixBF16ModsNeg(SDValue In, SDValue &Src,
4510 SDValue &SrcMods) const {
4511 unsigned Mods = 0;
4512 SelectVOP3PMadMixModsImpl(In, Src, Mods, MVT::bf16);
4513 SrcMods =
4514 CurDAG->getTargetConstant(Mods ^ SISrcMods::NEG, SDLoc(In), MVT::i32);
4515 return true;
4516}
4517
4518// Match BITOP3 operation and return a number of matched instructions plus
4519// truth table.
4520static std::pair<unsigned, uint8_t> BitOp3_Op(SDValue In,
4522 unsigned NumOpcodes = 0;
4523 uint8_t LHSBits, RHSBits;
4524
4525 auto getOperandBits = [&Src, In](SDValue Op, uint8_t &Bits) -> bool {
4526 // Define truth table given Src0, Src1, Src2 bits permutations:
4527 // 0 0 0
4528 // 0 0 1
4529 // 0 1 0
4530 // 0 1 1
4531 // 1 0 0
4532 // 1 0 1
4533 // 1 1 0
4534 // 1 1 1
4535 const uint8_t SrcBits[3] = { 0xf0, 0xcc, 0xaa };
4536
4537 if (auto *C = dyn_cast<ConstantSDNode>(Op)) {
4538 if (C->isAllOnes()) {
4539 Bits = 0xff;
4540 return true;
4541 }
4542 if (C->isZero()) {
4543 Bits = 0;
4544 return true;
4545 }
4546 }
4547
4548 for (unsigned I = 0; I < Src.size(); ++I) {
4549 // Try to find existing reused operand
4550 if (Src[I] == Op) {
4551 Bits = SrcBits[I];
4552 return true;
4553 }
4554 // Try to replace parent operator
4555 if (Src[I] == In) {
4556 Bits = SrcBits[I];
4557 Src[I] = Op;
4558 return true;
4559 }
4560 }
4561
4562 if (Src.size() == 3) {
4563 // No room left for operands. Try one last time, there can be a 'not' of
4564 // one of our source operands. In this case we can compute the bits
4565 // without growing Src vector.
4566 if (Op.getOpcode() == ISD::XOR) {
4567 if (auto *C = dyn_cast<ConstantSDNode>(Op.getOperand(1))) {
4568 if (C->isAllOnes()) {
4569 SDValue LHS = Op.getOperand(0);
4570 for (unsigned I = 0; I < Src.size(); ++I) {
4571 if (Src[I] == LHS) {
4572 Bits = ~SrcBits[I];
4573 return true;
4574 }
4575 }
4576 }
4577 }
4578 }
4579
4580 return false;
4581 }
4582
4583 Bits = SrcBits[Src.size()];
4584 Src.push_back(Op);
4585 return true;
4586 };
4587
4588 switch (In.getOpcode()) {
4589 case ISD::AND:
4590 case ISD::OR:
4591 case ISD::XOR: {
4592 SDValue LHS = In.getOperand(0);
4593 SDValue RHS = In.getOperand(1);
4594
4595 SmallVector<SDValue, 3> Backup(Src.begin(), Src.end());
4596 if (!getOperandBits(LHS, LHSBits) ||
4597 !getOperandBits(RHS, RHSBits)) {
4598 Src = std::move(Backup);
4599 return std::make_pair(0, 0);
4600 }
4601
4602 // Recursion is naturally limited by the size of the operand vector.
4603 //
4604 // When LHS and RHS share a common sub-expression, one side's recursion
4605 // may decompose that sub-expression and replace the Src slot the other
4606 // side occupies with sub-operands via the "replace parent" path in
4607 // getOperandBits. The other side's cached bit-pattern then refers to a
4608 // slot whose contents changed, producing a wrong truth table.
4609 //
4610 // We detect this in three ways:
4611 // (A) If LHS recursed, its truth table is valid against the Src state
4612 // when LHS recursion completed (SrcAfterLHS). If RHS recursion
4613 // then mutates a Src slot that LHSBits depends on, LHSBits is
4614 // stale.
4615 // (B) If RHS did not recurse, RHSBits came from getOperandBits and
4616 // refers to a specific Src slot. If that slot's contents changed
4617 // (by either recursion), RHSBits is stale.
4618 // (C) Symmetrically for LHS if it did not recurse.
4619 SmallVector<SDValue, 3> SrcBeforeRecurse(Src.begin(), Src.end());
4620 uint8_t LHSBitsOrig = LHSBits;
4621 uint8_t RHSBitsOrig = RHSBits;
4622
4623 auto LHSOp = BitOp3_Op(LHS, Src);
4624 if (LHSOp.first) {
4625 NumOpcodes += LHSOp.first;
4626 LHSBits = LHSOp.second;
4627 }
4628
4629 SmallVector<SDValue, 3> SrcAfterLHS(Src.begin(), Src.end());
4630
4631 auto RHSOp = BitOp3_Op(RHS, Src);
4632 if (RHSOp.first) {
4633 NumOpcodes += RHSOp.first;
4634 RHSBits = RHSOp.second;
4635 }
4636
4637 // dependsOnSlot: true iff the truth table TT varies with slot Slot.
4638 auto dependsOnSlot = [](uint8_t TT, int Slot) -> bool {
4639 if (Slot < 0 || Slot > 2)
4640 return false;
4641 const uint8_t Masks[3] = {0x0f, 0x33, 0x55};
4642 const int Shifts[3] = {4, 2, 1};
4643 return ((TT ^ (TT >> Shifts[Slot])) & Masks[Slot]) != 0;
4644 };
4645
4646 // findSlot: locate the Src slot a getOperandBits result depends on,
4647 // including negated (XOR with -1) patterns that getOperandBits
4648 // resolves via the NOT shortcut (~SrcBits[I]).
4649 const uint8_t SrcBitsConst[3] = {0xf0, 0xcc, 0xaa};
4650 auto findSlot = [&](uint8_t Bits, SDValue Op,
4651 const SmallVectorImpl<SDValue> &S) -> int {
4652 SDValue NegatedInner;
4653 bool IsNegationOp =
4654 Op.getOpcode() == ISD::XOR && isAllOnesConstant(Op.getOperand(1));
4655 if (IsNegationOp)
4656 NegatedInner = Op.getOperand(0);
4657 for (int I = 0; I < (int)S.size(); I++) {
4658 if (Bits == SrcBitsConst[I] && S[I] == Op)
4659 return I;
4660 if (IsNegationOp && Bits == (uint8_t)~SrcBitsConst[I] &&
4661 S[I] == NegatedInner)
4662 return I;
4663 }
4664 return -1;
4665 };
4666
4667 bool Stale = false;
4668
4669 // (A) LHS recursed: its truth table is against SrcAfterLHS.
4670 // Check if RHS recursion mutated a slot that LHSBits uses.
4671 if (LHSOp.first) {
4672 for (int I = 0; I < (int)SrcAfterLHS.size() && I < 3; I++) {
4673 if (I < (int)Src.size() && Src[I] != SrcAfterLHS[I] &&
4674 dependsOnSlot(LHSBits, I)) {
4675 Stale = true;
4676 break;
4677 }
4678 }
4679 }
4680
4681 // (B) RHS did not recurse: RHSBits from getOperandBits is against
4682 // SrcBeforeRecurse. Check if that slot was mutated since then.
4683 if (!Stale && !RHSOp.first) {
4684 int Slot = findSlot(RHSBitsOrig, RHS, SrcBeforeRecurse);
4685 if (Slot >= 0 &&
4686 (Slot >= (int)Src.size() || Src[Slot] != SrcBeforeRecurse[Slot]))
4687 Stale = true;
4688 }
4689
4690 // (C) LHS did not recurse: LHSBits from getOperandBits is against
4691 // SrcBeforeRecurse. Check if that slot was mutated since then.
4692 if (!Stale && !LHSOp.first) {
4693 int Slot = findSlot(LHSBitsOrig, LHS, SrcBeforeRecurse);
4694 if (Slot >= 0 &&
4695 (Slot >= (int)Src.size() || Src[Slot] != SrcBeforeRecurse[Slot]))
4696 Stale = true;
4697 }
4698
4699 if (Stale) {
4700 Src = std::move(SrcBeforeRecurse);
4701 LHSBits = LHSBitsOrig;
4702 RHSBits = RHSBitsOrig;
4703 NumOpcodes = 0;
4704 }
4705 break;
4706 }
4707 default:
4708 return std::make_pair(0, 0);
4709 }
4710
4711 uint8_t TTbl;
4712 switch (In.getOpcode()) {
4713 case ISD::AND:
4714 TTbl = LHSBits & RHSBits;
4715 break;
4716 case ISD::OR:
4717 TTbl = LHSBits | RHSBits;
4718 break;
4719 case ISD::XOR:
4720 TTbl = LHSBits ^ RHSBits;
4721 break;
4722 default:
4723 break;
4724 }
4725
4726 return std::make_pair(NumOpcodes + 1, TTbl);
4727}
4728
4729bool AMDGPUDAGToDAGISel::SelectBITOP3(SDValue In, SDValue &Src0, SDValue &Src1,
4730 SDValue &Src2, SDValue &Tbl) const {
4732 uint8_t TTbl;
4733 unsigned NumOpcodes;
4734
4735 std::tie(NumOpcodes, TTbl) = BitOp3_Op(In, Src);
4736
4737 // Src.empty() case can happen if all operands are all zero or all ones.
4738 // Normally it shall be optimized out before reaching this.
4739 if (NumOpcodes < 2 || Src.empty())
4740 return false;
4741
4742 // For a uniform case threshold should be higher to account for moves between
4743 // VGPRs and SGPRs. It needs one operand in a VGPR, rest two can be in SGPRs
4744 // and a readtfirstlane after.
4745 if (NumOpcodes < 4 && !In->isDivergent())
4746 return false;
4747
4748 if (NumOpcodes == 2 && In.getValueType() == MVT::i32) {
4749 // Avoid using BITOP3 for OR3, XOR3, AND_OR. This is not faster but makes
4750 // asm more readable. This cannot be modeled with AddedComplexity because
4751 // selector does not know how many operations did we match.
4752 if ((In.getOpcode() == ISD::XOR || In.getOpcode() == ISD::OR) &&
4753 (In.getOperand(0).getOpcode() == In.getOpcode() ||
4754 In.getOperand(1).getOpcode() == In.getOpcode()))
4755 return false;
4756
4757 if (In.getOpcode() == ISD::OR &&
4758 (In.getOperand(0).getOpcode() == ISD::AND ||
4759 In.getOperand(1).getOpcode() == ISD::AND))
4760 return false;
4761 }
4762
4763 // Last operand can be ignored, turning a ternary operation into a binary.
4764 // For example: (~a & b & c) | (~a & b & ~c) -> (~a & b). We can replace
4765 // 'c' with 'a' here without changing the answer. In some pathological
4766 // cases it should be possible to get an operation with a single operand
4767 // too if optimizer would not catch it.
4768 while (Src.size() < 3)
4769 Src.push_back(Src[0]);
4770
4771 Src0 = Src[0];
4772 Src1 = Src[1];
4773 Src2 = Src[2];
4774
4775 Tbl = CurDAG->getTargetConstant(TTbl, SDLoc(In), MVT::i32);
4776 return true;
4777}
4778
4779SDValue AMDGPUDAGToDAGISel::getHi16Elt(SDValue In) const {
4780 if (In.getOpcode() == ISD::POISON)
4781 return CurDAG->getPOISON(MVT::i32);
4782
4783 if (In.getOpcode() == ISD::UNDEF)
4784 return CurDAG->getUNDEF(MVT::i32);
4785
4786 if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(In)) {
4787 SDLoc SL(In);
4788 return CurDAG->getConstant(C->getZExtValue() << 16, SL, MVT::i32);
4789 }
4790
4791 if (ConstantFPSDNode *C = dyn_cast<ConstantFPSDNode>(In)) {
4792 SDLoc SL(In);
4793 return CurDAG->getConstant(
4794 C->getValueAPF().bitcastToAPInt().getZExtValue() << 16, SL, MVT::i32);
4795 }
4796
4797 SDValue Src;
4798 if (isExtractHiElt(In, Src))
4799 return Src;
4800
4801 return SDValue();
4802}
4803
4804bool AMDGPUDAGToDAGISel::isVGPRImm(const SDNode * N) const {
4805 assert(CurDAG->getTarget().getTargetTriple().isAMDGCN());
4806
4807 const SIRegisterInfo *SIRI = Subtarget->getRegisterInfo();
4808 const SIInstrInfo *SII = Subtarget->getInstrInfo();
4809
4810 unsigned Limit = 0;
4811 bool AllUsesAcceptSReg = true;
4812 for (SDNode::use_iterator U = N->use_begin(), E = SDNode::use_end();
4813 Limit < 10 && U != E; ++U, ++Limit) {
4814 const TargetRegisterClass *RC =
4815 getOperandRegClass(U->getUser(), U->getOperandNo());
4816
4817 // If the register class is unknown, it could be an unknown
4818 // register class that needs to be an SGPR, e.g. an inline asm
4819 // constraint
4820 if (!RC || SIRI->isSGPRClass(RC))
4821 return false;
4822
4823 if (RC != &AMDGPU::VS_32RegClass && RC != &AMDGPU::VS_64RegClass &&
4824 RC != &AMDGPU::VS_64_Align2RegClass) {
4825 AllUsesAcceptSReg = false;
4826 SDNode *User = U->getUser();
4827 if (User->isMachineOpcode()) {
4828 unsigned Opc = User->getMachineOpcode();
4829 const MCInstrDesc &Desc = SII->get(Opc);
4830 if (Desc.isCommutable()) {
4831 unsigned OpIdx = Desc.getNumDefs() + U->getOperandNo();
4832 unsigned CommuteIdx1 = TargetInstrInfo::CommuteAnyOperandIndex;
4833 if (SII->findCommutedOpIndices(Desc, OpIdx, CommuteIdx1)) {
4834 unsigned CommutedOpNo = CommuteIdx1 - Desc.getNumDefs();
4835 const TargetRegisterClass *CommutedRC =
4836 getOperandRegClass(U->getUser(), CommutedOpNo);
4837 if (CommutedRC == &AMDGPU::VS_32RegClass ||
4838 CommutedRC == &AMDGPU::VS_64RegClass ||
4839 CommutedRC == &AMDGPU::VS_64_Align2RegClass)
4840 AllUsesAcceptSReg = true;
4841 }
4842 }
4843 }
4844 // If "AllUsesAcceptSReg == false" so far we haven't succeeded
4845 // commuting current user. This means have at least one use
4846 // that strictly require VGPR. Thus, we will not attempt to commute
4847 // other user instructions.
4848 if (!AllUsesAcceptSReg)
4849 break;
4850 }
4851 }
4852 return !AllUsesAcceptSReg && (Limit < 10);
4853}
4854
4857 *static_cast<const AMDGPUTargetLowering*>(getTargetLowering());
4858 bool IsModified = false;
4859 do {
4860 IsModified = false;
4861
4862 // Go over all selected nodes and try to fold them a bit more
4863 SelectionDAG::allnodes_iterator Position = CurDAG->allnodes_begin();
4864 while (Position != CurDAG->allnodes_end()) {
4865 SDNode *Node = &*Position++;
4867 if (!MachineNode)
4868 continue;
4869
4870 SDNode *ResNode = Lowering.PostISelFolding(MachineNode, *CurDAG);
4871 if (ResNode != Node) {
4872 if (ResNode)
4873 ReplaceUses(Node, ResNode);
4874 IsModified = true;
4875 }
4876 }
4877 CurDAG->RemoveDeadNodes();
4878 } while (IsModified);
4879}
4880
4885
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
unsigned Imm
unsigned uint64_t
static bool getBaseWithOffsetUsingSplitOR(SelectionDAG &DAG, SDValue Addr, SDValue &N0, SDValue &N1)
static SDValue SelectSAddrFI(SelectionDAG *CurDAG, SDValue SAddr)
static SDValue matchExtFromI32orI32(SDValue Op, bool IsSigned, const SelectionDAG *DAG)
static MemSDNode * findMemSDNode(SDNode *N)
static bool IsCopyFromSGPR(const SIRegisterInfo &TRI, SDValue Val)
static SDValue combineBallotPattern(SDValue VCMP, bool &Negate)
static SDValue matchBF16FPExtendLike(SDValue Op, bool &IsExtractHigh)
static void checkWMMAElementsModifiersF16(BuildVectorSDNode *BV, std::function< bool(SDValue)> ModifierCheck)
Defines an instruction selector for the AMDGPU target.
Contains the definition of a TargetInstrInfo class that is common to all AMD GPUs.
static bool isNoUnsignedWrap(MachineInstr *Addr)
static bool isExtractHiElt(MachineRegisterInfo &MRI, Register In, Register &Out)
static std::pair< unsigned, uint8_t > BitOp3_Op(Register R, SmallVectorImpl< Register > &Src, const MachineRegisterInfo &MRI)
static unsigned gwsIntrinToOpcode(unsigned IntrID)
Base class for AMDGPU specific classes of TargetSubtarget.
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
const HexagonInstrInfo * TII
const AbstractManglingParser< Derived, Alloc >::OperatorInfo AbstractManglingParser< Derived, Alloc >::Ops[]
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
Register Reg
Register const TargetRegisterInfo * TRI
Promote Memory to Register
Definition Mem2Reg.cpp:110
FunctionAnalysisManager FAM
#define INITIALIZE_PASS_DEPENDENCY(depName)
Definition PassSupport.h:42
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
Definition PassSupport.h:44
#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis)
Definition PassSupport.h:39
Provides R600 specific target descriptions.
Interface definition for R600RegisterInfo.
const SmallVectorImpl< MachineOperand > & Cond
SI DAG Lowering interface definition.
#define LLVM_DEBUG(...)
Definition Debug.h:119
LLVM IR instance of the generic uniformity analysis.
Value * RHS
Value * LHS
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - This function should be overriden by passes that need analysis information to do t...
AMDGPUDAGToDAGISelLegacy(TargetMachine &TM, CodeGenOptLevel OptLevel)
bool runOnMachineFunction(MachineFunction &MF) override
runOnMachineFunction - This method must be overloaded to perform the desired machine code transformat...
StringRef getPassName() const override
getPassName - Return a nice clean name for a pass.
AMDGPU specific code to select AMDGPU machine instructions for SelectionDAG operations.
bool isSDWAOperand(const SDNode *N) const
void SelectBuildVector(SDNode *N, unsigned RegClassID)
void Select(SDNode *N) override
Main hook for targets to transform nodes into machine nodes.
bool widenRegionLoad16(SDNode *N) const
bool runOnMachineFunction(MachineFunction &MF) override
void PreprocessISelDAG() override
PreprocessISelDAG - This hook allows targets to hack on the graph before instruction selection starts...
void PostprocessISelDAG() override
PostprocessISelDAG() - This hook allows the target to hack on the graph right after selection.
bool matchLoadD16FromBuildVector(SDNode *N) const
PreservedAnalyses run(MachineFunction &MF, MachineFunctionAnalysisManager &MFAM)
static SDValue stripBitcast(SDValue Val)
static const fltSemantics & BFloat()
Definition APFloat.h:303
static const fltSemantics & IEEEhalf()
Definition APFloat.h:302
Class for arbitrary precision integers.
Definition APInt.h:78
uint64_t getZExtValue() const
Get zero extended value.
Definition APInt.h:1560
bool isSignMask() const
Check if the APInt's value is returned by getSignMask.
Definition APInt.h:462
bool isMaxSignedValue() const
Determine if this is the largest signed value.
Definition APInt.h:401
int64_t getSExtValue() const
Get sign extended value.
Definition APInt.h:1582
unsigned countr_one() const
Count the number of trailing one bits.
Definition APInt.h:1676
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)
Get the result of an analysis pass for a given IR unit.
Represent the analysis usage information of a pass.
AnalysisUsage & addRequired()
Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:40
size_t size() const
Get the array size.
Definition ArrayRef.h:141
LLVM Basic Block Representation.
Definition BasicBlock.h:62
const Instruction * getTerminator() const LLVM_READONLY
Returns the terminator instruction; assumes that the block is well-formed.
Definition BasicBlock.h:237
A "pseudo-class" with methods for operating on BUILD_VECTORs.
LLVM_ABI SDValue getSplatValue(const APInt &DemandedElts, BitVector *UndefElements=nullptr) const
Returns the demanded splatted value or a null value if this is not a splat.
uint64_t getZExtValue() const
const APInt & getAPIntValue() const
int64_t getSExtValue() const
Analysis pass which computes a DominatorTree.
Definition Dominators.h:241
Legacy analysis pass which computes a DominatorTree.
Definition Dominators.h:277
Concrete subclass of DominatorTreeBase that is used to compute a normal dominator tree.
Definition Dominators.h:122
FunctionPass class - This class is used to implement most global optimizations.
Definition Pass.h:314
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function.
Definition Function.cpp:356
const SIInstrInfo * getInstrInfo() const override
bool useRealTrue16Insts() const
Return true if real (non-fake) variants of True16 instructions using 16-bit registers should be code-...
Generation getGeneration() const
void checkSubtargetFeatures(const Function &F) const
Diagnose inconsistent subtarget features before attempting to codegen function F.
LLVM_ABI void diagnose(const DiagnosticInfo &DI)
Report a message to the currently installed diagnostic handler.
This class is used to represent ISD::LOAD nodes.
const SDValue & getBasePtr() const
ISD::LoadExtType getExtensionType() const
Return whether this is a plain node, or one of the varieties of value-extending loads.
Analysis pass that exposes the LoopInfo for a function.
Definition LoopInfo.h:594
SmallVector< LoopT *, 4 > getLoopsInPreorder() const
Return all of the loops in the function in preorder across the loop nests, with siblings in forward p...
The legacy pass manager's analysis pass to compute loop information.
Definition LoopInfo.h:619
unsigned getID() const
getID() - Return the register class ID number.
LLVM_ABI StringRef getString() const
Definition Metadata.cpp:615
Machine Value Type.
static MVT getIntegerVT(unsigned BitWidth)
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
Function & getFunction()
Return the LLVM function that this machine code represents.
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
const TargetRegisterClass * getRegClass(Register Reg) const
Return the register class of the specified virtual register.
An SDNode that represents everything that will be needed to construct a MachineInstr.
This is an abstract virtual class for memory operations.
unsigned getAddressSpace() const
Return the address space for the associated pointer.
MachineMemOperand * getMemOperand() const
Return the unique MachineMemOperand object describing the memory reference performed by operation.
const SDValue & getChain() const
EVT getMemoryVT() const
Return the type of the in-memory value.
AnalysisType & getAnalysis() const
getAnalysis<AnalysisType>() - This function is used by subclasses to get to the analysis information ...
A set of analyses that are preserved following a run of a transformation pass.
Definition Analysis.h:112
Wrapper class representing virtual and physical registers.
Definition Register.h:20
Wrapper class for IR location info (IR ordering and DebugLoc) to be passed into SDNode creation funct...
Represents one node in the SelectionDAG.
const APInt & getAsAPIntVal() const
Helper method returns the APInt value of a ConstantSDNode.
unsigned getOpcode() const
Return the SelectionDAG opcode value for this node.
bool isDivergent() const
SDNodeFlags getFlags() const
uint64_t getAsZExtVal() const
Helper method returns the zero-extended integer value of a ConstantSDNode.
unsigned getNumOperands() const
Return the number of values used by this operation.
const SDValue & getOperand(unsigned Num) const
uint64_t getConstantOperandVal(unsigned Num) const
Helper method returns the integer value of a ConstantSDNode operand.
bool isPredecessorOf(const SDNode *N) const
Return true if this node is a predecessor of N.
bool isAnyAdd() const
Returns true if the node type is ADD or PTRADD.
static use_iterator use_end()
Unlike LLVM values, Selection DAG nodes may return multiple values as the result of a computation.
bool isUndef() const
SDNode * getNode() const
get the SDNode which holds the desired result
SDValue getValue(unsigned R) const
EVT getValueType() const
Return the ValueType of the referenced return value.
TypeSize getValueSizeInBits() const
Returns the size of the value in bits.
const SDValue & getOperand(unsigned i) const
uint64_t getConstantOperandVal(unsigned i) const
unsigned getOpcode() const
static unsigned getMaxMUBUFImmOffset(const GCNSubtarget &ST)
bool findCommutedOpIndices(const MachineInstr &MI, unsigned &SrcOpIdx0, unsigned &SrcOpIdx1) const override
static unsigned getSubRegFromChannel(unsigned Channel, unsigned NumRegs=1)
static LLVM_READONLY const TargetRegisterClass * getSGPRClassForBitWidth(unsigned BitWidth)
static bool isSGPRClass(const TargetRegisterClass *RC)
bool runOnMachineFunction(MachineFunction &MF) override
runOnMachineFunction - This method must be overloaded to perform the desired machine code transformat...
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - Subclasses that override getAnalysisUsage must call this.
SelectionDAGISelLegacy(char &ID, std::unique_ptr< SelectionDAGISel > S)
SelectionDAGISelPass(std::unique_ptr< SelectionDAGISel > Selector)
LLVM_ABI PreservedAnalyses run(MachineFunction &MF, MachineFunctionAnalysisManager &MFAM)
std::unique_ptr< FunctionLoweringInfo > FuncInfo
const TargetLowering * TLI
const TargetInstrInfo * TII
void ReplaceUses(SDValue F, SDValue T)
ReplaceUses - replace all uses of the old node F with the use of the new node T.
void ReplaceNode(SDNode *F, SDNode *T)
Replace all uses of F with T, then remove F from the DAG.
SelectionDAGISel(TargetMachine &tm, CodeGenOptLevel OL=CodeGenOptLevel::Default)
virtual bool runOnMachineFunction(MachineFunction &mf)
const TargetLowering * getTargetLowering() const
This is used to represent a portion of an LLVM function in a low-level Data Dependence DAG representa...
LLVM_ABI MachineSDNode * getMachineNode(unsigned Opcode, const SDLoc &dl, EVT VT)
These are used for target selectors to create a new node with specified return type(s),...
LLVM_ABI SDValue getRegister(Register Reg, EVT VT)
SDValue getTargetFrameIndex(int FI, EVT VT)
LLVM_ABI bool SignBitIsZero(SDValue Op, unsigned Depth=0) const
Return true if the sign bit of Op is known to be zero.
SDValue getTargetConstant(uint64_t Val, const SDLoc &DL, EVT VT, bool isOpaque=false)
LLVM_ABI bool isBaseWithConstantOffset(SDValue Op) const
Return true if the specified operand is an ISD::ADD with a ConstantSDNode on the right-hand side,...
MachineFunction & getMachineFunction() const
LLVM_ABI KnownBits computeKnownBits(SDValue Op, unsigned Depth=0) const
Determine which bits of Op are known to be either zero or one and return them in Known.
ilist< SDNode >::iterator allnodes_iterator
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
constexpr const char * data() const
Get a pointer to the start of the string (which may not be null terminated).
Definition StringRef.h:138
static const unsigned CommuteAnyOperandIndex
Primary interface to the complete machine description for the target machine.
Analysis pass which computes UniformityInfo.
Legacy analysis pass which computes a CycleInfo.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
@ REGION_ADDRESS
Address space for region memory. (GDS)
@ LOCAL_ADDRESS
Address space for local memory.
@ FLAT_ADDRESS
Address space for flat memory.
@ GLOBAL_ADDRESS
Address space for global memory (RAT0, VTX0).
@ PRIVATE_ADDRESS
Address space for private memory.
constexpr char Args[]
Key for Kernel::Metadata::mArgs.
std::optional< int64_t > getSMRDEncodedLiteralOffset32(const MCSubtargetInfo &ST, int64_t ByteOffset)
bool isGFX12Plus(const MCSubtargetInfo &STI)
constexpr int64_t getNullPointerValue(unsigned AS)
Get the null pointer value for the given address space.
bool isValid32BitLiteral(uint64_t Val, bool IsFP64)
bool isInlinableLiteral32(int32_t Literal, bool HasInv2Pi)
bool hasSMRDSignedImmOffset(const MCSubtargetInfo &ST)
std::optional< int64_t > getSMRDEncodedOffset(const MCSubtargetInfo &ST, int64_t ByteOffset, bool IsBuffer, bool HasSOffset)
constexpr std::underlying_type_t< E > Mask()
Get a bitmask with 1s in all places up to the high-order bit of E's largest value.
@ SETCC
SetCC operator - This evaluates to a true value iff the condition is true.
Definition ISDOpcodes.h:837
@ STACKRESTORE
STACKRESTORE has two operands, an input chain and a pointer to restore to it returns an output chain.
@ PTRADD
PTRADD represents pointer arithmetic semantics, for targets that opt in using shouldPreservePtrArith(...
@ POISON
POISON - A poison node.
Definition ISDOpcodes.h:238
@ SMUL_LOHI
SMUL_LOHI/UMUL_LOHI - Multiply two integers of type iN, producing a signed/unsigned value of type i[2...
Definition ISDOpcodes.h:277
@ FMAD
FMAD - Perform a * b + c, while getting the same result as the separately rounded operations.
Definition ISDOpcodes.h:527
@ ADD
Simple integer binary arithmetic operators.
Definition ISDOpcodes.h:266
@ LOAD
LOAD and STORE have token chains as their first operand, then the same operands as an LLVM load/store...
@ ANY_EXTEND
ANY_EXTEND - Used for integer types. The high bits are undefined.
Definition ISDOpcodes.h:871
@ FMA
FMA - Perform a * b + c with no intermediate rounding step.
Definition ISDOpcodes.h:523
@ INTRINSIC_VOID
OUTCHAIN = INTRINSIC_VOID(INCHAIN, INTRINSICID, arg1, arg2, ...) This node represents a target intrin...
Definition ISDOpcodes.h:222
@ SINT_TO_FP
[SU]INT_TO_FP - These operators convert integers (whose interpreted sign depends on the first letter)...
Definition ISDOpcodes.h:898
@ FADD
Simple binary floating point operators.
Definition ISDOpcodes.h:420
@ BITCAST
BITCAST - This operator converts between integer, vector and FP values, as if the value was stored to...
@ BUILD_PAIR
BUILD_PAIR - This is the opposite of EXTRACT_ELEMENT in some ways.
Definition ISDOpcodes.h:256
@ FLDEXP
FLDEXP - ldexp, inspired by libm (op0 * 2**op1).
@ CONVERGENCECTRL_GLUE
This does not correspond to any convergence control intrinsic.
@ SIGN_EXTEND
Conversion operators.
Definition ISDOpcodes.h:862
@ SCALAR_TO_VECTOR
SCALAR_TO_VECTOR(VAL) - This represents the operation of loading a scalar value into element 0 of the...
Definition ISDOpcodes.h:675
@ FNEG
Perform various unary floating-point operations inspired by libm.
@ FCANONICALIZE
Returns platform specific canonical encoding of a floating point number.
Definition ISDOpcodes.h:546
@ ATOMIC_LOAD
Val, OUTCHAIN = ATOMIC_LOAD(INCHAIN, ptr) This corresponds to "load atomic" instruction.
@ UNDEF
UNDEF - An undefined node.
Definition ISDOpcodes.h:235
@ CopyFromReg
CopyFromReg - This node indicates that the input value is a virtual or physical register that is defi...
Definition ISDOpcodes.h:232
@ SHL
Shift and rotation operations.
Definition ISDOpcodes.h:779
@ VECTOR_SHUFFLE
VECTOR_SHUFFLE(VEC1, VEC2) - Returns a vector, of the same type as VEC1/VEC2.
Definition ISDOpcodes.h:659
@ EXTRACT_VECTOR_ELT
EXTRACT_VECTOR_ELT(VECTOR, IDX) - Returns a single element from VECTOR identified by the (potentially...
Definition ISDOpcodes.h:581
@ CopyToReg
CopyToReg - This node has three operands: a chain, a register number to set to this value,...
Definition ISDOpcodes.h:226
@ ZERO_EXTEND
ZERO_EXTEND - Used for integer types, zeroing the new bits.
Definition ISDOpcodes.h:868
@ FMINNUM
FMINNUM/FMAXNUM - Perform floating-point minimum maximum on two values, following IEEE-754 definition...
@ TargetFrameIndex
Definition ISDOpcodes.h:189
@ SIGN_EXTEND_INREG
SIGN_EXTEND_INREG - This operator atomically performs a SHL/SRA pair to sign extend a small value in ...
Definition ISDOpcodes.h:906
@ FP_EXTEND
X = FP_EXTEND(Y) - Extend a smaller FP type into a larger FP type.
Definition ISDOpcodes.h:996
@ UADDO_CARRY
Carry-using nodes for multiple precision addition and subtraction.
Definition ISDOpcodes.h:331
@ AND
Bitwise operators - logical and, logical or, logical xor.
Definition ISDOpcodes.h:749
@ INTRINSIC_WO_CHAIN
RESULT = INTRINSIC_WO_CHAIN(INTRINSICID, arg1, arg2, ...) This node represents a target intrinsic fun...
Definition ISDOpcodes.h:207
@ FP_ROUND
X = FP_ROUND(Y, TRUNC) - Rounding 'Y' from a larger floating point type down to the precision of the ...
Definition ISDOpcodes.h:977
@ TRUNCATE
TRUNCATE - Completely drop the high bits.
Definition ISDOpcodes.h:874
@ BRCOND
BRCOND - Conditional branch.
@ INTRINSIC_W_CHAIN
RESULT,OUTCHAIN = INTRINSIC_W_CHAIN(INCHAIN, INTRINSICID, arg1, ...) This node represents a target in...
Definition ISDOpcodes.h:215
@ BUILD_VECTOR
BUILD_VECTOR(ELT0, ELT1, ELT2, ELT3,...) - Return a fixed-width vector with the specified,...
Definition ISDOpcodes.h:561
bool isExtOpcode(unsigned Opcode)
LLVM_ABI bool isBuildVectorAllZeros(const SDNode *N)
Return true if the specified node is a BUILD_VECTOR where all of the elements are 0 or undef.
CondCode
ISD::CondCode enum - These are ordered carefully to make the bitfields below work out,...
LoadExtType
LoadExtType enum - This enum defines the three variants of LOADEXT (load with extension).
@ User
could "use" a pointer
This is an optimization pass for GlobalISel generic memory operations.
@ Offset
Definition DWP.cpp:577
constexpr bool isInt(int64_t x)
Checks if an integer fits into the given bit width.
Definition MathExtras.h:166
LLVM_ABI bool isNullConstant(SDValue V)
Returns true if V is a constant integer zero.
@ Undef
Value of the register doesn't matter.
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
constexpr bool isMask_32(uint32_t Value)
Return true if the argument is a non-empty sequence of ones starting at the least significant bit wit...
Definition MathExtras.h:256
LLVM_ABI LLT getLLTForMVT(MVT Ty)
Get a rough equivalent of an LLT for a given MVT.
AnalysisManager< MachineFunction > MachineFunctionAnalysisManager
Op::Description Desc
constexpr int popcount(T Value) noexcept
Count the number of set bits in a value.
Definition bit.h:156
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
Definition InstrProf.h:143
unsigned Log2_32(uint32_t Value)
Return the floor log base 2 of the specified value, -1 if the value is zero.
Definition MathExtras.h:326
bool isBoolSGPR(SDValue V)
constexpr bool isPowerOf2_32(uint32_t Value)
Return true if the argument is a power of two > 0.
Definition MathExtras.h:280
constexpr uint32_t Hi_32(uint64_t Value)
Return the high 32 bits of a 64 bit value.
Definition MathExtras.h:151
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:209
static bool getConstantValue(SDValue N, uint32_t &Out)
constexpr bool isUInt(uint64_t x)
Checks if an unsigned integer fits into the given bit width.
Definition MathExtras.h:190
CodeGenOptLevel
Code generation optimization level.
Definition CodeGen.h:227
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
constexpr uint32_t Lo_32(uint64_t Value)
Return the low 32 bits of a 64 bit value.
Definition MathExtras.h:156
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
Definition Casting.h:547
LLVM_ATTRIBUTE_VISIBILITY_DEFAULT AnalysisKey InnerAnalysisManagerProxy< AnalysisManagerT, IRUnitT, ExtraArgTs... >::Key
FunctionPass * createAMDGPUISelDag(TargetMachine &TM, CodeGenOptLevel OptLevel)
This pass converts a legalized DAG into a AMDGPU-specific.
@ SMax
Signed integer max implemented in terms of select(cmp()).
@ And
Bitwise or logical AND of integers.
@ Sub
Subtraction of integers.
@ Add
Sum of integers.
DWARFExpression::Operation Op
unsigned M0(unsigned Val)
Definition VE.h:376
LLVM_ABI ConstantSDNode * isConstOrConstSplat(SDValue N, bool AllowUndefs=false, bool AllowTruncation=false)
Returns the SDNode if it is a constant splat BuildVector or constant int.
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
constexpr T maskTrailingOnes(unsigned N)
Create a bitmask with the N right-most bits set to 1, and all other bits set to 0.
Definition MathExtras.h:78
LLVM_ABI bool isAllOnesConstant(SDValue V)
Returns true if V is an integer constant with all bits set.
MCRegisterClass TargetRegisterClass
Definition FastISel.h:58
Implement std::hash so that hash_code can be used in STL containers.
Definition BitVector.h:878
#define N
Extended Value Type.
Definition ValueTypes.h:35
EVT changeTypeToInteger() const
Return the type converted to an equivalently sized integer or vector with integer element type.
Definition ValueTypes.h:129
TypeSize getSizeInBits() const
Return the size of the specified value type in bits.
Definition ValueTypes.h:396
uint64_t getScalarSizeInBits() const
Definition ValueTypes.h:408
MVT getSimpleVT() const
Return the SimpleValueType held in the specified simple EVT.
Definition ValueTypes.h:339
bool isVector() const
Return true if this is a vector value type.
Definition ValueTypes.h:176
bool bitsEq(EVT VT) const
Return true if this has the same number of bits as VT.
Definition ValueTypes.h:279
EVT getVectorElementType() const
Given a vector type, return the type of each element.
Definition ValueTypes.h:351
bool isScalarInteger() const
Return true if this is an integer, but not a vector.
Definition ValueTypes.h:165
unsigned getVectorNumElements() const
Given a vector type, return the number of elements it contains.
Definition ValueTypes.h:359
static KnownBits makeConstant(const APInt &C)
Create known bits from a known constant.
Definition KnownBits.h:315
static KnownBits add(const KnownBits &LHS, const KnownBits &RHS, bool NSW=false, bool NUW=false, bool SelfAdd=false)
Compute knownbits resulting from addition of LHS and RHS.
Definition KnownBits.h:361
APInt getMaxValue() const
Return the maximal unsigned value possible given these KnownBits.
Definition KnownBits.h:146
APInt getMinValue() const
Return the minimal unsigned value possible given these KnownBits.
Definition KnownBits.h:130
static unsigned getSubRegFromChannel(unsigned Channel)
bool hasNoUnsignedWrap() const
This represents a list of ValueType's that has been intern'd by a SelectionDAG.