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