34#include "llvm/IR/IntrinsicsSPIRV.h"
37#define DEBUG_TYPE "spirv-isel"
40namespace CL = SPIRV::OpenCLExtInst;
41namespace GL = SPIRV::GLSLExtInst;
44 std::vector<std::pair<SPIRV::InstructionSet::InstructionSet, uint32_t>>;
48#define GET_GLOBALISEL_PREDICATE_BITSET
49#include "SPIRVGenGlobalISel.inc"
50#undef GET_GLOBALISEL_PREDICATE_BITSET
77#define GET_GLOBALISEL_PREDICATES_DECL
78#include "SPIRVGenGlobalISel.inc"
79#undef GET_GLOBALISEL_PREDICATES_DECL
81#define GET_GLOBALISEL_TEMPORARIES_DECL
82#include "SPIRVGenGlobalISel.inc"
83#undef GET_GLOBALISEL_TEMPORARIES_DECL
105 bool IsSigned)
const;
115 unsigned Opcode)
const;
118 unsigned Opcode)
const;
135 unsigned NegateOpcode = 0)
const;
189 template <
bool Signed>
192 template <
bool Signed>
205 bool IsSigned)
const;
207 bool IsSigned,
unsigned Opcode)
const;
209 bool IsSigned)
const;
215 bool IsSigned)
const;
248 [[maybe_unused]]
bool selectExtInst(
Register ResVReg,
251 GL::GLSLExtInst GLInst)
const;
256 GL::GLSLExtInst GLInst)
const;
283 std::pair<Register, bool>
285 const SPIRVType *ResType =
nullptr)
const;
297 SPIRV::StorageClass::StorageClass SC)
const;
305 Register IndexReg,
bool IsNonUniform,
311 bool loadVec3BuiltinInputID(SPIRV::BuiltIn::BuiltIn BuiltInValue,
318#define GET_GLOBALISEL_IMPL
319#include "SPIRVGenGlobalISel.inc"
320#undef GET_GLOBALISEL_IMPL
326 TRI(*ST.getRegisterInfo()), RBI(RBI), GR(*ST.getSPIRVGlobalRegistry()),
328#include
"SPIRVGenGlobalISel.inc"
331#include
"SPIRVGenGlobalISel.inc"
341 GR.setCurrentFunc(MF);
342 InstructionSelector::setupMF(MF, KB, CoverageInfo, PSI, BFI);
347 if (HasVRegsReset == &MF)
352 for (
unsigned I = 0, E =
MRI.getNumVirtRegs();
I != E; ++
I) {
354 LLT RegType =
MRI.getType(Reg);
362 for (
const auto &
MBB : MF) {
363 for (
const auto &
MI :
MBB) {
364 if (
MI.getOpcode() != SPIRV::ASSIGN_TYPE)
367 LLT DstType =
MRI.getType(DstReg);
369 LLT SrcType =
MRI.getType(SrcReg);
370 if (DstType != SrcType)
371 MRI.setType(DstReg,
MRI.getType(SrcReg));
375 if (DstRC != SrcRC && SrcRC)
376 MRI.setRegClass(DstReg, SrcRC);
387 for (
const auto &MO :
MI.all_defs()) {
389 if (Reg.isPhysical() || !
MRI.use_nodbg_empty(Reg))
392 if (
MI.getOpcode() == TargetOpcode::LOCAL_ESCAPE ||
MI.isFakeUse() ||
393 MI.isLifetimeMarker())
397 if (
MI.mayStore() ||
MI.isCall() ||
398 (
MI.mayLoad() &&
MI.hasOrderedMemoryRef()) ||
MI.isPosition() ||
399 MI.isDebugInstr() ||
MI.isTerminator() ||
MI.isJumpTableDebugInfo())
405 resetVRegsType(*
I.getParent()->getParent());
407 assert(
I.getParent() &&
"Instruction should be in a basic block!");
408 assert(
I.getParent()->getParent() &&
"Instruction should be in a function!");
413 if (Opcode == SPIRV::ASSIGN_TYPE) {
414 Register DstReg =
I.getOperand(0).getReg();
415 Register SrcReg =
I.getOperand(1).getReg();
416 auto *
Def =
MRI->getVRegDef(SrcReg);
418 bool Res = selectImpl(
I, *CoverageInfo);
420 if (!Res &&
Def->getOpcode() != TargetOpcode::G_CONSTANT) {
421 dbgs() <<
"Unexpected pattern in ASSIGN_TYPE.\nInstruction: ";
425 assert(Res ||
Def->getOpcode() == TargetOpcode::G_CONSTANT);
432 MRI->setRegClass(SrcReg,
MRI->getRegClass(DstReg));
433 MRI->replaceRegWith(SrcReg, DstReg);
434 GR.invalidateMachineInstr(&
I);
435 I.removeFromParent();
437 }
else if (
I.getNumDefs() == 1) {
444 if (DeadMIs.contains(&
I)) {
449 GR.invalidateMachineInstr(&
I);
454 if (
I.getNumOperands() !=
I.getNumExplicitOperands()) {
455 LLVM_DEBUG(
errs() <<
"Generic instr has unexpected implicit operands\n");
461 bool HasDefs =
I.getNumDefs() > 0;
463 SPIRVType *ResType = HasDefs ? GR.getSPIRVTypeForVReg(ResVReg) :
nullptr;
464 assert(!HasDefs || ResType ||
I.getOpcode() == TargetOpcode::G_GLOBAL_VALUE);
465 if (spvSelect(ResVReg, ResType,
I)) {
467 for (
unsigned i = 0; i <
I.getNumDefs(); ++i)
469 GR.invalidateMachineInstr(&
I);
470 I.removeFromParent();
478 case TargetOpcode::G_CONSTANT:
480 case TargetOpcode::G_SADDO:
481 case TargetOpcode::G_SSUBO:
491 if (DstRC != SrcRC && SrcRC)
492 MRI->setRegClass(DestReg, SrcRC);
493 return BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
494 TII.get(TargetOpcode::COPY))
500bool SPIRVInstructionSelector::spvSelect(
Register ResVReg,
503 const unsigned Opcode =
I.getOpcode();
505 return selectImpl(
I, *CoverageInfo);
507 case TargetOpcode::G_CONSTANT:
508 return selectConst(ResVReg, ResType,
I.getOperand(1).getCImm()->getValue(),
510 case TargetOpcode::G_GLOBAL_VALUE:
511 return selectGlobalValue(ResVReg,
I);
512 case TargetOpcode::G_IMPLICIT_DEF:
513 return selectOpUndef(ResVReg, ResType,
I);
514 case TargetOpcode::G_FREEZE:
515 return selectFreeze(ResVReg, ResType,
I);
517 case TargetOpcode::G_INTRINSIC:
518 case TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS:
519 case TargetOpcode::G_INTRINSIC_CONVERGENT:
520 case TargetOpcode::G_INTRINSIC_CONVERGENT_W_SIDE_EFFECTS:
521 return selectIntrinsic(ResVReg, ResType,
I);
522 case TargetOpcode::G_BITREVERSE:
523 return selectBitreverse(ResVReg, ResType,
I);
525 case TargetOpcode::G_BUILD_VECTOR:
526 return selectBuildVector(ResVReg, ResType,
I);
527 case TargetOpcode::G_SPLAT_VECTOR:
528 return selectSplatVector(ResVReg, ResType,
I);
530 case TargetOpcode::G_SHUFFLE_VECTOR: {
532 auto MIB =
BuildMI(BB,
I,
I.getDebugLoc(),
TII.get(SPIRV::OpVectorShuffle))
534 .
addUse(GR.getSPIRVTypeID(ResType))
535 .
addUse(
I.getOperand(1).getReg())
536 .
addUse(
I.getOperand(2).getReg());
537 for (
auto V :
I.getOperand(3).getShuffleMask())
541 case TargetOpcode::G_MEMMOVE:
542 case TargetOpcode::G_MEMCPY:
543 case TargetOpcode::G_MEMSET:
544 return selectMemOperation(ResVReg,
I);
546 case TargetOpcode::G_ICMP:
547 return selectICmp(ResVReg, ResType,
I);
548 case TargetOpcode::G_FCMP:
549 return selectFCmp(ResVReg, ResType,
I);
551 case TargetOpcode::G_FRAME_INDEX:
552 return selectFrameIndex(ResVReg, ResType,
I);
554 case TargetOpcode::G_LOAD:
555 return selectLoad(ResVReg, ResType,
I);
556 case TargetOpcode::G_STORE:
557 return selectStore(
I);
559 case TargetOpcode::G_BR:
560 return selectBranch(
I);
561 case TargetOpcode::G_BRCOND:
562 return selectBranchCond(
I);
564 case TargetOpcode::G_PHI:
565 return selectPhi(ResVReg, ResType,
I);
567 case TargetOpcode::G_FPTOSI:
568 return selectUnOp(ResVReg, ResType,
I, SPIRV::OpConvertFToS);
569 case TargetOpcode::G_FPTOUI:
570 return selectUnOp(ResVReg, ResType,
I, SPIRV::OpConvertFToU);
572 case TargetOpcode::G_SITOFP:
573 return selectIToF(ResVReg, ResType,
I,
true, SPIRV::OpConvertSToF);
574 case TargetOpcode::G_UITOFP:
575 return selectIToF(ResVReg, ResType,
I,
false, SPIRV::OpConvertUToF);
577 case TargetOpcode::G_CTPOP:
578 return selectUnOp(ResVReg, ResType,
I, SPIRV::OpBitCount);
579 case TargetOpcode::G_SMIN:
580 return selectExtInst(ResVReg, ResType,
I, CL::s_min, GL::SMin);
581 case TargetOpcode::G_UMIN:
582 return selectExtInst(ResVReg, ResType,
I, CL::u_min, GL::UMin);
584 case TargetOpcode::G_SMAX:
585 return selectExtInst(ResVReg, ResType,
I, CL::s_max, GL::SMax);
586 case TargetOpcode::G_UMAX:
587 return selectExtInst(ResVReg, ResType,
I, CL::u_max, GL::UMax);
589 case TargetOpcode::G_SCMP:
590 return selectSUCmp(ResVReg, ResType,
I,
true);
591 case TargetOpcode::G_UCMP:
592 return selectSUCmp(ResVReg, ResType,
I,
false);
594 case TargetOpcode::G_STRICT_FMA:
595 case TargetOpcode::G_FMA:
596 return selectExtInst(ResVReg, ResType,
I, CL::fma, GL::Fma);
598 case TargetOpcode::G_STRICT_FLDEXP:
599 return selectExtInst(ResVReg, ResType,
I, CL::ldexp);
601 case TargetOpcode::G_FPOW:
602 return selectExtInst(ResVReg, ResType,
I, CL::pow, GL::Pow);
603 case TargetOpcode::G_FPOWI:
604 return selectExtInst(ResVReg, ResType,
I, CL::pown);
606 case TargetOpcode::G_FEXP:
607 return selectExtInst(ResVReg, ResType,
I, CL::exp, GL::Exp);
608 case TargetOpcode::G_FEXP2:
609 return selectExtInst(ResVReg, ResType,
I, CL::exp2, GL::Exp2);
611 case TargetOpcode::G_FLOG:
612 return selectExtInst(ResVReg, ResType,
I, CL::log, GL::Log);
613 case TargetOpcode::G_FLOG2:
614 return selectExtInst(ResVReg, ResType,
I, CL::log2, GL::Log2);
615 case TargetOpcode::G_FLOG10:
616 return selectLog10(ResVReg, ResType,
I);
618 case TargetOpcode::G_FABS:
619 return selectExtInst(ResVReg, ResType,
I, CL::fabs, GL::FAbs);
620 case TargetOpcode::G_ABS:
621 return selectExtInst(ResVReg, ResType,
I, CL::s_abs, GL::SAbs);
623 case TargetOpcode::G_FMINNUM:
624 case TargetOpcode::G_FMINIMUM:
625 return selectExtInst(ResVReg, ResType,
I, CL::fmin, GL::NMin);
626 case TargetOpcode::G_FMAXNUM:
627 case TargetOpcode::G_FMAXIMUM:
628 return selectExtInst(ResVReg, ResType,
I, CL::fmax, GL::NMax);
630 case TargetOpcode::G_FCOPYSIGN:
631 return selectExtInst(ResVReg, ResType,
I, CL::copysign);
633 case TargetOpcode::G_FCEIL:
634 return selectExtInst(ResVReg, ResType,
I, CL::ceil, GL::Ceil);
635 case TargetOpcode::G_FFLOOR:
636 return selectExtInst(ResVReg, ResType,
I, CL::floor, GL::Floor);
638 case TargetOpcode::G_FCOS:
639 return selectExtInst(ResVReg, ResType,
I, CL::cos, GL::Cos);
640 case TargetOpcode::G_FSIN:
641 return selectExtInst(ResVReg, ResType,
I, CL::sin, GL::Sin);
642 case TargetOpcode::G_FTAN:
643 return selectExtInst(ResVReg, ResType,
I, CL::tan, GL::Tan);
644 case TargetOpcode::G_FACOS:
645 return selectExtInst(ResVReg, ResType,
I, CL::acos, GL::Acos);
646 case TargetOpcode::G_FASIN:
647 return selectExtInst(ResVReg, ResType,
I, CL::asin, GL::Asin);
648 case TargetOpcode::G_FATAN:
649 return selectExtInst(ResVReg, ResType,
I, CL::atan, GL::Atan);
650 case TargetOpcode::G_FATAN2:
651 return selectExtInst(ResVReg, ResType,
I, CL::atan2, GL::Atan2);
652 case TargetOpcode::G_FCOSH:
653 return selectExtInst(ResVReg, ResType,
I, CL::cosh, GL::Cosh);
654 case TargetOpcode::G_FSINH:
655 return selectExtInst(ResVReg, ResType,
I, CL::sinh, GL::Sinh);
656 case TargetOpcode::G_FTANH:
657 return selectExtInst(ResVReg, ResType,
I, CL::tanh, GL::Tanh);
659 case TargetOpcode::G_STRICT_FSQRT:
660 case TargetOpcode::G_FSQRT:
661 return selectExtInst(ResVReg, ResType,
I, CL::sqrt, GL::Sqrt);
663 case TargetOpcode::G_CTTZ:
664 case TargetOpcode::G_CTTZ_ZERO_UNDEF:
665 return selectExtInst(ResVReg, ResType,
I, CL::ctz);
666 case TargetOpcode::G_CTLZ:
667 case TargetOpcode::G_CTLZ_ZERO_UNDEF:
668 return selectExtInst(ResVReg, ResType,
I, CL::clz);
670 case TargetOpcode::G_INTRINSIC_ROUND:
671 return selectExtInst(ResVReg, ResType,
I, CL::round, GL::Round);
672 case TargetOpcode::G_INTRINSIC_ROUNDEVEN:
673 return selectExtInst(ResVReg, ResType,
I, CL::rint, GL::RoundEven);
674 case TargetOpcode::G_INTRINSIC_TRUNC:
675 return selectExtInst(ResVReg, ResType,
I, CL::trunc, GL::Trunc);
676 case TargetOpcode::G_FRINT:
677 case TargetOpcode::G_FNEARBYINT:
678 return selectExtInst(ResVReg, ResType,
I, CL::rint, GL::RoundEven);
680 case TargetOpcode::G_SMULH:
681 return selectExtInst(ResVReg, ResType,
I, CL::s_mul_hi);
682 case TargetOpcode::G_UMULH:
683 return selectExtInst(ResVReg, ResType,
I, CL::u_mul_hi);
685 case TargetOpcode::G_SADDSAT:
686 return selectExtInst(ResVReg, ResType,
I, CL::s_add_sat);
687 case TargetOpcode::G_UADDSAT:
688 return selectExtInst(ResVReg, ResType,
I, CL::u_add_sat);
689 case TargetOpcode::G_SSUBSAT:
690 return selectExtInst(ResVReg, ResType,
I, CL::s_sub_sat);
691 case TargetOpcode::G_USUBSAT:
692 return selectExtInst(ResVReg, ResType,
I, CL::u_sub_sat);
694 case TargetOpcode::G_UADDO:
695 return selectOverflowArith(ResVReg, ResType,
I,
696 ResType->
getOpcode() == SPIRV::OpTypeVector
697 ? SPIRV::OpIAddCarryV
698 : SPIRV::OpIAddCarryS);
699 case TargetOpcode::G_USUBO:
700 return selectOverflowArith(ResVReg, ResType,
I,
701 ResType->
getOpcode() == SPIRV::OpTypeVector
702 ? SPIRV::OpISubBorrowV
703 : SPIRV::OpISubBorrowS);
704 case TargetOpcode::G_UMULO:
705 return selectOverflowArith(ResVReg, ResType,
I, SPIRV::OpUMulExtended);
706 case TargetOpcode::G_SMULO:
707 return selectOverflowArith(ResVReg, ResType,
I, SPIRV::OpSMulExtended);
709 case TargetOpcode::G_SEXT:
710 return selectExt(ResVReg, ResType,
I,
true);
711 case TargetOpcode::G_ANYEXT:
712 case TargetOpcode::G_ZEXT:
713 return selectExt(ResVReg, ResType,
I,
false);
714 case TargetOpcode::G_TRUNC:
715 return selectTrunc(ResVReg, ResType,
I);
716 case TargetOpcode::G_FPTRUNC:
717 case TargetOpcode::G_FPEXT:
718 return selectUnOp(ResVReg, ResType,
I, SPIRV::OpFConvert);
720 case TargetOpcode::G_PTRTOINT:
721 return selectUnOp(ResVReg, ResType,
I, SPIRV::OpConvertPtrToU);
722 case TargetOpcode::G_INTTOPTR:
723 return selectUnOp(ResVReg, ResType,
I, SPIRV::OpConvertUToPtr);
724 case TargetOpcode::G_BITCAST:
725 return selectBitcast(ResVReg, ResType,
I);
726 case TargetOpcode::G_ADDRSPACE_CAST:
727 return selectAddrSpaceCast(ResVReg, ResType,
I);
728 case TargetOpcode::G_PTR_ADD: {
730 assert(
I.getOperand(1).isReg() &&
I.getOperand(2).isReg());
734 assert(((*II).getOpcode() == TargetOpcode::G_GLOBAL_VALUE ||
735 (*II).getOpcode() == TargetOpcode::COPY ||
736 (*II).getOpcode() == SPIRV::OpVariable) &&
739 bool IsGVInit =
false;
741 UseIt =
MRI->use_instr_begin(
I.getOperand(0).getReg()),
742 UseEnd =
MRI->use_instr_end();
743 UseIt != UseEnd; UseIt = std::next(UseIt)) {
744 if ((*UseIt).getOpcode() == TargetOpcode::G_GLOBAL_VALUE ||
745 (*UseIt).getOpcode() == SPIRV::OpVariable) {
752 SPIRVType *GVType = GR.getSPIRVTypeForVReg(GV);
753 SPIRVType *GVPointeeType = GR.getPointeeType(GVType);
754 SPIRVType *ResPointeeType = GR.getPointeeType(ResType);
755 if (GVPointeeType && ResPointeeType && GVPointeeType != ResPointeeType) {
758 Register NewVReg =
MRI->createGenericVirtualRegister(
MRI->getType(GV));
759 MRI->setRegClass(NewVReg,
MRI->getRegClass(GV));
766 if (!GR.isBitcastCompatible(ResType, GVType))
768 "incompatible result and operand types in a bitcast");
769 Register ResTypeReg = GR.getSPIRVTypeID(ResType);
771 BuildMI(BB,
I,
I.getDebugLoc(),
TII.get(SPIRV::OpBitcast))
777 TII.get(STI.isVulkanEnv()
778 ? SPIRV::OpInBoundsAccessChain
779 : SPIRV::OpInBoundsPtrAccessChain))
783 .
addUse(
I.getOperand(2).getReg())
786 return BuildMI(BB,
I,
I.getDebugLoc(),
TII.get(SPIRV::OpSpecConstantOp))
788 .
addUse(GR.getSPIRVTypeID(ResType))
790 static_cast<uint32_t>(SPIRV::Opcode::InBoundsPtrAccessChain))
792 .
addUse(
I.getOperand(2).getReg())
799 Register Idx = buildZerosVal(GR.getOrCreateSPIRVIntegerType(32,
I,
TII),
I);
800 auto MIB =
BuildMI(BB,
I,
I.getDebugLoc(),
TII.get(SPIRV::OpSpecConstantOp))
802 .
addUse(GR.getSPIRVTypeID(ResType))
804 SPIRV::Opcode::InBoundsPtrAccessChain))
807 .
addUse(
I.getOperand(2).getReg());
811 case TargetOpcode::G_ATOMICRMW_OR:
812 return selectAtomicRMW(ResVReg, ResType,
I, SPIRV::OpAtomicOr);
813 case TargetOpcode::G_ATOMICRMW_ADD:
814 return selectAtomicRMW(ResVReg, ResType,
I, SPIRV::OpAtomicIAdd);
815 case TargetOpcode::G_ATOMICRMW_AND:
816 return selectAtomicRMW(ResVReg, ResType,
I, SPIRV::OpAtomicAnd);
817 case TargetOpcode::G_ATOMICRMW_MAX:
818 return selectAtomicRMW(ResVReg, ResType,
I, SPIRV::OpAtomicSMax);
819 case TargetOpcode::G_ATOMICRMW_MIN:
820 return selectAtomicRMW(ResVReg, ResType,
I, SPIRV::OpAtomicSMin);
821 case TargetOpcode::G_ATOMICRMW_SUB:
822 return selectAtomicRMW(ResVReg, ResType,
I, SPIRV::OpAtomicISub);
823 case TargetOpcode::G_ATOMICRMW_XOR:
824 return selectAtomicRMW(ResVReg, ResType,
I, SPIRV::OpAtomicXor);
825 case TargetOpcode::G_ATOMICRMW_UMAX:
826 return selectAtomicRMW(ResVReg, ResType,
I, SPIRV::OpAtomicUMax);
827 case TargetOpcode::G_ATOMICRMW_UMIN:
828 return selectAtomicRMW(ResVReg, ResType,
I, SPIRV::OpAtomicUMin);
829 case TargetOpcode::G_ATOMICRMW_XCHG:
830 return selectAtomicRMW(ResVReg, ResType,
I, SPIRV::OpAtomicExchange);
831 case TargetOpcode::G_ATOMIC_CMPXCHG:
832 return selectAtomicCmpXchg(ResVReg, ResType,
I);
834 case TargetOpcode::G_ATOMICRMW_FADD:
835 return selectAtomicRMW(ResVReg, ResType,
I, SPIRV::OpAtomicFAddEXT);
836 case TargetOpcode::G_ATOMICRMW_FSUB:
838 return selectAtomicRMW(ResVReg, ResType,
I, SPIRV::OpAtomicFAddEXT,
840 case TargetOpcode::G_ATOMICRMW_FMIN:
841 return selectAtomicRMW(ResVReg, ResType,
I, SPIRV::OpAtomicFMinEXT);
842 case TargetOpcode::G_ATOMICRMW_FMAX:
843 return selectAtomicRMW(ResVReg, ResType,
I, SPIRV::OpAtomicFMaxEXT);
845 case TargetOpcode::G_FENCE:
846 return selectFence(
I);
848 case TargetOpcode::G_STACKSAVE:
849 return selectStackSave(ResVReg, ResType,
I);
850 case TargetOpcode::G_STACKRESTORE:
851 return selectStackRestore(
I);
853 case TargetOpcode::G_UNMERGE_VALUES:
859 case TargetOpcode::G_TRAP:
860 case TargetOpcode::G_DEBUGTRAP:
861 case TargetOpcode::G_UBSANTRAP:
862 case TargetOpcode::DBG_LABEL:
870bool SPIRVInstructionSelector::selectExtInst(
Register ResVReg,
873 GL::GLSLExtInst GLInst)
const {
874 return selectExtInst(ResVReg, ResType,
I,
875 {{SPIRV::InstructionSet::GLSL_std_450, GLInst}});
878bool SPIRVInstructionSelector::selectExtInst(
Register ResVReg,
881 CL::OpenCLExtInst CLInst)
const {
882 return selectExtInst(ResVReg, ResType,
I,
883 {{SPIRV::InstructionSet::OpenCL_std, CLInst}});
886bool SPIRVInstructionSelector::selectExtInst(
Register ResVReg,
889 CL::OpenCLExtInst CLInst,
890 GL::GLSLExtInst GLInst)
const {
891 ExtInstList ExtInsts = {{SPIRV::InstructionSet::OpenCL_std, CLInst},
892 {SPIRV::InstructionSet::GLSL_std_450, GLInst}};
893 return selectExtInst(ResVReg, ResType,
I, ExtInsts);
896bool SPIRVInstructionSelector::selectExtInst(
Register ResVReg,
901 for (
const auto &Ex : Insts) {
902 SPIRV::InstructionSet::InstructionSet
Set = Ex.first;
904 if (STI.canUseExtInstSet(Set)) {
906 auto MIB =
BuildMI(BB,
I,
I.getDebugLoc(),
TII.get(SPIRV::OpExtInst))
908 .
addUse(GR.getSPIRVTypeID(ResType))
911 const unsigned NumOps =
I.getNumOperands();
913 if (Index < NumOps &&
914 I.getOperand(Index).getType() ==
915 MachineOperand::MachineOperandType::MO_IntrinsicID)
918 MIB.
add(
I.getOperand(Index));
925bool SPIRVInstructionSelector::selectOpWithSrcs(
Register ResVReg,
928 std::vector<Register> Srcs,
929 unsigned Opcode)
const {
930 auto MIB =
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
TII.get(Opcode))
932 .
addUse(GR.getSPIRVTypeID(ResType));
939bool SPIRVInstructionSelector::selectUnOp(
Register ResVReg,
942 unsigned Opcode)
const {
943 if (STI.isOpenCLEnv() &&
I.getOperand(1).isReg()) {
944 Register SrcReg =
I.getOperand(1).getReg();
947 MRI->def_instr_begin(SrcReg);
948 DefIt !=
MRI->def_instr_end(); DefIt = std::next(DefIt)) {
949 if ((*DefIt).getOpcode() == TargetOpcode::G_GLOBAL_VALUE) {
957 case SPIRV::OpConvertPtrToU:
958 SpecOpcode =
static_cast<uint32_t>(SPIRV::Opcode::ConvertPtrToU);
960 case SPIRV::OpConvertUToPtr:
961 SpecOpcode =
static_cast<uint32_t>(SPIRV::Opcode::ConvertUToPtr);
965 return BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
966 TII.get(SPIRV::OpSpecConstantOp))
968 .
addUse(GR.getSPIRVTypeID(ResType))
974 return selectOpWithSrcs(ResVReg, ResType,
I, {
I.getOperand(1).
getReg()},
978bool SPIRVInstructionSelector::selectBitcast(
Register ResVReg,
981 Register OpReg =
I.getOperand(1).getReg();
982 SPIRVType *OpType = OpReg.
isValid() ? GR.getSPIRVTypeForVReg(OpReg) :
nullptr;
983 if (!GR.isBitcastCompatible(ResType, OpType))
985 return selectUnOp(ResVReg, ResType,
I, SPIRV::OpBitcast);
991 if (
MemOp->isVolatile())
992 SpvMemOp |=
static_cast<uint32_t>(SPIRV::MemoryOperand::Volatile);
993 if (
MemOp->isNonTemporal())
994 SpvMemOp |=
static_cast<uint32_t>(SPIRV::MemoryOperand::Nontemporal);
995 if (
MemOp->getAlign().value())
996 SpvMemOp |=
static_cast<uint32_t>(SPIRV::MemoryOperand::Aligned);
998 if (SpvMemOp !=
static_cast<uint32_t>(SPIRV::MemoryOperand::None)) {
1000 if (SpvMemOp &
static_cast<uint32_t>(SPIRV::MemoryOperand::Aligned))
1007 if (Flags & MachineMemOperand::Flags::MOVolatile)
1008 SpvMemOp |=
static_cast<uint32_t>(SPIRV::MemoryOperand::Volatile);
1009 if (Flags & MachineMemOperand::Flags::MONonTemporal)
1010 SpvMemOp |=
static_cast<uint32_t>(SPIRV::MemoryOperand::Nontemporal);
1012 if (SpvMemOp !=
static_cast<uint32_t>(SPIRV::MemoryOperand::None))
1016bool SPIRVInstructionSelector::selectLoad(
Register ResVReg,
1019 unsigned OpOffset = isa<GIntrinsic>(
I) ? 1 : 0;
1021 auto MIB =
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
TII.get(SPIRV::OpLoad))
1023 .
addUse(GR.getSPIRVTypeID(ResType))
1025 if (!
I.getNumMemOperands()) {
1026 assert(
I.getOpcode() == TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS ||
1028 TargetOpcode::G_INTRINSIC_CONVERGENT_W_SIDE_EFFECTS);
1036bool SPIRVInstructionSelector::selectStore(
MachineInstr &
I)
const {
1037 unsigned OpOffset = isa<GIntrinsic>(
I) ? 1 : 0;
1038 Register StoreVal =
I.getOperand(0 + OpOffset).getReg();
1041 auto MIB =
BuildMI(BB,
I,
I.getDebugLoc(),
TII.get(SPIRV::OpStore))
1044 if (!
I.getNumMemOperands()) {
1045 assert(
I.getOpcode() == TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS ||
1047 TargetOpcode::G_INTRINSIC_CONVERGENT_W_SIDE_EFFECTS);
1055bool SPIRVInstructionSelector::selectStackSave(
Register ResVReg,
1058 if (!STI.canUseExtension(SPIRV::Extension::SPV_INTEL_variable_length_array))
1060 "llvm.stacksave intrinsic: this instruction requires the following "
1061 "SPIR-V extension: SPV_INTEL_variable_length_array",
1064 return BuildMI(BB,
I,
I.getDebugLoc(),
TII.get(SPIRV::OpSaveMemoryINTEL))
1066 .
addUse(GR.getSPIRVTypeID(ResType))
1070bool SPIRVInstructionSelector::selectStackRestore(
MachineInstr &
I)
const {
1071 if (!STI.canUseExtension(SPIRV::Extension::SPV_INTEL_variable_length_array))
1073 "llvm.stackrestore intrinsic: this instruction requires the following "
1074 "SPIR-V extension: SPV_INTEL_variable_length_array",
1076 if (!
I.getOperand(0).isReg())
1079 return BuildMI(BB,
I,
I.getDebugLoc(),
TII.get(SPIRV::OpRestoreMemoryINTEL))
1080 .
addUse(
I.getOperand(0).getReg())
1084bool SPIRVInstructionSelector::selectMemOperation(
Register ResVReg,
1087 Register SrcReg =
I.getOperand(1).getReg();
1089 if (
I.getOpcode() == TargetOpcode::G_MEMSET) {
1090 assert(
I.getOperand(1).isReg() &&
I.getOperand(2).isReg());
1093 SPIRVType *ValTy = GR.getOrCreateSPIRVIntegerType(8,
I,
TII);
1094 SPIRVType *ArrTy = GR.getOrCreateSPIRVArrayType(ValTy, Num,
I,
TII);
1096 SPIRVType *VarTy = GR.getOrCreateSPIRVPointerType(
1097 ArrTy,
I,
TII, SPIRV::StorageClass::UniformConstant);
1107 GR.add(GV, GR.CurMF, VarReg);
1108 GR.addGlobalObject(GV, GR.CurMF, VarReg);
1111 BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
TII.get(SPIRV::OpVariable))
1113 .
addUse(GR.getSPIRVTypeID(VarTy))
1114 .
addImm(SPIRV::StorageClass::UniformConstant)
1118 SPIRVType *SourceTy = GR.getOrCreateSPIRVPointerType(
1119 ValTy,
I,
TII, SPIRV::StorageClass::UniformConstant);
1121 selectOpWithSrcs(SrcReg, SourceTy,
I, {VarReg}, SPIRV::OpBitcast);
1123 auto MIB =
BuildMI(BB,
I,
I.getDebugLoc(),
TII.get(SPIRV::OpCopyMemorySized))
1124 .
addUse(
I.getOperand(0).getReg())
1126 .
addUse(
I.getOperand(2).getReg());
1127 if (
I.getNumMemOperands())
1135bool SPIRVInstructionSelector::selectAtomicRMW(
Register ResVReg,
1139 unsigned NegateOpcode)
const {
1144 GR.CurMF->getFunction().getContext(),
MemOp->getSyncScopeID()));
1145 auto ScopeConstant = buildI32Constant(Scope,
I);
1146 Register ScopeReg = ScopeConstant.first;
1147 Result &= ScopeConstant.second;
1155 auto MemSemConstant = buildI32Constant(MemSem ,
I);
1156 Register MemSemReg = MemSemConstant.first;
1157 Result &= MemSemConstant.second;
1159 Register ValueReg =
I.getOperand(2).getReg();
1160 if (NegateOpcode != 0) {
1162 Register TmpReg =
MRI->createVirtualRegister(&SPIRV::iIDRegClass);
1163 Result &= selectOpWithSrcs(TmpReg, ResType,
I, {ValueReg}, NegateOpcode);
1168 BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
TII.get(NewOpcode))
1170 .
addUse(GR.getSPIRVTypeID(ResType))
1178bool SPIRVInstructionSelector::selectUnmergeValues(
MachineInstr &
I)
const {
1179 unsigned ArgI =
I.getNumOperands() - 1;
1181 I.getOperand(ArgI).isReg() ?
I.getOperand(ArgI).getReg() :
Register(0);
1183 SrcReg.
isValid() ? GR.getSPIRVTypeForVReg(SrcReg) :
nullptr;
1184 if (!DefType || DefType->
getOpcode() != SPIRV::OpTypeVector)
1186 "cannot select G_UNMERGE_VALUES with a non-vector argument");
1192 for (
unsigned i = 0; i <
I.getNumDefs(); ++i) {
1193 Register ResVReg =
I.getOperand(i).getReg();
1194 SPIRVType *ResType = GR.getSPIRVTypeForVReg(ResVReg);
1197 ResType = ScalarType;
1198 MRI->setRegClass(ResVReg, GR.getRegClass(ResType));
1199 MRI->setType(ResVReg,
LLT::scalar(GR.getScalarOrVectorBitWidth(ResType)));
1200 GR.assignSPIRVTypeToVReg(ResType, ResVReg, *GR.CurMF);
1203 BuildMI(BB,
I,
I.getDebugLoc(),
TII.get(SPIRV::OpCompositeExtract))
1205 .
addUse(GR.getSPIRVTypeID(ResType))
1207 .
addImm(
static_cast<int64_t
>(i));
1213bool SPIRVInstructionSelector::selectFence(
MachineInstr &
I)
const {
1216 auto MemSemConstant = buildI32Constant(MemSem,
I);
1217 Register MemSemReg = MemSemConstant.first;
1218 bool Result = MemSemConstant.second;
1221 getMemScope(GR.CurMF->getFunction().getContext(), Ord));
1222 auto ScopeConstant = buildI32Constant(Scope,
I);
1223 Register ScopeReg = ScopeConstant.first;
1224 Result &= ScopeConstant.second;
1227 BuildMI(BB,
I,
I.getDebugLoc(),
TII.get(SPIRV::OpMemoryBarrier))
1233bool SPIRVInstructionSelector::selectOverflowArith(
Register ResVReg,
1236 unsigned Opcode)
const {
1237 Type *ResTy =
nullptr;
1239 if (!GR.findValueAttrs(&
I, ResTy, ResName))
1241 "Not enough info to select the arithmetic with overflow instruction");
1244 "with overflow instruction");
1247 Type *ResElemTy = cast<StructType>(ResTy)->getElementType(0);
1252 ResTy, MIRBuilder, SPIRV::AccessQualifier::ReadWrite,
false);
1253 assert(
I.getNumDefs() > 1 &&
"Not enought operands");
1255 unsigned N = GR.getScalarOrVectorComponentCount(ResType);
1257 BoolType = GR.getOrCreateSPIRVVectorType(BoolType,
N,
I,
TII);
1258 Register BoolTypeReg = GR.getSPIRVTypeID(BoolType);
1259 Register ZeroReg = buildZerosVal(ResType,
I);
1262 MRI->setRegClass(StructVReg, &SPIRV::IDRegClass);
1264 if (ResName.
size() > 0)
1269 BuildMI(BB, MIRBuilder.getInsertPt(),
I.getDebugLoc(),
TII.get(Opcode))
1272 for (
unsigned i =
I.getNumDefs(); i <
I.getNumOperands(); ++i)
1273 MIB.
addUse(
I.getOperand(i).getReg());
1278 MRI->setRegClass(HigherVReg, &SPIRV::iIDRegClass);
1279 for (
unsigned i = 0; i <
I.getNumDefs(); ++i) {
1281 BuildMI(BB,
I,
I.getDebugLoc(),
TII.get(SPIRV::OpCompositeExtract))
1282 .
addDef(i == 1 ? HigherVReg :
I.getOperand(i).getReg())
1283 .
addUse(GR.getSPIRVTypeID(ResType))
1290 .
addDef(
I.getOperand(1).getReg())
1297bool SPIRVInstructionSelector::selectAtomicCmpXchg(
Register ResVReg,
1305 if (!isa<GIntrinsic>(
I)) {
1309 GR.CurMF->getFunction().getContext(),
MemOp->getSyncScopeID()));
1310 auto ScopeConstant = buildI32Constant(Scope,
I);
1311 ScopeReg = ScopeConstant.first;
1312 Result &= ScopeConstant.second;
1314 unsigned ScSem =
static_cast<uint32_t>(
1318 auto MemSemEqConstant = buildI32Constant(MemSemEq,
I);
1319 MemSemEqReg = MemSemEqConstant.first;
1320 Result &= MemSemEqConstant.second;
1323 if (MemSemEq == MemSemNeq)
1324 MemSemNeqReg = MemSemEqReg;
1326 auto MemSemNeqConstant = buildI32Constant(MemSemEq,
I);
1327 MemSemNeqReg = MemSemNeqConstant.first;
1328 Result &= MemSemNeqConstant.second;
1331 ScopeReg =
I.getOperand(5).getReg();
1332 MemSemEqReg =
I.getOperand(6).getReg();
1333 MemSemNeqReg =
I.getOperand(7).getReg();
1337 Register Val =
I.getOperand(4).getReg();
1338 SPIRVType *SpvValTy = GR.getSPIRVTypeForVReg(Val);
1339 Register ACmpRes =
MRI->createVirtualRegister(&SPIRV::iIDRegClass);
1342 BuildMI(*
I.getParent(),
I,
DL,
TII.get(SPIRV::OpAtomicCompareExchange))
1344 .
addUse(GR.getSPIRVTypeID(SpvValTy))
1352 Register CmpSuccReg =
MRI->createVirtualRegister(&SPIRV::iIDRegClass);
1356 .
addUse(GR.getSPIRVTypeID(BoolTy))
1360 Register TmpReg =
MRI->createVirtualRegister(&SPIRV::iIDRegClass);
1363 .
addUse(GR.getSPIRVTypeID(ResType))
1365 .
addUse(GR.getOrCreateUndef(
I, ResType,
TII))
1369 BuildMI(*
I.getParent(),
I,
DL,
TII.get(SPIRV::OpCompositeInsert))
1371 .
addUse(GR.getSPIRVTypeID(ResType))
1380 case SPIRV::StorageClass::Workgroup:
1381 case SPIRV::StorageClass::CrossWorkgroup:
1382 case SPIRV::StorageClass::Function:
1391 case SPIRV::StorageClass::DeviceOnlyINTEL:
1392 case SPIRV::StorageClass::HostOnlyINTEL:
1401 bool IsGRef =
false;
1402 bool IsAllowedRefs =
1403 std::all_of(
MRI->use_instr_begin(ResVReg),
MRI->use_instr_end(),
1404 [&IsGRef](
auto const &It) {
1405 unsigned Opcode = It.getOpcode();
1406 if (Opcode == SPIRV::OpConstantComposite ||
1407 Opcode == SPIRV::OpVariable ||
1408 isSpvIntrinsic(It, Intrinsic::spv_init_global))
1409 return IsGRef = true;
1410 return Opcode == SPIRV::OpName;
1412 return IsAllowedRefs && IsGRef;
1415Register SPIRVInstructionSelector::getUcharPtrTypeReg(
1416 MachineInstr &
I, SPIRV::StorageClass::StorageClass SC)
const {
1417 return GR.getSPIRVTypeID(GR.getOrCreateSPIRVPointerType(
1418 GR.getOrCreateSPIRVIntegerType(8,
I,
TII),
I,
TII, SC));
1425 return BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
1426 TII.get(SPIRV::OpSpecConstantOp))
1436 SPIRVType *GenericPtrTy = GR.getOrCreateSPIRVPointerType(
1437 GR.getPointeeType(SrcPtrTy),
I,
TII, SPIRV::StorageClass::Generic);
1438 Register Tmp =
MRI->createVirtualRegister(&SPIRV::pIDRegClass);
1440 SPIRV::StorageClass::Generic),
1441 GR.getPointerSize()));
1443 GR.assignSPIRVTypeToVReg(GenericPtrTy, Tmp, *MF);
1445 I, Tmp, SrcPtr, GR.getSPIRVTypeID(GenericPtrTy),
1446 static_cast<uint32_t>(SPIRV::Opcode::PtrCastToGeneric));
1456bool SPIRVInstructionSelector::selectAddrSpaceCast(
Register ResVReg,
1462 Register SrcPtr =
I.getOperand(1).getReg();
1463 SPIRVType *SrcPtrTy = GR.getSPIRVTypeForVReg(SrcPtr);
1466 if (SrcPtrTy->
getOpcode() != SPIRV::OpTypePointer ||
1467 ResType->
getOpcode() != SPIRV::OpTypePointer)
1468 return BuildCOPY(ResVReg, SrcPtr,
I);
1470 SPIRV::StorageClass::StorageClass SrcSC = GR.getPointerStorageClass(SrcPtrTy);
1471 SPIRV::StorageClass::StorageClass DstSC = GR.getPointerStorageClass(ResType);
1478 unsigned SpecOpcode =
1480 ?
static_cast<uint32_t>(SPIRV::Opcode::PtrCastToGeneric)
1481 : (SrcSC == SPIRV::StorageClass::Generic &&
1483 ?
static_cast<uint32_t>(SPIRV::Opcode::GenericCastToPtr)
1490 return buildSpecConstantOp(
I, ResVReg, SrcPtr,
1491 getUcharPtrTypeReg(
I, DstSC), SpecOpcode)
1492 .constrainAllUses(
TII,
TRI, RBI);
1496 buildSpecConstantOp(
1498 getUcharPtrTypeReg(
I, DstSC),
1499 static_cast<uint32_t>(SPIRV::Opcode::GenericCastToPtr))
1500 .constrainAllUses(
TII,
TRI, RBI);
1506 return BuildCOPY(ResVReg, SrcPtr,
I);
1508 if ((SrcSC == SPIRV::StorageClass::Function &&
1509 DstSC == SPIRV::StorageClass::Private) ||
1510 (DstSC == SPIRV::StorageClass::Function &&
1511 SrcSC == SPIRV::StorageClass::Private))
1512 return BuildCOPY(ResVReg, SrcPtr,
I);
1516 return selectUnOp(ResVReg, ResType,
I, SPIRV::OpPtrCastToGeneric);
1519 return selectUnOp(ResVReg, ResType,
I, SPIRV::OpGenericCastToPtr);
1522 Register Tmp =
MRI->createVirtualRegister(&SPIRV::iIDRegClass);
1523 SPIRVType *GenericPtrTy = GR.getOrCreateSPIRVPointerType(
1524 GR.getPointeeType(SrcPtrTy),
I,
TII, SPIRV::StorageClass::Generic);
1527 .
addUse(GR.getSPIRVTypeID(GenericPtrTy))
1532 .
addUse(GR.getSPIRVTypeID(ResType))
1540 return selectUnOp(ResVReg, ResType,
I,
1541 SPIRV::OpPtrCastToCrossWorkgroupINTEL);
1543 return selectUnOp(ResVReg, ResType,
I,
1544 SPIRV::OpCrossWorkgroupCastToPtrINTEL);
1546 return selectUnOp(ResVReg, ResType,
I, SPIRV::OpPtrCastToGeneric);
1548 return selectUnOp(ResVReg, ResType,
I, SPIRV::OpGenericCastToPtr);
1558 return SPIRV::OpFOrdEqual;
1560 return SPIRV::OpFOrdGreaterThanEqual;
1562 return SPIRV::OpFOrdGreaterThan;
1564 return SPIRV::OpFOrdLessThanEqual;
1566 return SPIRV::OpFOrdLessThan;
1568 return SPIRV::OpFOrdNotEqual;
1570 return SPIRV::OpOrdered;
1572 return SPIRV::OpFUnordEqual;
1574 return SPIRV::OpFUnordGreaterThanEqual;
1576 return SPIRV::OpFUnordGreaterThan;
1578 return SPIRV::OpFUnordLessThanEqual;
1580 return SPIRV::OpFUnordLessThan;
1582 return SPIRV::OpFUnordNotEqual;
1584 return SPIRV::OpUnordered;
1594 return SPIRV::OpIEqual;
1596 return SPIRV::OpINotEqual;
1598 return SPIRV::OpSGreaterThanEqual;
1600 return SPIRV::OpSGreaterThan;
1602 return SPIRV::OpSLessThanEqual;
1604 return SPIRV::OpSLessThan;
1606 return SPIRV::OpUGreaterThanEqual;
1608 return SPIRV::OpUGreaterThan;
1610 return SPIRV::OpULessThanEqual;
1612 return SPIRV::OpULessThan;
1621 return SPIRV::OpPtrEqual;
1623 return SPIRV::OpPtrNotEqual;
1634 return SPIRV::OpLogicalEqual;
1636 return SPIRV::OpLogicalNotEqual;
1670bool SPIRVInstructionSelector::selectAnyOrAll(
Register ResVReg,
1673 unsigned OpAnyOrAll)
const {
1674 assert(
I.getNumOperands() == 3);
1675 assert(
I.getOperand(2).isReg());
1677 Register InputRegister =
I.getOperand(2).getReg();
1678 SPIRVType *InputType = GR.getSPIRVTypeForVReg(InputRegister);
1683 bool IsBoolTy = GR.isScalarOrVectorOfType(InputRegister, SPIRV::OpTypeBool);
1684 bool IsVectorTy = InputType->
getOpcode() == SPIRV::OpTypeVector;
1685 if (IsBoolTy && !IsVectorTy) {
1686 assert(ResVReg ==
I.getOperand(0).getReg());
1687 return BuildCOPY(ResVReg, InputRegister,
I);
1690 bool IsFloatTy = GR.isScalarOrVectorOfType(InputRegister, SPIRV::OpTypeFloat);
1691 unsigned SpirvNotEqualId =
1692 IsFloatTy ? SPIRV::OpFOrdNotEqual : SPIRV::OpINotEqual;
1693 SPIRVType *SpvBoolScalarTy = GR.getOrCreateSPIRVBoolType(
I,
TII);
1698 NotEqualReg = IsBoolTy ? InputRegister
1699 :
MRI->createVirtualRegister(&SPIRV::iIDRegClass);
1701 SpvBoolTy = GR.getOrCreateSPIRVVectorType(SpvBoolTy, NumElts,
I,
TII);
1707 IsFloatTy ? buildZerosValF(InputType,
I) : buildZerosVal(InputType,
I);
1711 .
addUse(GR.getSPIRVTypeID(SpvBoolTy))
1722 .
addUse(GR.getSPIRVTypeID(SpvBoolScalarTy))
1727bool SPIRVInstructionSelector::selectAll(
Register ResVReg,
1730 return selectAnyOrAll(ResVReg, ResType,
I, SPIRV::OpAll);
1733bool SPIRVInstructionSelector::selectAny(
Register ResVReg,
1736 return selectAnyOrAll(ResVReg, ResType,
I, SPIRV::OpAny);
1740bool SPIRVInstructionSelector::selectFloatDot(
Register ResVReg,
1743 assert(
I.getNumOperands() == 4);
1744 assert(
I.getOperand(2).isReg());
1745 assert(
I.getOperand(3).isReg());
1748 GR.getSPIRVTypeForVReg(
I.getOperand(2).getReg());
1751 GR.getScalarOrVectorComponentCount(VecType) > 1 &&
1752 "dot product requires a vector of at least 2 components");
1755 GR.getSPIRVTypeForVReg(
VecType->getOperand(1).getReg());
1760 return BuildMI(BB,
I,
I.getDebugLoc(),
TII.get(SPIRV::OpDot))
1762 .
addUse(GR.getSPIRVTypeID(ResType))
1763 .
addUse(
I.getOperand(2).getReg())
1764 .
addUse(
I.getOperand(3).getReg())
1768bool SPIRVInstructionSelector::selectIntegerDot(
Register ResVReg,
1772 assert(
I.getNumOperands() == 4);
1773 assert(
I.getOperand(2).isReg());
1774 assert(
I.getOperand(3).isReg());
1777 auto DotOp =
Signed ? SPIRV::OpSDot : SPIRV::OpUDot;
1780 .
addUse(GR.getSPIRVTypeID(ResType))
1781 .
addUse(
I.getOperand(2).getReg())
1782 .
addUse(
I.getOperand(3).getReg())
1788bool SPIRVInstructionSelector::selectIntegerDotExpansion(
1790 assert(
I.getNumOperands() == 4);
1791 assert(
I.getOperand(2).isReg());
1792 assert(
I.getOperand(3).isReg());
1796 Register Vec0 =
I.getOperand(2).getReg();
1797 Register Vec1 =
I.getOperand(3).getReg();
1798 Register TmpVec =
MRI->createVirtualRegister(GR.getRegClass(ResType));
1803 .
addUse(GR.getSPIRVTypeID(VecType))
1809 GR.getScalarOrVectorComponentCount(VecType) > 1 &&
1810 "dot product requires a vector of at least 2 components");
1812 Register Res =
MRI->createVirtualRegister(GR.getRegClass(ResType));
1815 .
addUse(GR.getSPIRVTypeID(ResType))
1820 for (
unsigned i = 1; i < GR.getScalarOrVectorComponentCount(VecType); i++) {
1821 Register Elt =
MRI->createVirtualRegister(GR.getRegClass(ResType));
1824 BuildMI(BB,
I,
I.getDebugLoc(),
TII.get(SPIRV::OpCompositeExtract))
1826 .
addUse(GR.getSPIRVTypeID(ResType))
1831 Register Sum = i < GR.getScalarOrVectorComponentCount(VecType) - 1
1832 ?
MRI->createVirtualRegister(GR.getRegClass(ResType))
1837 .
addUse(GR.getSPIRVTypeID(ResType))
1847template <
bool Signed>
1848bool SPIRVInstructionSelector::selectDot4AddPacked(
Register ResVReg,
1851 assert(
I.getNumOperands() == 5);
1852 assert(
I.getOperand(2).isReg());
1853 assert(
I.getOperand(3).isReg());
1854 assert(
I.getOperand(4).isReg());
1857 auto DotOp =
Signed ? SPIRV::OpSDot : SPIRV::OpUDot;
1858 Register Dot =
MRI->createVirtualRegister(GR.getRegClass(ResType));
1861 .
addUse(GR.getSPIRVTypeID(ResType))
1862 .
addUse(
I.getOperand(2).getReg())
1863 .
addUse(
I.getOperand(3).getReg())
1868 .
addUse(GR.getSPIRVTypeID(ResType))
1870 .
addUse(
I.getOperand(4).getReg())
1877template <
bool Signed>
1878bool SPIRVInstructionSelector::selectDot4AddPackedExpansion(
1880 assert(
I.getNumOperands() == 5);
1881 assert(
I.getOperand(2).isReg());
1882 assert(
I.getOperand(3).isReg());
1883 assert(
I.getOperand(4).isReg());
1889 Register Acc =
I.getOperand(4).getReg();
1890 SPIRVType *EltType = GR.getOrCreateSPIRVIntegerType(8,
I,
TII);
1892 Signed ? SPIRV::OpBitFieldSExtract : SPIRV::OpBitFieldUExtract;
1895 for (
unsigned i = 0; i < 4; i++) {
1897 Register AElt =
MRI->createVirtualRegister(&SPIRV::IDRegClass);
1900 .
addUse(GR.getSPIRVTypeID(ResType))
1901 .
addUse(
I.getOperand(2).getReg())
1902 .
addUse(GR.getOrCreateConstInt(i * 8,
I, EltType,
TII))
1903 .
addUse(GR.getOrCreateConstInt(8,
I, EltType,
TII))
1907 Register BElt =
MRI->createVirtualRegister(&SPIRV::IDRegClass);
1910 .
addUse(GR.getSPIRVTypeID(ResType))
1911 .
addUse(
I.getOperand(3).getReg())
1912 .
addUse(GR.getOrCreateConstInt(i * 8,
I, EltType,
TII))
1913 .
addUse(GR.getOrCreateConstInt(8,
I, EltType,
TII))
1920 .
addUse(GR.getSPIRVTypeID(ResType))
1926 Register MaskMul =
MRI->createVirtualRegister(&SPIRV::IDRegClass);
1929 .
addUse(GR.getSPIRVTypeID(ResType))
1931 .
addUse(GR.getOrCreateConstInt(0,
I, EltType,
TII))
1932 .
addUse(GR.getOrCreateConstInt(8,
I, EltType,
TII))
1937 i < 3 ?
MRI->createVirtualRegister(&SPIRV::IDRegClass) : ResVReg;
1940 .
addUse(GR.getSPIRVTypeID(ResType))
1953bool SPIRVInstructionSelector::selectSaturate(
Register ResVReg,
1956 assert(
I.getNumOperands() == 3);
1957 assert(
I.getOperand(2).isReg());
1959 Register VZero = buildZerosValF(ResType,
I);
1960 Register VOne = buildOnesValF(ResType,
I);
1962 return BuildMI(BB,
I,
I.getDebugLoc(),
TII.get(SPIRV::OpExtInst))
1964 .
addUse(GR.getSPIRVTypeID(ResType))
1965 .
addImm(
static_cast<uint32_t>(SPIRV::InstructionSet::GLSL_std_450))
1967 .
addUse(
I.getOperand(2).getReg())
1973bool SPIRVInstructionSelector::selectSign(
Register ResVReg,
1976 assert(
I.getNumOperands() == 3);
1977 assert(
I.getOperand(2).isReg());
1979 Register InputRegister =
I.getOperand(2).getReg();
1980 SPIRVType *InputType = GR.getSPIRVTypeForVReg(InputRegister);
1981 auto &
DL =
I.getDebugLoc();
1986 bool IsFloatTy = GR.isScalarOrVectorOfType(InputRegister, SPIRV::OpTypeFloat);
1988 unsigned SignBitWidth = GR.getScalarOrVectorBitWidth(InputType);
1989 unsigned ResBitWidth = GR.getScalarOrVectorBitWidth(ResType);
1991 bool NeedsConversion = IsFloatTy || SignBitWidth != ResBitWidth;
1993 auto SignOpcode = IsFloatTy ? GL::FSign : GL::SSign;
1995 ?
MRI->createVirtualRegister(&SPIRV::IDRegClass)
2001 .
addUse(GR.getSPIRVTypeID(InputType))
2002 .
addImm(
static_cast<uint32_t>(SPIRV::InstructionSet::GLSL_std_450))
2007 if (NeedsConversion) {
2008 auto ConvertOpcode = IsFloatTy ? SPIRV::OpConvertFToS : SPIRV::OpSConvert;
2011 .
addUse(GR.getSPIRVTypeID(ResType))
2019bool SPIRVInstructionSelector::selectWaveOpInst(
Register ResVReg,
2022 unsigned Opcode)
const {
2024 SPIRVType *IntTy = GR.getOrCreateSPIRVIntegerType(32,
I,
TII);
2026 auto BMI =
BuildMI(BB,
I,
I.getDebugLoc(),
TII.get(Opcode))
2028 .
addUse(GR.getSPIRVTypeID(ResType))
2029 .
addUse(GR.getOrCreateConstInt(SPIRV::Scope::Subgroup,
I,
2032 for (
unsigned J = 2; J <
I.getNumOperands(); J++) {
2033 BMI.
addUse(
I.getOperand(J).getReg());
2039bool SPIRVInstructionSelector::selectWaveActiveCountBits(
2042 SPIRVType *IntTy = GR.getOrCreateSPIRVIntegerType(32,
I,
TII);
2043 SPIRVType *BallotType = GR.getOrCreateSPIRVVectorType(IntTy, 4,
I,
TII);
2044 Register BallotReg =
MRI->createVirtualRegister(GR.getRegClass(BallotType));
2045 bool Result = selectWaveOpInst(BallotReg, BallotType,
I,
2046 SPIRV::OpGroupNonUniformBallot);
2051 TII.get(SPIRV::OpGroupNonUniformBallotBitCount))
2053 .
addUse(GR.getSPIRVTypeID(ResType))
2054 .
addUse(GR.getOrCreateConstInt(SPIRV::Scope::Subgroup,
I, IntTy,
TII))
2055 .
addImm(SPIRV::GroupOperation::Reduce)
2062bool SPIRVInstructionSelector::selectBitreverse(
Register ResVReg,
2066 return BuildMI(BB,
I,
I.getDebugLoc(),
TII.get(SPIRV::OpBitReverse))
2068 .
addUse(GR.getSPIRVTypeID(ResType))
2069 .
addUse(
I.getOperand(1).getReg())
2073bool SPIRVInstructionSelector::selectFreeze(
Register ResVReg,
2081 if (!
I.getOperand(0).isReg() || !
I.getOperand(1).isReg())
2083 Register OpReg =
I.getOperand(1).getReg();
2086 switch (
Def->getOpcode()) {
2087 case SPIRV::ASSIGN_TYPE:
2089 MRI->getVRegDef(
Def->getOperand(1).getReg())) {
2090 if (AssignToDef->getOpcode() == TargetOpcode::G_IMPLICIT_DEF)
2091 Reg =
Def->getOperand(2).getReg();
2094 case SPIRV::OpUndef:
2095 Reg =
Def->getOperand(1).getReg();
2098 unsigned DestOpCode;
2099 if (
Reg.isValid()) {
2100 DestOpCode = SPIRV::OpConstantNull;
2102 DestOpCode = TargetOpcode::COPY;
2105 return BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
TII.get(DestOpCode))
2106 .
addDef(
I.getOperand(0).getReg())
2119 if (OpDef->
getOpcode() == SPIRV::ASSIGN_TYPE &&
2124 unsigned N = OpDef->
getOpcode() == TargetOpcode::G_CONSTANT
2133 if (OpDef->
getOpcode() == SPIRV::ASSIGN_TYPE &&
2145 case TargetOpcode::G_CONSTANT:
2146 case TargetOpcode::G_FCONSTANT:
2148 case TargetOpcode::G_INTRINSIC:
2149 case TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS:
2150 case TargetOpcode::G_INTRINSIC_CONVERGENT_W_SIDE_EFFECTS:
2151 return cast<GIntrinsic>(*OpDef).getIntrinsicID() ==
2152 Intrinsic::spv_const_composite;
2153 case TargetOpcode::G_BUILD_VECTOR:
2154 case TargetOpcode::G_SPLAT_VECTOR: {
2178bool SPIRVInstructionSelector::selectBuildVector(
Register ResVReg,
2182 if (ResType->
getOpcode() == SPIRV::OpTypeVector)
2183 N = GR.getScalarOrVectorComponentCount(ResType);
2184 else if (ResType->
getOpcode() == SPIRV::OpTypeArray)
2188 if (
I.getNumExplicitOperands() -
I.getNumExplicitDefs() !=
N)
2193 for (
unsigned i =
I.getNumExplicitDefs();
2194 i <
I.getNumExplicitOperands() && IsConst; ++i)
2198 if (!IsConst &&
N < 2)
2200 "There must be at least two constituent operands in a vector");
2202 MRI->setRegClass(ResVReg, GR.getRegClass(ResType));
2203 auto MIB =
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
2204 TII.get(IsConst ? SPIRV::OpConstantComposite
2205 : SPIRV::OpCompositeConstruct))
2207 .
addUse(GR.getSPIRVTypeID(ResType));
2208 for (
unsigned i =
I.getNumExplicitDefs(); i <
I.getNumExplicitOperands(); ++i)
2209 MIB.
addUse(
I.getOperand(i).getReg());
2213bool SPIRVInstructionSelector::selectSplatVector(
Register ResVReg,
2217 if (ResType->
getOpcode() == SPIRV::OpTypeVector)
2218 N = GR.getScalarOrVectorComponentCount(ResType);
2219 else if (ResType->
getOpcode() == SPIRV::OpTypeArray)
2224 unsigned OpIdx =
I.getNumExplicitDefs();
2225 if (!
I.getOperand(OpIdx).isReg())
2229 Register OpReg =
I.getOperand(OpIdx).getReg();
2232 if (!IsConst &&
N < 2)
2234 "There must be at least two constituent operands in a vector");
2236 MRI->setRegClass(ResVReg, GR.getRegClass(ResType));
2237 auto MIB =
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
2238 TII.get(IsConst ? SPIRV::OpConstantComposite
2239 : SPIRV::OpCompositeConstruct))
2241 .
addUse(GR.getSPIRVTypeID(ResType));
2242 for (
unsigned i = 0; i <
N; ++i)
2247bool SPIRVInstructionSelector::selectDiscard(
Register ResVReg,
2253 if (STI.canUseExtension(
2254 SPIRV::Extension::SPV_EXT_demote_to_helper_invocation) ||
2256 Opcode = SPIRV::OpDemoteToHelperInvocation;
2258 Opcode = SPIRV::OpKill;
2261 GR.invalidateMachineInstr(NextI);
2262 NextI->removeFromParent();
2267 return BuildMI(BB,
I,
I.getDebugLoc(),
TII.get(Opcode))
2271bool SPIRVInstructionSelector::selectCmp(
Register ResVReg,
2275 Register Cmp0 =
I.getOperand(2).getReg();
2276 Register Cmp1 =
I.getOperand(3).getReg();
2277 assert(GR.getSPIRVTypeForVReg(Cmp0)->getOpcode() ==
2278 GR.getSPIRVTypeForVReg(Cmp1)->getOpcode() &&
2279 "CMP operands should have the same type");
2280 return BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
TII.get(CmpOpc))
2282 .
addUse(GR.getSPIRVTypeID(ResType))
2288bool SPIRVInstructionSelector::selectICmp(
Register ResVReg,
2291 auto Pred =
I.getOperand(1).getPredicate();
2294 Register CmpOperand =
I.getOperand(2).getReg();
2295 if (GR.isScalarOfType(CmpOperand, SPIRV::OpTypePointer))
2297 else if (GR.isScalarOrVectorOfType(CmpOperand, SPIRV::OpTypeBool))
2301 return selectCmp(ResVReg, ResType, CmpOpc,
I);
2307 assert(
I.getOpcode() == TargetOpcode::G_FCONSTANT && OpIdx == -1 &&
2308 "Expected G_FCONSTANT");
2309 const ConstantFP *FPImm =
I.getOperand(1).getFPImm();
2316 assert(
I.getOpcode() == TargetOpcode::G_CONSTANT && OpIdx == -1 &&
2317 "Expected G_CONSTANT");
2318 addNumImm(
I.getOperand(1).getCImm()->getValue(), MIB);
2321std::pair<Register, bool>
2326 ResType ? ResType : GR.getOrCreateSPIRVIntegerType(32,
I,
TII);
2328 auto ConstInt = ConstantInt::get(LLVMTy, Val);
2329 Register NewReg = GR.find(ConstInt, GR.CurMF);
2333 GR.add(ConstInt, GR.CurMF, NewReg);
2337 MI =
BuildMI(BB,
I,
I.getDebugLoc(),
TII.get(SPIRV::OpConstantNull))
2339 .
addUse(GR.getSPIRVTypeID(SpvI32Ty));
2341 MI =
BuildMI(BB,
I,
I.getDebugLoc(),
TII.get(SPIRV::OpConstantI))
2343 .
addUse(GR.getSPIRVTypeID(SpvI32Ty))
2351bool SPIRVInstructionSelector::selectFCmp(
Register ResVReg,
2355 return selectCmp(ResVReg, ResType, CmpOp,
I);
2361 bool ZeroAsNull = STI.isOpenCLEnv();
2362 if (ResType->
getOpcode() == SPIRV::OpTypeVector)
2363 return GR.getOrCreateConstVector(0UL,
I, ResType,
TII, ZeroAsNull);
2364 return GR.getOrCreateConstInt(0,
I, ResType,
TII, ZeroAsNull);
2370 bool ZeroAsNull = STI.isOpenCLEnv();
2372 if (ResType->
getOpcode() == SPIRV::OpTypeVector)
2373 return GR.getOrCreateConstVector(VZero,
I, ResType,
TII, ZeroAsNull);
2374 return GR.getOrCreateConstFP(VZero,
I, ResType,
TII, ZeroAsNull);
2380 bool ZeroAsNull = STI.isOpenCLEnv();
2382 if (ResType->
getOpcode() == SPIRV::OpTypeVector)
2383 return GR.getOrCreateConstVector(VOne,
I, ResType,
TII, ZeroAsNull);
2384 return GR.getOrCreateConstFP(VOne,
I, ResType,
TII, ZeroAsNull);
2390 unsigned BitWidth = GR.getScalarOrVectorBitWidth(ResType);
2393 if (ResType->
getOpcode() == SPIRV::OpTypeVector)
2398bool SPIRVInstructionSelector::selectSelect(
Register ResVReg,
2401 bool IsSigned)
const {
2403 Register ZeroReg = buildZerosVal(ResType,
I);
2404 Register OneReg = buildOnesVal(IsSigned, ResType,
I);
2406 GR.isScalarOfType(
I.getOperand(1).getReg(), SPIRV::OpTypeBool);
2408 IsScalarBool ? SPIRV::OpSelectSISCond : SPIRV::OpSelectVIVCond;
2409 return BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
TII.get(Opcode))
2411 .
addUse(GR.getSPIRVTypeID(ResType))
2412 .
addUse(
I.getOperand(1).getReg())
2418bool SPIRVInstructionSelector::selectIToF(
Register ResVReg,
2421 unsigned Opcode)
const {
2422 Register SrcReg =
I.getOperand(1).getReg();
2425 if (GR.isScalarOrVectorOfType(
I.getOperand(1).getReg(), SPIRV::OpTypeBool)) {
2426 unsigned BitWidth = GR.getScalarOrVectorBitWidth(ResType);
2428 if (ResType->
getOpcode() == SPIRV::OpTypeVector) {
2430 TmpType = GR.getOrCreateSPIRVVectorType(TmpType, NumElts,
I,
TII);
2432 SrcReg =
MRI->createVirtualRegister(&SPIRV::iIDRegClass);
2433 selectSelect(SrcReg, TmpType,
I,
false);
2435 return selectOpWithSrcs(ResVReg, ResType,
I, {SrcReg}, Opcode);
2438bool SPIRVInstructionSelector::selectExt(
Register ResVReg,
2441 Register SrcReg =
I.getOperand(1).getReg();
2442 if (GR.isScalarOrVectorOfType(SrcReg, SPIRV::OpTypeBool))
2443 return selectSelect(ResVReg, ResType,
I, IsSigned);
2445 SPIRVType *SrcType = GR.getSPIRVTypeForVReg(SrcReg);
2446 if (SrcType == ResType)
2447 return BuildCOPY(ResVReg, SrcReg,
I);
2449 unsigned Opcode = IsSigned ? SPIRV::OpSConvert : SPIRV::OpUConvert;
2450 return selectUnOp(ResVReg, ResType,
I, Opcode);
2453bool SPIRVInstructionSelector::selectSUCmp(
Register ResVReg,
2456 bool IsSigned)
const {
2462 unsigned N = GR.getScalarOrVectorComponentCount(ResType);
2464 BoolType = GR.getOrCreateSPIRVVectorType(BoolType,
N,
I,
TII);
2465 Register BoolTypeReg = GR.getSPIRVTypeID(BoolType);
2469 Register IsLessEqReg =
MRI->createVirtualRegister(GR.getRegClass(ResType));
2471 GR.assignSPIRVTypeToVReg(ResType, IsLessEqReg, MIRBuilder.getMF());
2473 TII.get(IsSigned ? SPIRV::OpSLessThanEqual
2474 : SPIRV::OpULessThanEqual))
2477 .
addUse(
I.getOperand(1).getReg())
2478 .
addUse(
I.getOperand(2).getReg())
2480 Register IsLessReg =
MRI->createVirtualRegister(GR.getRegClass(ResType));
2482 GR.assignSPIRVTypeToVReg(ResType, IsLessReg, MIRBuilder.getMF());
2484 TII.get(IsSigned ? SPIRV::OpSLessThan : SPIRV::OpULessThan))
2487 .
addUse(
I.getOperand(1).getReg())
2488 .
addUse(
I.getOperand(2).getReg())
2491 Register ResTypeReg = GR.getSPIRVTypeID(ResType);
2493 MRI->createVirtualRegister(GR.getRegClass(ResType));
2495 GR.assignSPIRVTypeToVReg(ResType, NegOneOrZeroReg, MIRBuilder.getMF());
2496 unsigned SelectOpcode =
2497 N > 1 ? SPIRV::OpSelectVIVCond : SPIRV::OpSelectSISCond;
2502 .
addUse(buildOnesVal(
true, ResType,
I))
2503 .
addUse(buildZerosVal(ResType,
I))
2510 .
addUse(buildOnesVal(
false, ResType,
I))
2514bool SPIRVInstructionSelector::selectIntToBool(
Register IntReg,
2520 Register BitIntReg =
MRI->createVirtualRegister(&SPIRV::iIDRegClass);
2521 bool IsVectorTy = IntTy->
getOpcode() == SPIRV::OpTypeVector;
2522 unsigned Opcode = IsVectorTy ? SPIRV::OpBitwiseAndV : SPIRV::OpBitwiseAndS;
2524 Register One = buildOnesVal(
false, IntTy,
I);
2528 .
addUse(GR.getSPIRVTypeID(IntTy))
2534 .
addUse(GR.getSPIRVTypeID(BoolTy))
2540bool SPIRVInstructionSelector::selectTrunc(
Register ResVReg,
2543 Register IntReg =
I.getOperand(1).getReg();
2544 const SPIRVType *ArgType = GR.getSPIRVTypeForVReg(IntReg);
2545 if (GR.isScalarOrVectorOfType(ResVReg, SPIRV::OpTypeBool))
2546 return selectIntToBool(IntReg, ResVReg,
I, ArgType, ResType);
2547 if (ArgType == ResType)
2548 return BuildCOPY(ResVReg, IntReg,
I);
2549 bool IsSigned = GR.isScalarOrVectorSigned(ResType);
2550 unsigned Opcode = IsSigned ? SPIRV::OpSConvert : SPIRV::OpUConvert;
2551 return selectUnOp(ResVReg, ResType,
I, Opcode);
2554bool SPIRVInstructionSelector::selectConst(
Register ResVReg,
2558 unsigned TyOpcode = ResType->
getOpcode();
2559 assert(TyOpcode != SPIRV::OpTypePointer ||
Imm.isZero());
2561 if ((TyOpcode == SPIRV::OpTypePointer || TyOpcode == SPIRV::OpTypeEvent) &&
2563 return BuildMI(BB,
I,
I.getDebugLoc(),
TII.get(SPIRV::OpConstantNull))
2565 .
addUse(GR.getSPIRVTypeID(ResType))
2567 if (TyOpcode == SPIRV::OpTypeInt) {
2568 assert(
Imm.getBitWidth() <= 64 &&
"Unsupported integer width!");
2570 return Reg == ResVReg ?
true : BuildCOPY(ResVReg, Reg,
I);
2572 auto MIB =
BuildMI(BB,
I,
I.getDebugLoc(),
TII.get(SPIRV::OpConstantI))
2574 .
addUse(GR.getSPIRVTypeID(ResType));
2581bool SPIRVInstructionSelector::selectOpUndef(
Register ResVReg,
2584 return BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
TII.get(SPIRV::OpUndef))
2586 .
addUse(GR.getSPIRVTypeID(ResType))
2593 if (TypeInst->
getOpcode() == SPIRV::ASSIGN_TYPE) {
2596 return ImmInst->
getOpcode() == TargetOpcode::G_CONSTANT;
2598 return TypeInst->
getOpcode() == SPIRV::OpConstantI;
2603 if (TypeInst->
getOpcode() == SPIRV::OpConstantI)
2610bool SPIRVInstructionSelector::selectInsertVal(
Register ResVReg,
2614 auto MIB =
BuildMI(BB,
I,
I.getDebugLoc(),
TII.get(SPIRV::OpCompositeInsert))
2616 .
addUse(GR.getSPIRVTypeID(ResType))
2618 .
addUse(
I.getOperand(3).getReg())
2620 .
addUse(
I.getOperand(2).getReg());
2621 for (
unsigned i = 4; i <
I.getNumOperands(); i++)
2626bool SPIRVInstructionSelector::selectExtractVal(
Register ResVReg,
2630 auto MIB =
BuildMI(BB,
I,
I.getDebugLoc(),
TII.get(SPIRV::OpCompositeExtract))
2632 .
addUse(GR.getSPIRVTypeID(ResType))
2633 .
addUse(
I.getOperand(2).getReg());
2634 for (
unsigned i = 3; i <
I.getNumOperands(); i++)
2639bool SPIRVInstructionSelector::selectInsertElt(
Register ResVReg,
2643 return selectInsertVal(ResVReg, ResType,
I);
2645 return BuildMI(BB,
I,
I.getDebugLoc(),
TII.get(SPIRV::OpVectorInsertDynamic))
2647 .
addUse(GR.getSPIRVTypeID(ResType))
2648 .
addUse(
I.getOperand(2).getReg())
2649 .
addUse(
I.getOperand(3).getReg())
2650 .
addUse(
I.getOperand(4).getReg())
2654bool SPIRVInstructionSelector::selectExtractElt(
Register ResVReg,
2658 return selectExtractVal(ResVReg, ResType,
I);
2660 return BuildMI(BB,
I,
I.getDebugLoc(),
TII.get(SPIRV::OpVectorExtractDynamic))
2662 .
addUse(GR.getSPIRVTypeID(ResType))
2663 .
addUse(
I.getOperand(2).getReg())
2664 .
addUse(
I.getOperand(3).getReg())
2668bool SPIRVInstructionSelector::selectGEP(
Register ResVReg,
2671 const bool IsGEPInBounds =
I.getOperand(2).getImm();
2676 const unsigned Opcode = STI.isVulkanEnv()
2677 ? (IsGEPInBounds ? SPIRV::OpInBoundsAccessChain
2678 : SPIRV::OpAccessChain)
2679 : (IsGEPInBounds ? SPIRV::OpInBoundsPtrAccessChain
2680 : SPIRV::OpPtrAccessChain);
2682 auto Res =
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
TII.get(Opcode))
2684 .
addUse(GR.getSPIRVTypeID(ResType))
2686 .
addUse(
I.getOperand(3).getReg());
2688 const unsigned StartingIndex =
2689 (Opcode == SPIRV::OpAccessChain || Opcode == SPIRV::OpInBoundsAccessChain)
2692 for (
unsigned i = StartingIndex; i <
I.getNumExplicitOperands(); ++i)
2693 Res.addUse(
I.getOperand(i).getReg());
2694 return Res.constrainAllUses(
TII,
TRI, RBI);
2698bool SPIRVInstructionSelector::wrapIntoSpecConstantOp(
2701 unsigned Lim =
I.getNumExplicitOperands();
2702 for (
unsigned i =
I.getNumExplicitDefs() + 1; i < Lim; ++i) {
2703 Register OpReg =
I.getOperand(i).getReg();
2705 SPIRVType *OpType = GR.getSPIRVTypeForVReg(OpReg);
2707 if (!OpDefine || !OpType ||
isConstReg(
MRI, OpDefine, Visited) ||
2708 OpDefine->
getOpcode() == TargetOpcode::G_ADDRSPACE_CAST ||
2709 GR.isAggregateType(OpType)) {
2716 Register WrapReg = GR.find(OpDefine, MF);
2722 WrapReg =
MRI->createVirtualRegister(GR.getRegClass(OpType));
2723 GR.add(OpDefine, MF, WrapReg);
2727 GR.assignSPIRVTypeToVReg(OpType, WrapReg, *MF);
2731 .
addUse(GR.getSPIRVTypeID(OpType))
2741bool SPIRVInstructionSelector::selectIntrinsic(
Register ResVReg,
2747 case Intrinsic::spv_load:
2748 return selectLoad(ResVReg, ResType,
I);
2749 case Intrinsic::spv_store:
2750 return selectStore(
I);
2751 case Intrinsic::spv_extractv:
2752 return selectExtractVal(ResVReg, ResType,
I);
2753 case Intrinsic::spv_insertv:
2754 return selectInsertVal(ResVReg, ResType,
I);
2755 case Intrinsic::spv_extractelt:
2756 return selectExtractElt(ResVReg, ResType,
I);
2757 case Intrinsic::spv_insertelt:
2758 return selectInsertElt(ResVReg, ResType,
I);
2759 case Intrinsic::spv_gep:
2760 return selectGEP(ResVReg, ResType,
I);
2761 case Intrinsic::spv_unref_global:
2762 case Intrinsic::spv_init_global: {
2765 ?
MRI->getVRegDef(
I.getOperand(2).getReg())
2768 return selectGlobalValue(
MI->getOperand(0).getReg(), *
MI,
Init);
2770 case Intrinsic::spv_undef: {
2771 auto MIB =
BuildMI(BB,
I,
I.getDebugLoc(),
TII.get(SPIRV::OpUndef))
2773 .
addUse(GR.getSPIRVTypeID(ResType));
2776 case Intrinsic::spv_const_composite: {
2778 bool IsNull =
I.getNumExplicitDefs() + 1 ==
I.getNumExplicitOperands();
2780 unsigned Opcode = SPIRV::OpConstantNull;
2783 Opcode = SPIRV::OpConstantComposite;
2784 if (!wrapIntoSpecConstantOp(
I, CompositeArgs))
2787 MRI->setRegClass(ResVReg, GR.getRegClass(ResType));
2788 auto MIB =
BuildMI(BB,
I,
I.getDebugLoc(),
TII.get(Opcode))
2790 .
addUse(GR.getSPIRVTypeID(ResType));
2793 for (
Register OpReg : CompositeArgs)
2798 case Intrinsic::spv_assign_name: {
2799 auto MIB =
BuildMI(BB,
I,
I.getDebugLoc(),
TII.get(SPIRV::OpName));
2800 MIB.
addUse(
I.getOperand(
I.getNumExplicitDefs() + 1).getReg());
2801 for (
unsigned i =
I.getNumExplicitDefs() + 2;
2802 i <
I.getNumExplicitOperands(); ++i) {
2803 MIB.
addImm(
I.getOperand(i).getImm());
2807 case Intrinsic::spv_switch: {
2808 auto MIB =
BuildMI(BB,
I,
I.getDebugLoc(),
TII.get(SPIRV::OpSwitch));
2809 for (
unsigned i = 1; i <
I.getNumExplicitOperands(); ++i) {
2810 if (
I.getOperand(i).isReg())
2811 MIB.
addReg(
I.getOperand(i).getReg());
2812 else if (
I.getOperand(i).isCImm())
2813 addNumImm(
I.getOperand(i).getCImm()->getValue(), MIB);
2814 else if (
I.getOperand(i).isMBB())
2815 MIB.
addMBB(
I.getOperand(i).getMBB());
2821 case Intrinsic::spv_loop_merge:
2822 case Intrinsic::spv_selection_merge: {
2823 const auto Opcode = IID == Intrinsic::spv_selection_merge
2824 ? SPIRV::OpSelectionMerge
2825 : SPIRV::OpLoopMerge;
2826 auto MIB =
BuildMI(BB,
I,
I.getDebugLoc(),
TII.get(Opcode));
2827 for (
unsigned i = 1; i <
I.getNumExplicitOperands(); ++i) {
2828 assert(
I.getOperand(i).isMBB());
2829 MIB.
addMBB(
I.getOperand(i).getMBB());
2831 MIB.
addImm(SPIRV::SelectionControl::None);
2834 case Intrinsic::spv_cmpxchg:
2835 return selectAtomicCmpXchg(ResVReg, ResType,
I);
2836 case Intrinsic::spv_unreachable:
2837 return BuildMI(BB,
I,
I.getDebugLoc(),
TII.get(SPIRV::OpUnreachable))
2839 case Intrinsic::spv_alloca:
2840 return selectFrameIndex(ResVReg, ResType,
I);
2841 case Intrinsic::spv_alloca_array:
2842 return selectAllocaArray(ResVReg, ResType,
I);
2843 case Intrinsic::spv_assume:
2844 if (STI.canUseExtension(SPIRV::Extension::SPV_KHR_expect_assume))
2845 return BuildMI(BB,
I,
I.getDebugLoc(),
TII.get(SPIRV::OpAssumeTrueKHR))
2846 .
addUse(
I.getOperand(1).getReg())
2849 case Intrinsic::spv_expect:
2850 if (STI.canUseExtension(SPIRV::Extension::SPV_KHR_expect_assume))
2851 return BuildMI(BB,
I,
I.getDebugLoc(),
TII.get(SPIRV::OpExpectKHR))
2853 .
addUse(GR.getSPIRVTypeID(ResType))
2854 .
addUse(
I.getOperand(2).getReg())
2855 .
addUse(
I.getOperand(3).getReg())
2858 case Intrinsic::arithmetic_fence:
2859 if (STI.canUseExtension(SPIRV::Extension::SPV_EXT_arithmetic_fence))
2861 TII.get(SPIRV::OpArithmeticFenceEXT))
2863 .
addUse(GR.getSPIRVTypeID(ResType))
2864 .
addUse(
I.getOperand(2).getReg())
2867 return BuildCOPY(ResVReg,
I.getOperand(2).getReg(),
I);
2869 case Intrinsic::spv_thread_id:
2875 return loadVec3BuiltinInputID(SPIRV::BuiltIn::GlobalInvocationId, ResVReg,
2877 case Intrinsic::spv_thread_id_in_group:
2883 return loadVec3BuiltinInputID(SPIRV::BuiltIn::LocalInvocationId, ResVReg,
2885 case Intrinsic::spv_group_id:
2891 return loadVec3BuiltinInputID(SPIRV::BuiltIn::WorkgroupId, ResVReg, ResType,
2893 case Intrinsic::spv_fdot:
2894 return selectFloatDot(ResVReg, ResType,
I);
2895 case Intrinsic::spv_udot:
2896 case Intrinsic::spv_sdot:
2897 if (STI.canUseExtension(SPIRV::Extension::SPV_KHR_integer_dot_product) ||
2899 return selectIntegerDot(ResVReg, ResType,
I,
2900 IID == Intrinsic::spv_sdot);
2901 return selectIntegerDotExpansion(ResVReg, ResType,
I);
2902 case Intrinsic::spv_dot4add_i8packed:
2903 if (STI.canUseExtension(SPIRV::Extension::SPV_KHR_integer_dot_product) ||
2905 return selectDot4AddPacked<true>(ResVReg, ResType,
I);
2906 return selectDot4AddPackedExpansion<true>(ResVReg, ResType,
I);
2907 case Intrinsic::spv_dot4add_u8packed:
2908 if (STI.canUseExtension(SPIRV::Extension::SPV_KHR_integer_dot_product) ||
2910 return selectDot4AddPacked<false>(ResVReg, ResType,
I);
2911 return selectDot4AddPackedExpansion<false>(ResVReg, ResType,
I);
2912 case Intrinsic::spv_all:
2913 return selectAll(ResVReg, ResType,
I);
2914 case Intrinsic::spv_any:
2915 return selectAny(ResVReg, ResType,
I);
2916 case Intrinsic::spv_cross:
2917 return selectExtInst(ResVReg, ResType,
I, CL::cross, GL::Cross);
2918 case Intrinsic::spv_distance:
2919 return selectExtInst(ResVReg, ResType,
I, CL::distance, GL::Distance);
2920 case Intrinsic::spv_lerp:
2921 return selectExtInst(ResVReg, ResType,
I, CL::mix, GL::FMix);
2922 case Intrinsic::spv_length:
2923 return selectExtInst(ResVReg, ResType,
I, CL::length, GL::Length);
2924 case Intrinsic::spv_degrees:
2925 return selectExtInst(ResVReg, ResType,
I, CL::degrees, GL::Degrees);
2926 case Intrinsic::spv_frac:
2927 return selectExtInst(ResVReg, ResType,
I, CL::fract, GL::Fract);
2928 case Intrinsic::spv_normalize:
2929 return selectExtInst(ResVReg, ResType,
I, CL::normalize, GL::Normalize);
2930 case Intrinsic::spv_rsqrt:
2931 return selectExtInst(ResVReg, ResType,
I, CL::rsqrt, GL::InverseSqrt);
2932 case Intrinsic::spv_sign:
2933 return selectSign(ResVReg, ResType,
I);
2934 case Intrinsic::spv_firstbituhigh:
2935 return selectFirstBitHigh(ResVReg, ResType,
I,
false);
2936 case Intrinsic::spv_firstbitshigh:
2937 return selectFirstBitHigh(ResVReg, ResType,
I,
true);
2938 case Intrinsic::spv_group_memory_barrier_with_group_sync: {
2940 auto MemSemConstant =
2941 buildI32Constant(SPIRV::MemorySemantics::SequentiallyConsistent,
I);
2942 Register MemSemReg = MemSemConstant.first;
2943 Result &= MemSemConstant.second;
2944 auto ScopeConstant = buildI32Constant(SPIRV::Scope::Workgroup,
I);
2945 Register ScopeReg = ScopeConstant.first;
2946 Result &= ScopeConstant.second;
2949 BuildMI(BB,
I,
I.getDebugLoc(),
TII.get(SPIRV::OpControlBarrier))
2955 case Intrinsic::spv_lifetime_start:
2956 case Intrinsic::spv_lifetime_end: {
2957 unsigned Op = IID == Intrinsic::spv_lifetime_start ? SPIRV::OpLifetimeStart
2958 : SPIRV::OpLifetimeStop;
2959 int64_t
Size =
I.getOperand(
I.getNumExplicitDefs() + 1).getImm();
2960 Register PtrReg =
I.getOperand(
I.getNumExplicitDefs() + 2).getReg();
2968 case Intrinsic::spv_saturate:
2969 return selectSaturate(ResVReg, ResType,
I);
2970 case Intrinsic::spv_nclamp:
2971 return selectExtInst(ResVReg, ResType,
I, CL::fclamp, GL::NClamp);
2972 case Intrinsic::spv_uclamp:
2973 return selectExtInst(ResVReg, ResType,
I, CL::u_clamp, GL::UClamp);
2974 case Intrinsic::spv_sclamp:
2975 return selectExtInst(ResVReg, ResType,
I, CL::s_clamp, GL::SClamp);
2976 case Intrinsic::spv_wave_active_countbits:
2977 return selectWaveActiveCountBits(ResVReg, ResType,
I);
2978 case Intrinsic::spv_wave_all:
2979 return selectWaveOpInst(ResVReg, ResType,
I, SPIRV::OpGroupNonUniformAll);
2980 case Intrinsic::spv_wave_any:
2981 return selectWaveOpInst(ResVReg, ResType,
I, SPIRV::OpGroupNonUniformAny);
2982 case Intrinsic::spv_wave_is_first_lane:
2983 return selectWaveOpInst(ResVReg, ResType,
I, SPIRV::OpGroupNonUniformElect);
2984 case Intrinsic::spv_wave_readlane:
2985 return selectWaveOpInst(ResVReg, ResType,
I,
2986 SPIRV::OpGroupNonUniformShuffle);
2987 case Intrinsic::spv_step:
2988 return selectExtInst(ResVReg, ResType,
I, CL::step, GL::Step);
2989 case Intrinsic::spv_radians:
2990 return selectExtInst(ResVReg, ResType,
I, CL::radians, GL::Radians);
2994 case Intrinsic::instrprof_increment:
2995 case Intrinsic::instrprof_increment_step:
2996 case Intrinsic::instrprof_value_profile:
2999 case Intrinsic::spv_value_md:
3001 case Intrinsic::spv_resource_handlefrombinding: {
3002 return selectHandleFromBinding(ResVReg, ResType,
I);
3004 case Intrinsic::spv_resource_store_typedbuffer: {
3005 selectImageWriteIntrinsic(
I);
3008 case Intrinsic::spv_resource_load_typedbuffer: {
3009 selectReadImageIntrinsic(ResVReg, ResType,
I);
3012 case Intrinsic::spv_discard: {
3013 return selectDiscard(ResVReg, ResType,
I);
3016 std::string DiagMsg;
3019 DiagMsg =
"Intrinsic selection not implemented: " + DiagMsg;
3026bool SPIRVInstructionSelector::selectHandleFromBinding(
Register &ResVReg,
3033 Register IndexReg =
I.getOperand(5).getReg();
3034 bool IsNonUniform = ArraySize > 1 &&
foldImm(
I.getOperand(6),
MRI);
3037 Register VarReg = buildPointerToResource(ResType, Set, Binding, ArraySize,
3038 IndexReg, IsNonUniform, MIRBuilder);
3045 return BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
TII.get(SPIRV::OpLoad))
3047 .
addUse(GR.getSPIRVTypeID(ResType))
3052void SPIRVInstructionSelector::selectReadImageIntrinsic(
3061 Register ImageReg =
I.getOperand(2).getReg();
3062 assert(
MRI->getVRegDef(ImageReg)->getParent() ==
I.getParent() &&
3063 "The image must be loaded in the same basic block as its use.");
3065 uint64_t ResultSize = GR.getScalarOrVectorComponentCount(ResType);
3066 if (ResultSize == 4) {
3067 BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
TII.get(SPIRV::OpImageRead))
3069 .
addUse(GR.getSPIRVTypeID(ResType))
3071 .
addUse(
I.getOperand(3).getReg());
3075 SPIRVType *ReadType = widenTypeToVec4(ResType,
I);
3076 Register ReadReg =
MRI->createVirtualRegister(GR.getRegClass(ReadType));
3077 BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
TII.get(SPIRV::OpImageRead))
3079 .
addUse(GR.getSPIRVTypeID(ReadType))
3081 .
addUse(
I.getOperand(3).getReg());
3083 if (ResultSize == 1) {
3085 TII.get(SPIRV::OpCompositeExtract))
3087 .
addUse(GR.getSPIRVTypeID(ResType))
3092 extractSubvector(ResVReg, ResType, ReadReg,
I);
3095void SPIRVInstructionSelector::extractSubvector(
3098 SPIRVType *InputType = GR.getResultType(ReadReg);
3099 [[maybe_unused]]
uint64_t InputSize =
3100 GR.getScalarOrVectorComponentCount(InputType);
3101 uint64_t ResultSize = GR.getScalarOrVectorComponentCount(ResType);
3102 assert(InputSize > 1 &&
"The input must be a vector.");
3103 assert(ResultSize > 1 &&
"The result must be a vector.");
3104 assert(ResultSize < InputSize &&
3105 "Cannot extract more element than there are in the input.");
3107 SPIRVType *ScalarType = GR.getScalarOrVectorComponentType(ResType);
3110 Register ComponentReg =
MRI->createVirtualRegister(ScalarRegClass);
3122 TII.get(SPIRV::OpCompositeConstruct))
3124 .
addUse(GR.getSPIRVTypeID(ResType));
3126 for (
Register ComponentReg : ComponentRegisters)
3127 MIB.
addUse(ComponentReg);
3130void SPIRVInstructionSelector::selectImageWriteIntrinsic(
3138 Register ImageReg =
I.getOperand(1).getReg();
3139 assert(
MRI->getVRegDef(ImageReg)->getParent() ==
I.getParent() &&
3140 "The image must be loaded in the same basic block as its use.");
3141 Register CoordinateReg =
I.getOperand(2).getReg();
3142 Register DataReg =
I.getOperand(3).getReg();
3143 assert(GR.getResultType(DataReg)->getOpcode() == SPIRV::OpTypeVector);
3144 assert(GR.getScalarOrVectorComponentCount(GR.getResultType(DataReg)) == 4);
3145 BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
TII.get(SPIRV::OpImageWrite))
3151Register SPIRVInstructionSelector::buildPointerToResource(
3156 return GR.getOrCreateGlobalVariableWithBinding(ResType, Set, Binding,
3159 const SPIRVType *VarType = GR.getOrCreateSPIRVArrayType(
3161 Register VarReg = GR.getOrCreateGlobalVariableWithBinding(
3162 VarType, Set, Binding, MIRBuilder);
3164 SPIRVType *ResPointerType = GR.getOrCreateSPIRVPointerType(
3165 ResType, MIRBuilder, SPIRV::StorageClass::UniformConstant);
3167 Register AcReg =
MRI->createVirtualRegister(&SPIRV::iIDRegClass);
3171 buildOpDecorate(IndexReg, MIRBuilder, SPIRV::Decoration::NonUniformEXT, {});
3172 buildOpDecorate(AcReg, MIRBuilder, SPIRV::Decoration::NonUniformEXT, {});
3177 .
addUse(GR.getSPIRVTypeID(ResPointerType))
3184bool SPIRVInstructionSelector::selectFirstBitHigh16(
Register ResVReg,
3187 bool IsSigned)
const {
3188 unsigned Opcode = IsSigned ? SPIRV::OpSConvert : SPIRV::OpUConvert;
3190 Register ExtReg =
MRI->createVirtualRegister(GR.getRegClass(ResType));
3192 selectOpWithSrcs(ExtReg, ResType,
I, {
I.getOperand(2).
getReg()}, Opcode);
3193 return Result && selectFirstBitHigh32(ResVReg, ResType,
I, ExtReg, IsSigned);
3196bool SPIRVInstructionSelector::selectFirstBitHigh32(
Register ResVReg,
3200 bool IsSigned)
const {
3201 unsigned Opcode = IsSigned ? GL::FindSMsb : GL::FindUMsb;
3202 return BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
TII.get(SPIRV::OpExtInst))
3204 .
addUse(GR.getSPIRVTypeID(ResType))
3205 .
addImm(
static_cast<uint32_t>(SPIRV::InstructionSet::GLSL_std_450))
3211bool SPIRVInstructionSelector::selectFirstBitHigh64(
Register ResVReg,
3214 bool IsSigned)
const {
3215 Register OpReg =
I.getOperand(2).getReg();
3217 unsigned count = GR.getScalarOrVectorComponentCount(ResType);
3218 SPIRVType *baseType = GR.retrieveScalarOrVectorIntType(ResType);
3221 GR.getOrCreateSPIRVVectorType(baseType, 2 *
count, MIRBuilder);
3222 Register bitcastReg =
MRI->createVirtualRegister(GR.getRegClass(postCastT));
3224 selectOpWithSrcs(bitcastReg, postCastT,
I, {OpReg}, SPIRV::OpBitcast);
3227 Register FBHReg =
MRI->createVirtualRegister(GR.getRegClass(postCastT));
3228 Result &= selectFirstBitHigh32(FBHReg, postCastT,
I, bitcastReg, IsSigned);
3231 Register HighReg =
MRI->createVirtualRegister(GR.getRegClass(ResType));
3232 Register LowReg =
MRI->createVirtualRegister(GR.getRegClass(ResType));
3234 bool ZeroAsNull = STI.isOpenCLEnv();
3235 bool isScalarRes = ResType->
getOpcode() != SPIRV::OpTypeVector;
3238 Result &= selectOpWithSrcs(
3239 HighReg, ResType,
I,
3240 {FBHReg, GR.getOrCreateConstInt(0,
I, ResType,
TII, ZeroAsNull)},
3241 SPIRV::OpVectorExtractDynamic);
3242 Result &= selectOpWithSrcs(
3244 {FBHReg, GR.getOrCreateConstInt(1,
I, ResType,
TII, ZeroAsNull)},
3245 SPIRV::OpVectorExtractDynamic);
3247 auto MIB =
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
3248 TII.get(SPIRV::OpVectorShuffle))
3250 .
addUse(GR.getSPIRVTypeID(ResType))
3255 for (j = 0;
j <
count * 2;
j += 2) {
3261 MIB =
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
3262 TII.get(SPIRV::OpVectorShuffle))
3264 .
addUse(GR.getSPIRVTypeID(ResType))
3268 for (j = 1;
j <
count * 2;
j += 2) {
3283 GR.getOrCreateConstInt((
unsigned)-1,
I, ResType,
TII, ZeroAsNull);
3284 Reg0 = GR.getOrCreateConstInt(0,
I, ResType,
TII, ZeroAsNull);
3285 Reg32 = GR.getOrCreateConstInt(32,
I, ResType,
TII, ZeroAsNull);
3286 selectOp = SPIRV::OpSelectSISCond;
3287 addOp = SPIRV::OpIAddS;
3289 BoolType = GR.getOrCreateSPIRVVectorType(BoolType,
count, MIRBuilder);
3291 GR.getOrCreateConstVector((
unsigned)-1,
I, ResType,
TII, ZeroAsNull);
3292 Reg0 = GR.getOrCreateConstVector(0,
I, ResType,
TII, ZeroAsNull);
3293 Reg32 = GR.getOrCreateConstVector(32,
I, ResType,
TII, ZeroAsNull);
3294 selectOp = SPIRV::OpSelectVIVCond;
3295 addOp = SPIRV::OpIAddV;
3299 Register BReg =
MRI->createVirtualRegister(GR.getRegClass(BoolType));
3300 Result &= selectOpWithSrcs(BReg, BoolType,
I, {HighReg, NegOneReg},
3304 Register TmpReg =
MRI->createVirtualRegister(GR.getRegClass(ResType));
3306 selectOpWithSrcs(TmpReg, ResType,
I, {BReg, LowReg, HighReg}, selectOp);
3309 Register ValReg =
MRI->createVirtualRegister(GR.getRegClass(ResType));
3310 Result &= selectOpWithSrcs(ValReg, ResType,
I, {BReg, Reg0, Reg32}, selectOp);
3313 selectOpWithSrcs(ResVReg, ResType,
I, {ValReg, TmpReg}, addOp);
3316bool SPIRVInstructionSelector::selectFirstBitHigh(
Register ResVReg,
3319 bool IsSigned)
const {
3321 Register OpReg =
I.getOperand(2).getReg();
3322 SPIRVType *OpType = GR.getSPIRVTypeForVReg(OpReg);
3324 switch (GR.getScalarOrVectorBitWidth(OpType)) {
3326 return selectFirstBitHigh16(ResVReg, ResType,
I, IsSigned);
3328 return selectFirstBitHigh32(ResVReg, ResType,
I, OpReg, IsSigned);
3330 return selectFirstBitHigh64(ResVReg, ResType,
I, IsSigned);
3333 "spv_firstbituhigh and spv_firstbitshigh only support 16,32,64 bits.");
3337bool SPIRVInstructionSelector::selectAllocaArray(
Register ResVReg,
3343 bool Res =
BuildMI(BB,
I,
I.getDebugLoc(),
3344 TII.get(SPIRV::OpVariableLengthArrayINTEL))
3346 .
addUse(GR.getSPIRVTypeID(ResType))
3347 .
addUse(
I.getOperand(2).getReg())
3349 if (!STI.isVulkanEnv()) {
3350 unsigned Alignment =
I.getOperand(3).getImm();
3356bool SPIRVInstructionSelector::selectFrameIndex(
Register ResVReg,
3362 bool Res =
BuildMI(*It->getParent(), It, It->getDebugLoc(),
3363 TII.get(SPIRV::OpVariable))
3365 .
addUse(GR.getSPIRVTypeID(ResType))
3368 if (!STI.isVulkanEnv()) {
3369 unsigned Alignment =
I.getOperand(2).getImm();
3376bool SPIRVInstructionSelector::selectBranch(
MachineInstr &
I)
const {
3383 if (PrevI !=
nullptr && PrevI->
getOpcode() == TargetOpcode::G_BRCOND) {
3384 return BuildMI(
MBB,
I,
I.getDebugLoc(),
TII.get(SPIRV::OpBranchConditional))
3387 .
addMBB(
I.getOperand(0).getMBB())
3391 .
addMBB(
I.getOperand(0).getMBB())
3395bool SPIRVInstructionSelector::selectBranchCond(
MachineInstr &
I)
const {
3408 if (NextI !=
nullptr && NextI->
getOpcode() == SPIRV::OpBranchConditional)
3415 return BuildMI(
MBB,
I,
I.getDebugLoc(),
TII.get(SPIRV::OpBranchConditional))
3416 .
addUse(
I.getOperand(0).getReg())
3417 .
addMBB(
I.getOperand(1).getMBB())
3422bool SPIRVInstructionSelector::selectPhi(
Register ResVReg,
3425 auto MIB =
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
TII.get(SPIRV::OpPhi))
3427 .
addUse(GR.getSPIRVTypeID(ResType));
3428 const unsigned NumOps =
I.getNumOperands();
3429 for (
unsigned i = 1; i < NumOps; i += 2) {
3430 MIB.
addUse(
I.getOperand(i + 0).getReg());
3431 MIB.
addMBB(
I.getOperand(i + 1).getMBB());
3439bool SPIRVInstructionSelector::selectGlobalValue(
3449 SPIRV::AccessQualifier::ReadWrite,
false);
3450 PointerBaseType = GR.getOrCreateSPIRVArrayType(
3453 PointerBaseType = GR.getOrCreateSPIRVType(
3454 GVType, MIRBuilder, SPIRV::AccessQualifier::ReadWrite,
false);
3457 std::string GlobalIdent;
3459 unsigned &
ID = UnnamedGlobalIDs[GV];
3461 ID = UnnamedGlobalIDs.size();
3462 GlobalIdent =
"__unnamed_" +
Twine(
ID).
str();
3477 if (isa<Function>(GV)) {
3480 Register NewReg = GR.find(ConstVal, GR.CurMF);
3483 GR.add(ConstVal, GR.CurMF, NewReg);
3485 STI.canUseExtension(SPIRV::Extension::SPV_INTEL_function_pointers)
3486 ? dyn_cast<Function>(GV)
3488 SPIRVType *ResType = GR.getOrCreateSPIRVPointerType(
3489 PointerBaseType,
I,
TII,
3490 GVFun ? SPIRV::StorageClass::CodeSectionINTEL
3496 Register ResTypeReg = GR.getSPIRVTypeID(ResType);
3499 MRI->createGenericVirtualRegister(GR.getRegType(ResType));
3500 MRI->setRegClass(FuncVReg, &SPIRV::pIDRegClass);
3502 BuildMI(BB,
I,
I.getDebugLoc(),
TII.get(SPIRV::OpUndef))
3507 TII.get(SPIRV::OpConstantFunctionPointerINTEL))
3516 return BuildMI(BB,
I,
I.getDebugLoc(),
TII.get(SPIRV::OpConstantNull))
3518 .
addUse(GR.getSPIRVTypeID(ResType))
3521 assert(NewReg != ResVReg);
3522 return BuildCOPY(ResVReg, NewReg,
I);
3524 auto GlobalVar = cast<GlobalVariable>(GV);
3533 SPIRV::LinkageType::LinkageType LnkType =
3535 ? SPIRV::LinkageType::Import
3537 STI.canUseExtension(SPIRV::Extension::SPV_KHR_linkonce_odr)
3538 ? SPIRV::LinkageType::LinkOnceODR
3539 : SPIRV::LinkageType::Export);
3548 GlobalVar->isConstant(), HasLnkTy, LnkType, MIRBuilder,
true);
3549 return Reg.isValid();
3552bool SPIRVInstructionSelector::selectLog10(
Register ResVReg,
3555 if (STI.canUseExtInstSet(SPIRV::InstructionSet::OpenCL_std)) {
3556 return selectExtInst(ResVReg, ResType,
I, CL::log10);
3568 Register VarReg =
MRI->createVirtualRegister(GR.getRegClass(ResType));
3570 BuildMI(BB,
I,
I.getDebugLoc(),
TII.get(SPIRV::OpExtInst))
3572 .
addUse(GR.getSPIRVTypeID(ResType))
3573 .
addImm(
static_cast<uint32_t>(SPIRV::InstructionSet::GLSL_std_450))
3575 .
add(
I.getOperand(1))
3580 ResType->
getOpcode() == SPIRV::OpTypeFloat);
3583 ResType->
getOpcode() == SPIRV::OpTypeVector
3587 GR.buildConstantFP(
APFloat(0.30103f), MIRBuilder, SpirvScalarType);
3590 auto Opcode = ResType->
getOpcode() == SPIRV::OpTypeVector
3591 ? SPIRV::OpVectorTimesScalar
3595 .
addUse(GR.getSPIRVTypeID(ResType))
3604bool SPIRVInstructionSelector::loadVec3BuiltinInputID(
3605 SPIRV::BuiltIn::BuiltIn BuiltInValue,
Register ResVReg,
3608 const SPIRVType *U32Type = GR.getOrCreateSPIRVIntegerType(32, MIRBuilder);
3610 GR.getOrCreateSPIRVVectorType(U32Type, 3, MIRBuilder);
3611 const SPIRVType *PtrType = GR.getOrCreateSPIRVPointerType(
3612 Vec3Ty, MIRBuilder, SPIRV::StorageClass::Input);
3618 GR.assignSPIRVTypeToVReg(PtrType, NewRegister, MIRBuilder.
getMF());
3622 Register Variable = GR.buildGlobalVariable(
3624 SPIRV::StorageClass::Input,
nullptr,
true,
true,
3625 SPIRV::LinkageType::Import, MIRBuilder,
false);
3629 Register LoadedRegister =
MRI->createVirtualRegister(&SPIRV::iIDRegClass);
3631 GR.assignSPIRVTypeToVReg(Vec3Ty, LoadedRegister, MIRBuilder.
getMF());
3635 BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
TII.get(SPIRV::OpLoad))
3637 .
addUse(GR.getSPIRVTypeID(Vec3Ty))
3642 assert(
I.getOperand(2).isReg());
3647 auto MIB =
BuildMI(BB,
I,
I.getDebugLoc(),
TII.get(SPIRV::OpCompositeExtract))
3649 .
addUse(GR.getSPIRVTypeID(ResType))
3658 if (
Type->getOpcode() != SPIRV::OpTypeVector)
3659 return GR.getOrCreateSPIRVVectorType(
Type, 4, MIRBuilder);
3662 if (VectorSize == 4)
3666 const SPIRVType *ScalarType = GR.getSPIRVTypeForVReg(ScalarTypeReg);
3667 return GR.getOrCreateSPIRVVectorType(ScalarType, 4, MIRBuilder);
3675 return new SPIRVInstructionSelector(TM, Subtarget, RBI);
unsigned const MachineRegisterInfo * MRI
This file declares a class to represent arbitrary precision floating point values and provide a varie...
static bool selectUnmergeValues(MachineInstrBuilder &MIB, const ARMBaseInstrInfo &TII, MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI, const RegisterBankInfo &RBI)
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
Returns the sub type a function will return at a given Idx Should correspond to the result type of an ExtractValue instruction executed with just that one unsigned Idx
Declares convenience wrapper classes for interpreting MachineInstr instances as specific generic oper...
const HexagonInstrInfo * TII
unsigned const TargetRegisterInfo * TRI
static unsigned getReg(const MCDisassembler *D, unsigned RC, unsigned RegNo)
uint64_t IntrinsicInst * II
static StringRef getName(Value *V)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
std::vector< std::pair< SPIRV::InstructionSet::InstructionSet, uint32_t > > ExtInstList
#define GET_GLOBALISEL_PREDICATES_INIT
#define GET_GLOBALISEL_TEMPORARIES_INIT
static APFloat getOneFP(const Type *LLVMFloatTy)
static bool isUSMStorageClass(SPIRV::StorageClass::StorageClass SC)
static bool isASCastInGVar(MachineRegisterInfo *MRI, Register ResVReg)
static bool mayApplyGenericSelection(unsigned Opcode)
static APFloat getZeroFP(const Type *LLVMFloatTy)
static void addMemoryOperands(MachineMemOperand *MemOp, MachineInstrBuilder &MIB)
static unsigned getFCmpOpcode(unsigned PredNum)
bool isTypeFoldingSupported(unsigned Opcode)
static bool isImm(const MachineOperand &MO, MachineRegisterInfo *MRI)
static unsigned getBoolCmpOpcode(unsigned PredNum)
static unsigned getICmpOpcode(unsigned PredNum)
static bool isConstReg(MachineRegisterInfo *MRI, SPIRVType *OpDef, SmallPtrSet< SPIRVType *, 4 > &Visited)
static int64_t foldImm(const MachineOperand &MO, MachineRegisterInfo *MRI)
static bool isGenericCastablePtr(SPIRV::StorageClass::StorageClass SC)
static unsigned getPtrCmpOpcode(unsigned Pred)
bool isDead(const MachineInstr &MI, const MachineRegisterInfo &MRI)
static unsigned getArrayComponentCount(MachineRegisterInfo *MRI, const SPIRVType *ResType)
static APFloat getOne(const fltSemantics &Sem, bool Negative=false)
Factory for Positive and Negative One.
APInt bitcastToAPInt() const
static APFloat getZero(const fltSemantics &Sem, bool Negative=false)
Factory for Positive and Negative Zero.
Class for arbitrary precision integers.
static APInt getAllOnes(unsigned numBits)
Return an APInt of a specified width with all bits set.
uint64_t getZExtValue() const
Get zero extended value.
BlockFrequencyInfo pass uses BlockFrequencyInfoImpl implementation to estimate IR basic block frequen...
Predicate
This enumeration lists the possible predicates for CmpInst subclasses.
@ FCMP_OEQ
0 0 0 1 True if ordered and equal
@ ICMP_SLT
signed less than
@ ICMP_SLE
signed less or equal
@ FCMP_OLT
0 1 0 0 True if ordered and less than
@ FCMP_ULE
1 1 0 1 True if unordered, less than, or equal
@ FCMP_OGT
0 0 1 0 True if ordered and greater than
@ FCMP_OGE
0 0 1 1 True if ordered and greater than or equal
@ ICMP_UGE
unsigned greater or equal
@ ICMP_UGT
unsigned greater than
@ ICMP_SGT
signed greater than
@ FCMP_ULT
1 1 0 0 True if unordered or less than
@ FCMP_ONE
0 1 1 0 True if ordered and operands are unequal
@ FCMP_UEQ
1 0 0 1 True if unordered or equal
@ ICMP_ULT
unsigned less than
@ FCMP_UGT
1 0 1 0 True if unordered or greater than
@ FCMP_OLE
0 1 0 1 True if ordered and less than or equal
@ FCMP_ORD
0 1 1 1 True if ordered (no nans)
@ ICMP_SGE
signed greater or equal
@ FCMP_UNE
1 1 1 0 True if unordered or not equal
@ ICMP_ULE
unsigned less or equal
@ FCMP_UGE
1 0 1 1 True if unordered, greater than, or equal
@ FCMP_UNO
1 0 0 0 True if unordered: isnan(X) | isnan(Y)
ConstantFP - Floating Point Values [float, double].
const APFloat & getValueAPF() const
uint64_t getZExtValue() const
Return the constant as a 64-bit unsigned integer value after it has been zero extended as appropriate...
const APInt & getValue() const
Return the constant as an APInt value reference.
This is an important base class in LLVM.
static Constant * getNullValue(Type *Ty)
Constructor to create a '0' constant of arbitrary type.
This class represents an Operation in the Expression.
const Function & getFunction() const
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function.
bool hasPrivateLinkage() const
bool isDeclarationForLinker() const
unsigned getAddressSpace() const
Module * getParent()
Get the module that this global value is contained inside of...
bool hasInternalLinkage() const
bool hasLinkOnceODRLinkage() const
@ InternalLinkage
Rename collisions when linking (static functions).
static IntegerType * get(LLVMContext &C, unsigned NumBits)
This static method is the primary way of constructing an IntegerType.
constexpr bool isScalar() const
static constexpr LLT scalar(unsigned SizeInBits)
Get a low-level scalar or aggregate "bag of bits".
constexpr bool isVector() const
static constexpr LLT pointer(unsigned AddressSpace, unsigned SizeInBits)
Get a low-level pointer in the given address space.
constexpr bool isPointer() const
static constexpr LLT fixed_vector(unsigned NumElements, unsigned ScalarSizeInBits)
Get a low-level fixed-width vector of some number of elements and element width.
int getNumber() const
MachineBasicBlocks are uniquely numbered at the function level, unless they're not in a MachineFuncti...
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
Helper class to build MachineInstr.
MachineBasicBlock::iterator getInsertPt()
Current insertion point for new instructions.
MachineInstrBuilder buildInstr(unsigned Opcode)
Build and insert <empty> = Opcode <empty>.
MachineFunction & getMF()
Getter for the function we currently build.
MachineRegisterInfo * getMRI()
Getter for MRI.
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
const MachineInstrBuilder & add(const MachineOperand &MO) const
const MachineInstrBuilder & addReg(Register RegNo, unsigned flags=0, unsigned SubReg=0) const
Add a new virtual register operand.
bool constrainAllUses(const TargetInstrInfo &TII, const TargetRegisterInfo &TRI, const RegisterBankInfo &RBI) const
const MachineInstrBuilder & addMBB(MachineBasicBlock *MBB, unsigned TargetFlags=0) const
const MachineInstrBuilder & addUse(Register RegNo, unsigned Flags=0, unsigned SubReg=0) const
Add a virtual register use operand.
MachineInstr * getInstr() const
If conversion operators fail, use this method to get the MachineInstr explicitly.
const MachineInstrBuilder & addDef(Register RegNo, unsigned Flags=0, unsigned SubReg=0) const
Add a virtual register definition operand.
Representation of each machine instruction.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
void setDesc(const MCInstrDesc &TID)
Replace the instruction descriptor (thus opcode) of the current instruction with a new one.
unsigned getNumExplicitDefs() const
Returns the number of non-implicit definitions.
void removeOperand(unsigned OpNo)
Erase an operand from an instruction, leaving it with one fewer operand than it started with.
const MachineOperand & getOperand(unsigned i) const
A description of a memory reference used in the backend.
MachineOperand class - Representation of each machine instruction operand.
const ConstantInt * getCImm() const
bool isReg() const
isReg - Tests if this is a MO_Register operand.
MachineBasicBlock * getMBB() const
Register getReg() const
getReg - Returns the register number.
defusechain_iterator - This class provides iterator support for machine operands in the function that...
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
Register createVirtualRegister(const TargetRegisterClass *RegClass, StringRef Name="")
createVirtualRegister - Create and return a new virtual register in the function with the specified r...
void setType(Register VReg, LLT Ty)
Set the low-level type of VReg to Ty.
Analysis providing profile information.
Holds all the information related to register banks.
Wrapper class representing virtual and physical registers.
static Register index2VirtReg(unsigned Index)
Convert a 0-based index to a virtual register number.
constexpr bool isValid() const
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
bool contains(ConstPtrType Ptr) const
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
reference emplace_back(ArgTypes &&... Args)
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
StringRef - Represent a constant reference to a string, i.e.
constexpr size_t size() const
size - Get the string size.
Class to represent struct types.
static StructType * get(LLVMContext &Context, ArrayRef< Type * > Elements, bool isPacked=false)
This static method is the primary way to create a literal StructType.
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
std::string str() const
Return the twine contents as a std::string.
The instances of the Type class are immutable: once they are created, they are never changed.
bool isArrayTy() const
True if this is an instance of ArrayType.
Type * getArrayElementType() const
uint64_t getArrayNumElements() const
@ HalfTyID
16-bit floating point type
@ FloatTyID
32-bit floating point type
@ DoubleTyID
64-bit floating point type
bool isStructTy() const
True if this is an instance of StructType.
TypeID getTypeID() const
Return the type id for the type.
Type * getScalarType() const
If this is a vector type, return the element type, otherwise return 'this'.
StringRef getName() const
Return a constant reference to the value's name.
Represents a version number in the form major[.minor[.subminor[.build]]].
NodeTy * getNextNode()
Get the next node, or nullptr for the list tail.
A raw_ostream that writes to an std::string.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
constexpr char IsConst[]
Key for Kernel::Arg::Metadata::mIsConst.
Reg
All possible values of the reg field in the ModR/M byte.
Scope
Defines the scope in which this symbol should be visible: Default – Visible in the public interface o...
NodeAddr< DefNode * > Def
This is an optimization pass for GlobalISel generic memory operations.
void buildOpName(Register Target, const StringRef &Name, MachineIRBuilder &MIRBuilder)
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
void addNumImm(const APInt &Imm, MachineInstrBuilder &MIB)
void salvageDebugInfo(const MachineRegisterInfo &MRI, MachineInstr &MI)
Assuming the instruction MI is going to be deleted, attempt to salvage debug users of MI by writing t...
bool constrainSelectedInstRegOperands(MachineInstr &I, const TargetInstrInfo &TII, const TargetRegisterInfo &TRI, const RegisterBankInfo &RBI)
Mutate the newly-selected instruction I to constrain its (possibly generic) virtual register operands...
bool isPreISelGenericOpcode(unsigned Opcode)
Check whether the given Opcode is a generic opcode that is not supposed to appear after ISel.
uint64_t getIConstVal(Register ConstReg, const MachineRegisterInfo *MRI)
SPIRV::MemorySemantics::MemorySemantics getMemSemanticsForStorageClass(SPIRV::StorageClass::StorageClass SC)
constexpr unsigned storageClassToAddressSpace(SPIRV::StorageClass::StorageClass SC)
void buildOpDecorate(Register Reg, MachineIRBuilder &MIRBuilder, SPIRV::Decoration::Decoration Dec, const std::vector< uint32_t > &DecArgs, StringRef StrImm)
MachineBasicBlock::iterator getOpVariableMBBIt(MachineInstr &I)
Type * toTypedPointer(Type *Ty)
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
void report_fatal_error(Error Err, bool gen_crash_diag=true)
Report a serious error, calling any installed error handler.
raw_fd_ostream & errs()
This returns a reference to a raw_ostream for standard error.
SPIRV::StorageClass::StorageClass addressSpaceToStorageClass(unsigned AddrSpace, const SPIRVSubtarget &STI)
AtomicOrdering
Atomic ordering for LLVM's memory model.
SPIRV::Scope::Scope getMemScope(LLVMContext &Ctx, SyncScope::ID Id)
InstructionSelector * createSPIRVInstructionSelector(const SPIRVTargetMachine &TM, const SPIRVSubtarget &Subtarget, const RegisterBankInfo &RBI)
auto count(R &&Range, const E &Element)
Wrapper function around std::count to count the number of times an element Element occurs in the give...
constexpr unsigned BitWidth
bool hasInitializer(const GlobalVariable *GV)
SPIRV::MemorySemantics::MemorySemantics getMemSemantics(AtomicOrdering Ord)
std::string getLinkStringForBuiltIn(SPIRV::BuiltIn::BuiltIn BuiltInValue)
bool isTriviallyDead(const MachineInstr &MI, const MachineRegisterInfo &MRI)
Check whether an instruction MI is dead: it only defines dead virtual registers, and doesn't have oth...