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);
1110 BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
TII.get(SPIRV::OpVariable))
1112 .
addUse(GR.getSPIRVTypeID(VarTy))
1113 .
addImm(SPIRV::StorageClass::UniformConstant)
1117 SPIRVType *SourceTy = GR.getOrCreateSPIRVPointerType(
1118 ValTy,
I,
TII, SPIRV::StorageClass::UniformConstant);
1120 selectOpWithSrcs(SrcReg, SourceTy,
I, {VarReg}, SPIRV::OpBitcast);
1122 auto MIB =
BuildMI(BB,
I,
I.getDebugLoc(),
TII.get(SPIRV::OpCopyMemorySized))
1123 .
addUse(
I.getOperand(0).getReg())
1125 .
addUse(
I.getOperand(2).getReg());
1126 if (
I.getNumMemOperands())
1134bool SPIRVInstructionSelector::selectAtomicRMW(
Register ResVReg,
1138 unsigned NegateOpcode)
const {
1143 GR.CurMF->getFunction().getContext(),
MemOp->getSyncScopeID()));
1144 auto ScopeConstant = buildI32Constant(Scope,
I);
1145 Register ScopeReg = ScopeConstant.first;
1146 Result &= ScopeConstant.second;
1154 auto MemSemConstant = buildI32Constant(MemSem ,
I);
1155 Register MemSemReg = MemSemConstant.first;
1156 Result &= MemSemConstant.second;
1158 Register ValueReg =
I.getOperand(2).getReg();
1159 if (NegateOpcode != 0) {
1161 Register TmpReg =
MRI->createVirtualRegister(&SPIRV::iIDRegClass);
1162 Result &= selectOpWithSrcs(TmpReg, ResType,
I, {ValueReg}, NegateOpcode);
1167 BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
TII.get(NewOpcode))
1169 .
addUse(GR.getSPIRVTypeID(ResType))
1177bool SPIRVInstructionSelector::selectUnmergeValues(
MachineInstr &
I)
const {
1178 unsigned ArgI =
I.getNumOperands() - 1;
1180 I.getOperand(ArgI).isReg() ?
I.getOperand(ArgI).getReg() :
Register(0);
1182 SrcReg.
isValid() ? GR.getSPIRVTypeForVReg(SrcReg) :
nullptr;
1183 if (!DefType || DefType->
getOpcode() != SPIRV::OpTypeVector)
1185 "cannot select G_UNMERGE_VALUES with a non-vector argument");
1191 for (
unsigned i = 0; i <
I.getNumDefs(); ++i) {
1192 Register ResVReg =
I.getOperand(i).getReg();
1193 SPIRVType *ResType = GR.getSPIRVTypeForVReg(ResVReg);
1196 ResType = ScalarType;
1197 MRI->setRegClass(ResVReg, GR.getRegClass(ResType));
1198 MRI->setType(ResVReg,
LLT::scalar(GR.getScalarOrVectorBitWidth(ResType)));
1199 GR.assignSPIRVTypeToVReg(ResType, ResVReg, *GR.CurMF);
1202 BuildMI(BB,
I,
I.getDebugLoc(),
TII.get(SPIRV::OpCompositeExtract))
1204 .
addUse(GR.getSPIRVTypeID(ResType))
1206 .
addImm(
static_cast<int64_t
>(i));
1212bool SPIRVInstructionSelector::selectFence(
MachineInstr &
I)
const {
1215 auto MemSemConstant = buildI32Constant(MemSem,
I);
1216 Register MemSemReg = MemSemConstant.first;
1217 bool Result = MemSemConstant.second;
1220 getMemScope(GR.CurMF->getFunction().getContext(), Ord));
1221 auto ScopeConstant = buildI32Constant(Scope,
I);
1222 Register ScopeReg = ScopeConstant.first;
1223 Result &= ScopeConstant.second;
1226 BuildMI(BB,
I,
I.getDebugLoc(),
TII.get(SPIRV::OpMemoryBarrier))
1232bool SPIRVInstructionSelector::selectOverflowArith(
Register ResVReg,
1235 unsigned Opcode)
const {
1236 Type *ResTy =
nullptr;
1238 if (!GR.findValueAttrs(&
I, ResTy, ResName))
1240 "Not enough info to select the arithmetic with overflow instruction");
1243 "with overflow instruction");
1246 Type *ResElemTy = cast<StructType>(ResTy)->getElementType(0);
1251 ResTy, MIRBuilder, SPIRV::AccessQualifier::ReadWrite,
false);
1252 assert(
I.getNumDefs() > 1 &&
"Not enought operands");
1254 unsigned N = GR.getScalarOrVectorComponentCount(ResType);
1256 BoolType = GR.getOrCreateSPIRVVectorType(BoolType,
N,
I,
TII);
1257 Register BoolTypeReg = GR.getSPIRVTypeID(BoolType);
1258 Register ZeroReg = buildZerosVal(ResType,
I);
1261 MRI->setRegClass(StructVReg, &SPIRV::IDRegClass);
1263 if (ResName.
size() > 0)
1268 BuildMI(BB, MIRBuilder.getInsertPt(),
I.getDebugLoc(),
TII.get(Opcode))
1271 for (
unsigned i =
I.getNumDefs(); i <
I.getNumOperands(); ++i)
1272 MIB.
addUse(
I.getOperand(i).getReg());
1277 MRI->setRegClass(HigherVReg, &SPIRV::iIDRegClass);
1278 for (
unsigned i = 0; i <
I.getNumDefs(); ++i) {
1280 BuildMI(BB,
I,
I.getDebugLoc(),
TII.get(SPIRV::OpCompositeExtract))
1281 .
addDef(i == 1 ? HigherVReg :
I.getOperand(i).getReg())
1282 .
addUse(GR.getSPIRVTypeID(ResType))
1289 .
addDef(
I.getOperand(1).getReg())
1296bool SPIRVInstructionSelector::selectAtomicCmpXchg(
Register ResVReg,
1304 if (!isa<GIntrinsic>(
I)) {
1308 GR.CurMF->getFunction().getContext(),
MemOp->getSyncScopeID()));
1309 auto ScopeConstant = buildI32Constant(Scope,
I);
1310 ScopeReg = ScopeConstant.first;
1311 Result &= ScopeConstant.second;
1313 unsigned ScSem =
static_cast<uint32_t>(
1317 auto MemSemEqConstant = buildI32Constant(MemSemEq,
I);
1318 MemSemEqReg = MemSemEqConstant.first;
1319 Result &= MemSemEqConstant.second;
1322 if (MemSemEq == MemSemNeq)
1323 MemSemNeqReg = MemSemEqReg;
1325 auto MemSemNeqConstant = buildI32Constant(MemSemEq,
I);
1326 MemSemNeqReg = MemSemNeqConstant.first;
1327 Result &= MemSemNeqConstant.second;
1330 ScopeReg =
I.getOperand(5).getReg();
1331 MemSemEqReg =
I.getOperand(6).getReg();
1332 MemSemNeqReg =
I.getOperand(7).getReg();
1336 Register Val =
I.getOperand(4).getReg();
1337 SPIRVType *SpvValTy = GR.getSPIRVTypeForVReg(Val);
1338 Register ACmpRes =
MRI->createVirtualRegister(&SPIRV::iIDRegClass);
1341 BuildMI(*
I.getParent(),
I,
DL,
TII.get(SPIRV::OpAtomicCompareExchange))
1343 .
addUse(GR.getSPIRVTypeID(SpvValTy))
1351 Register CmpSuccReg =
MRI->createVirtualRegister(&SPIRV::iIDRegClass);
1355 .
addUse(GR.getSPIRVTypeID(BoolTy))
1359 Register TmpReg =
MRI->createVirtualRegister(&SPIRV::iIDRegClass);
1362 .
addUse(GR.getSPIRVTypeID(ResType))
1364 .
addUse(GR.getOrCreateUndef(
I, ResType,
TII))
1368 BuildMI(*
I.getParent(),
I,
DL,
TII.get(SPIRV::OpCompositeInsert))
1370 .
addUse(GR.getSPIRVTypeID(ResType))
1379 case SPIRV::StorageClass::Workgroup:
1380 case SPIRV::StorageClass::CrossWorkgroup:
1381 case SPIRV::StorageClass::Function:
1390 case SPIRV::StorageClass::DeviceOnlyINTEL:
1391 case SPIRV::StorageClass::HostOnlyINTEL:
1400 bool IsGRef =
false;
1401 bool IsAllowedRefs =
1402 std::all_of(
MRI->use_instr_begin(ResVReg),
MRI->use_instr_end(),
1403 [&IsGRef](
auto const &It) {
1404 unsigned Opcode = It.getOpcode();
1405 if (Opcode == SPIRV::OpConstantComposite ||
1406 Opcode == SPIRV::OpVariable ||
1407 isSpvIntrinsic(It, Intrinsic::spv_init_global))
1408 return IsGRef = true;
1409 return Opcode == SPIRV::OpName;
1411 return IsAllowedRefs && IsGRef;
1414Register SPIRVInstructionSelector::getUcharPtrTypeReg(
1415 MachineInstr &
I, SPIRV::StorageClass::StorageClass SC)
const {
1416 return GR.getSPIRVTypeID(GR.getOrCreateSPIRVPointerType(
1417 GR.getOrCreateSPIRVIntegerType(8,
I,
TII),
I,
TII, SC));
1424 return BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
1425 TII.get(SPIRV::OpSpecConstantOp))
1435 SPIRVType *GenericPtrTy = GR.getOrCreateSPIRVPointerType(
1436 GR.getPointeeType(SrcPtrTy),
I,
TII, SPIRV::StorageClass::Generic);
1437 Register Tmp =
MRI->createVirtualRegister(&SPIRV::pIDRegClass);
1439 SPIRV::StorageClass::Generic),
1440 GR.getPointerSize()));
1442 GR.assignSPIRVTypeToVReg(GenericPtrTy, Tmp, *MF);
1444 I, Tmp, SrcPtr, GR.getSPIRVTypeID(GenericPtrTy),
1445 static_cast<uint32_t>(SPIRV::Opcode::PtrCastToGeneric));
1455bool SPIRVInstructionSelector::selectAddrSpaceCast(
Register ResVReg,
1461 Register SrcPtr =
I.getOperand(1).getReg();
1462 SPIRVType *SrcPtrTy = GR.getSPIRVTypeForVReg(SrcPtr);
1465 if (SrcPtrTy->
getOpcode() != SPIRV::OpTypePointer ||
1466 ResType->
getOpcode() != SPIRV::OpTypePointer)
1467 return BuildCOPY(ResVReg, SrcPtr,
I);
1469 SPIRV::StorageClass::StorageClass SrcSC = GR.getPointerStorageClass(SrcPtrTy);
1470 SPIRV::StorageClass::StorageClass DstSC = GR.getPointerStorageClass(ResType);
1477 unsigned SpecOpcode =
1479 ?
static_cast<uint32_t>(SPIRV::Opcode::PtrCastToGeneric)
1480 : (SrcSC == SPIRV::StorageClass::Generic &&
1482 ?
static_cast<uint32_t>(SPIRV::Opcode::GenericCastToPtr)
1489 return buildSpecConstantOp(
I, ResVReg, SrcPtr,
1490 getUcharPtrTypeReg(
I, DstSC), SpecOpcode)
1491 .constrainAllUses(
TII,
TRI, RBI);
1495 buildSpecConstantOp(
1497 getUcharPtrTypeReg(
I, DstSC),
1498 static_cast<uint32_t>(SPIRV::Opcode::GenericCastToPtr))
1499 .constrainAllUses(
TII,
TRI, RBI);
1505 return BuildCOPY(ResVReg, SrcPtr,
I);
1507 if ((SrcSC == SPIRV::StorageClass::Function &&
1508 DstSC == SPIRV::StorageClass::Private) ||
1509 (DstSC == SPIRV::StorageClass::Function &&
1510 SrcSC == SPIRV::StorageClass::Private))
1511 return BuildCOPY(ResVReg, SrcPtr,
I);
1515 return selectUnOp(ResVReg, ResType,
I, SPIRV::OpPtrCastToGeneric);
1518 return selectUnOp(ResVReg, ResType,
I, SPIRV::OpGenericCastToPtr);
1521 Register Tmp =
MRI->createVirtualRegister(&SPIRV::iIDRegClass);
1522 SPIRVType *GenericPtrTy = GR.getOrCreateSPIRVPointerType(
1523 GR.getPointeeType(SrcPtrTy),
I,
TII, SPIRV::StorageClass::Generic);
1526 .
addUse(GR.getSPIRVTypeID(GenericPtrTy))
1531 .
addUse(GR.getSPIRVTypeID(ResType))
1539 return selectUnOp(ResVReg, ResType,
I,
1540 SPIRV::OpPtrCastToCrossWorkgroupINTEL);
1542 return selectUnOp(ResVReg, ResType,
I,
1543 SPIRV::OpCrossWorkgroupCastToPtrINTEL);
1545 return selectUnOp(ResVReg, ResType,
I, SPIRV::OpPtrCastToGeneric);
1547 return selectUnOp(ResVReg, ResType,
I, SPIRV::OpGenericCastToPtr);
1557 return SPIRV::OpFOrdEqual;
1559 return SPIRV::OpFOrdGreaterThanEqual;
1561 return SPIRV::OpFOrdGreaterThan;
1563 return SPIRV::OpFOrdLessThanEqual;
1565 return SPIRV::OpFOrdLessThan;
1567 return SPIRV::OpFOrdNotEqual;
1569 return SPIRV::OpOrdered;
1571 return SPIRV::OpFUnordEqual;
1573 return SPIRV::OpFUnordGreaterThanEqual;
1575 return SPIRV::OpFUnordGreaterThan;
1577 return SPIRV::OpFUnordLessThanEqual;
1579 return SPIRV::OpFUnordLessThan;
1581 return SPIRV::OpFUnordNotEqual;
1583 return SPIRV::OpUnordered;
1593 return SPIRV::OpIEqual;
1595 return SPIRV::OpINotEqual;
1597 return SPIRV::OpSGreaterThanEqual;
1599 return SPIRV::OpSGreaterThan;
1601 return SPIRV::OpSLessThanEqual;
1603 return SPIRV::OpSLessThan;
1605 return SPIRV::OpUGreaterThanEqual;
1607 return SPIRV::OpUGreaterThan;
1609 return SPIRV::OpULessThanEqual;
1611 return SPIRV::OpULessThan;
1620 return SPIRV::OpPtrEqual;
1622 return SPIRV::OpPtrNotEqual;
1633 return SPIRV::OpLogicalEqual;
1635 return SPIRV::OpLogicalNotEqual;
1669bool SPIRVInstructionSelector::selectAnyOrAll(
Register ResVReg,
1672 unsigned OpAnyOrAll)
const {
1673 assert(
I.getNumOperands() == 3);
1674 assert(
I.getOperand(2).isReg());
1676 Register InputRegister =
I.getOperand(2).getReg();
1677 SPIRVType *InputType = GR.getSPIRVTypeForVReg(InputRegister);
1682 bool IsBoolTy = GR.isScalarOrVectorOfType(InputRegister, SPIRV::OpTypeBool);
1683 bool IsVectorTy = InputType->
getOpcode() == SPIRV::OpTypeVector;
1684 if (IsBoolTy && !IsVectorTy) {
1685 assert(ResVReg ==
I.getOperand(0).getReg());
1686 return BuildCOPY(ResVReg, InputRegister,
I);
1689 bool IsFloatTy = GR.isScalarOrVectorOfType(InputRegister, SPIRV::OpTypeFloat);
1690 unsigned SpirvNotEqualId =
1691 IsFloatTy ? SPIRV::OpFOrdNotEqual : SPIRV::OpINotEqual;
1692 SPIRVType *SpvBoolScalarTy = GR.getOrCreateSPIRVBoolType(
I,
TII);
1697 NotEqualReg = IsBoolTy ? InputRegister
1698 :
MRI->createVirtualRegister(&SPIRV::iIDRegClass);
1700 SpvBoolTy = GR.getOrCreateSPIRVVectorType(SpvBoolTy, NumElts,
I,
TII);
1706 IsFloatTy ? buildZerosValF(InputType,
I) : buildZerosVal(InputType,
I);
1710 .
addUse(GR.getSPIRVTypeID(SpvBoolTy))
1721 .
addUse(GR.getSPIRVTypeID(SpvBoolScalarTy))
1726bool SPIRVInstructionSelector::selectAll(
Register ResVReg,
1729 return selectAnyOrAll(ResVReg, ResType,
I, SPIRV::OpAll);
1732bool SPIRVInstructionSelector::selectAny(
Register ResVReg,
1735 return selectAnyOrAll(ResVReg, ResType,
I, SPIRV::OpAny);
1739bool SPIRVInstructionSelector::selectFloatDot(
Register ResVReg,
1742 assert(
I.getNumOperands() == 4);
1743 assert(
I.getOperand(2).isReg());
1744 assert(
I.getOperand(3).isReg());
1747 GR.getSPIRVTypeForVReg(
I.getOperand(2).getReg());
1750 GR.getScalarOrVectorComponentCount(VecType) > 1 &&
1751 "dot product requires a vector of at least 2 components");
1754 GR.getSPIRVTypeForVReg(
VecType->getOperand(1).getReg());
1759 return BuildMI(BB,
I,
I.getDebugLoc(),
TII.get(SPIRV::OpDot))
1761 .
addUse(GR.getSPIRVTypeID(ResType))
1762 .
addUse(
I.getOperand(2).getReg())
1763 .
addUse(
I.getOperand(3).getReg())
1767bool SPIRVInstructionSelector::selectIntegerDot(
Register ResVReg,
1771 assert(
I.getNumOperands() == 4);
1772 assert(
I.getOperand(2).isReg());
1773 assert(
I.getOperand(3).isReg());
1776 auto DotOp =
Signed ? SPIRV::OpSDot : SPIRV::OpUDot;
1779 .
addUse(GR.getSPIRVTypeID(ResType))
1780 .
addUse(
I.getOperand(2).getReg())
1781 .
addUse(
I.getOperand(3).getReg())
1787bool SPIRVInstructionSelector::selectIntegerDotExpansion(
1789 assert(
I.getNumOperands() == 4);
1790 assert(
I.getOperand(2).isReg());
1791 assert(
I.getOperand(3).isReg());
1795 Register Vec0 =
I.getOperand(2).getReg();
1796 Register Vec1 =
I.getOperand(3).getReg();
1797 Register TmpVec =
MRI->createVirtualRegister(GR.getRegClass(ResType));
1802 .
addUse(GR.getSPIRVTypeID(VecType))
1808 GR.getScalarOrVectorComponentCount(VecType) > 1 &&
1809 "dot product requires a vector of at least 2 components");
1811 Register Res =
MRI->createVirtualRegister(GR.getRegClass(ResType));
1814 .
addUse(GR.getSPIRVTypeID(ResType))
1819 for (
unsigned i = 1; i < GR.getScalarOrVectorComponentCount(VecType); i++) {
1820 Register Elt =
MRI->createVirtualRegister(GR.getRegClass(ResType));
1823 BuildMI(BB,
I,
I.getDebugLoc(),
TII.get(SPIRV::OpCompositeExtract))
1825 .
addUse(GR.getSPIRVTypeID(ResType))
1830 Register Sum = i < GR.getScalarOrVectorComponentCount(VecType) - 1
1831 ?
MRI->createVirtualRegister(GR.getRegClass(ResType))
1836 .
addUse(GR.getSPIRVTypeID(ResType))
1846template <
bool Signed>
1847bool SPIRVInstructionSelector::selectDot4AddPacked(
Register ResVReg,
1850 assert(
I.getNumOperands() == 5);
1851 assert(
I.getOperand(2).isReg());
1852 assert(
I.getOperand(3).isReg());
1853 assert(
I.getOperand(4).isReg());
1856 auto DotOp =
Signed ? SPIRV::OpSDot : SPIRV::OpUDot;
1857 Register Dot =
MRI->createVirtualRegister(GR.getRegClass(ResType));
1860 .
addUse(GR.getSPIRVTypeID(ResType))
1861 .
addUse(
I.getOperand(2).getReg())
1862 .
addUse(
I.getOperand(3).getReg())
1867 .
addUse(GR.getSPIRVTypeID(ResType))
1869 .
addUse(
I.getOperand(4).getReg())
1876template <
bool Signed>
1877bool SPIRVInstructionSelector::selectDot4AddPackedExpansion(
1879 assert(
I.getNumOperands() == 5);
1880 assert(
I.getOperand(2).isReg());
1881 assert(
I.getOperand(3).isReg());
1882 assert(
I.getOperand(4).isReg());
1888 Register Acc =
I.getOperand(4).getReg();
1889 SPIRVType *EltType = GR.getOrCreateSPIRVIntegerType(8,
I,
TII);
1891 Signed ? SPIRV::OpBitFieldSExtract : SPIRV::OpBitFieldUExtract;
1894 for (
unsigned i = 0; i < 4; i++) {
1896 Register AElt =
MRI->createVirtualRegister(&SPIRV::IDRegClass);
1899 .
addUse(GR.getSPIRVTypeID(ResType))
1900 .
addUse(
I.getOperand(2).getReg())
1901 .
addUse(GR.getOrCreateConstInt(i * 8,
I, EltType,
TII))
1902 .
addUse(GR.getOrCreateConstInt(8,
I, EltType,
TII))
1906 Register BElt =
MRI->createVirtualRegister(&SPIRV::IDRegClass);
1909 .
addUse(GR.getSPIRVTypeID(ResType))
1910 .
addUse(
I.getOperand(3).getReg())
1911 .
addUse(GR.getOrCreateConstInt(i * 8,
I, EltType,
TII))
1912 .
addUse(GR.getOrCreateConstInt(8,
I, EltType,
TII))
1919 .
addUse(GR.getSPIRVTypeID(ResType))
1925 Register MaskMul =
MRI->createVirtualRegister(&SPIRV::IDRegClass);
1928 .
addUse(GR.getSPIRVTypeID(ResType))
1930 .
addUse(GR.getOrCreateConstInt(0,
I, EltType,
TII))
1931 .
addUse(GR.getOrCreateConstInt(8,
I, EltType,
TII))
1936 i < 3 ?
MRI->createVirtualRegister(&SPIRV::IDRegClass) : ResVReg;
1939 .
addUse(GR.getSPIRVTypeID(ResType))
1952bool SPIRVInstructionSelector::selectSaturate(
Register ResVReg,
1955 assert(
I.getNumOperands() == 3);
1956 assert(
I.getOperand(2).isReg());
1958 Register VZero = buildZerosValF(ResType,
I);
1959 Register VOne = buildOnesValF(ResType,
I);
1961 return BuildMI(BB,
I,
I.getDebugLoc(),
TII.get(SPIRV::OpExtInst))
1963 .
addUse(GR.getSPIRVTypeID(ResType))
1964 .
addImm(
static_cast<uint32_t>(SPIRV::InstructionSet::GLSL_std_450))
1966 .
addUse(
I.getOperand(2).getReg())
1972bool SPIRVInstructionSelector::selectSign(
Register ResVReg,
1975 assert(
I.getNumOperands() == 3);
1976 assert(
I.getOperand(2).isReg());
1978 Register InputRegister =
I.getOperand(2).getReg();
1979 SPIRVType *InputType = GR.getSPIRVTypeForVReg(InputRegister);
1980 auto &
DL =
I.getDebugLoc();
1985 bool IsFloatTy = GR.isScalarOrVectorOfType(InputRegister, SPIRV::OpTypeFloat);
1987 unsigned SignBitWidth = GR.getScalarOrVectorBitWidth(InputType);
1988 unsigned ResBitWidth = GR.getScalarOrVectorBitWidth(ResType);
1990 bool NeedsConversion = IsFloatTy || SignBitWidth != ResBitWidth;
1992 auto SignOpcode = IsFloatTy ? GL::FSign : GL::SSign;
1994 ?
MRI->createVirtualRegister(&SPIRV::IDRegClass)
2000 .
addUse(GR.getSPIRVTypeID(InputType))
2001 .
addImm(
static_cast<uint32_t>(SPIRV::InstructionSet::GLSL_std_450))
2006 if (NeedsConversion) {
2007 auto ConvertOpcode = IsFloatTy ? SPIRV::OpConvertFToS : SPIRV::OpSConvert;
2010 .
addUse(GR.getSPIRVTypeID(ResType))
2018bool SPIRVInstructionSelector::selectWaveOpInst(
Register ResVReg,
2021 unsigned Opcode)
const {
2023 SPIRVType *IntTy = GR.getOrCreateSPIRVIntegerType(32,
I,
TII);
2025 auto BMI =
BuildMI(BB,
I,
I.getDebugLoc(),
TII.get(Opcode))
2027 .
addUse(GR.getSPIRVTypeID(ResType))
2028 .
addUse(GR.getOrCreateConstInt(SPIRV::Scope::Subgroup,
I,
2031 for (
unsigned J = 2; J <
I.getNumOperands(); J++) {
2032 BMI.
addUse(
I.getOperand(J).getReg());
2038bool SPIRVInstructionSelector::selectWaveActiveCountBits(
2041 SPIRVType *IntTy = GR.getOrCreateSPIRVIntegerType(32,
I,
TII);
2042 SPIRVType *BallotType = GR.getOrCreateSPIRVVectorType(IntTy, 4,
I,
TII);
2043 Register BallotReg =
MRI->createVirtualRegister(GR.getRegClass(BallotType));
2044 bool Result = selectWaveOpInst(BallotReg, BallotType,
I,
2045 SPIRV::OpGroupNonUniformBallot);
2050 TII.get(SPIRV::OpGroupNonUniformBallotBitCount))
2052 .
addUse(GR.getSPIRVTypeID(ResType))
2053 .
addUse(GR.getOrCreateConstInt(SPIRV::Scope::Subgroup,
I, IntTy,
TII))
2054 .
addImm(SPIRV::GroupOperation::Reduce)
2061bool SPIRVInstructionSelector::selectBitreverse(
Register ResVReg,
2065 return BuildMI(BB,
I,
I.getDebugLoc(),
TII.get(SPIRV::OpBitReverse))
2067 .
addUse(GR.getSPIRVTypeID(ResType))
2068 .
addUse(
I.getOperand(1).getReg())
2072bool SPIRVInstructionSelector::selectFreeze(
Register ResVReg,
2080 if (!
I.getOperand(0).isReg() || !
I.getOperand(1).isReg())
2082 Register OpReg =
I.getOperand(1).getReg();
2085 switch (
Def->getOpcode()) {
2086 case SPIRV::ASSIGN_TYPE:
2088 MRI->getVRegDef(
Def->getOperand(1).getReg())) {
2089 if (AssignToDef->getOpcode() == TargetOpcode::G_IMPLICIT_DEF)
2090 Reg =
Def->getOperand(2).getReg();
2093 case SPIRV::OpUndef:
2094 Reg =
Def->getOperand(1).getReg();
2097 unsigned DestOpCode;
2098 if (
Reg.isValid()) {
2099 DestOpCode = SPIRV::OpConstantNull;
2101 DestOpCode = TargetOpcode::COPY;
2104 return BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
TII.get(DestOpCode))
2105 .
addDef(
I.getOperand(0).getReg())
2118 if (OpDef->
getOpcode() == SPIRV::ASSIGN_TYPE &&
2123 unsigned N = OpDef->
getOpcode() == TargetOpcode::G_CONSTANT
2132 if (OpDef->
getOpcode() == SPIRV::ASSIGN_TYPE &&
2144 case TargetOpcode::G_CONSTANT:
2145 case TargetOpcode::G_FCONSTANT:
2147 case TargetOpcode::G_INTRINSIC:
2148 case TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS:
2149 case TargetOpcode::G_INTRINSIC_CONVERGENT_W_SIDE_EFFECTS:
2150 return cast<GIntrinsic>(*OpDef).getIntrinsicID() ==
2151 Intrinsic::spv_const_composite;
2152 case TargetOpcode::G_BUILD_VECTOR:
2153 case TargetOpcode::G_SPLAT_VECTOR: {
2177bool SPIRVInstructionSelector::selectBuildVector(
Register ResVReg,
2181 if (ResType->
getOpcode() == SPIRV::OpTypeVector)
2182 N = GR.getScalarOrVectorComponentCount(ResType);
2183 else if (ResType->
getOpcode() == SPIRV::OpTypeArray)
2187 if (
I.getNumExplicitOperands() -
I.getNumExplicitDefs() !=
N)
2192 for (
unsigned i =
I.getNumExplicitDefs();
2193 i <
I.getNumExplicitOperands() && IsConst; ++i)
2197 if (!IsConst &&
N < 2)
2199 "There must be at least two constituent operands in a vector");
2201 MRI->setRegClass(ResVReg, GR.getRegClass(ResType));
2202 auto MIB =
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
2203 TII.get(IsConst ? SPIRV::OpConstantComposite
2204 : SPIRV::OpCompositeConstruct))
2206 .
addUse(GR.getSPIRVTypeID(ResType));
2207 for (
unsigned i =
I.getNumExplicitDefs(); i <
I.getNumExplicitOperands(); ++i)
2208 MIB.
addUse(
I.getOperand(i).getReg());
2212bool SPIRVInstructionSelector::selectSplatVector(
Register ResVReg,
2216 if (ResType->
getOpcode() == SPIRV::OpTypeVector)
2217 N = GR.getScalarOrVectorComponentCount(ResType);
2218 else if (ResType->
getOpcode() == SPIRV::OpTypeArray)
2223 unsigned OpIdx =
I.getNumExplicitDefs();
2224 if (!
I.getOperand(OpIdx).isReg())
2228 Register OpReg =
I.getOperand(OpIdx).getReg();
2231 if (!IsConst &&
N < 2)
2233 "There must be at least two constituent operands in a vector");
2235 MRI->setRegClass(ResVReg, GR.getRegClass(ResType));
2236 auto MIB =
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
2237 TII.get(IsConst ? SPIRV::OpConstantComposite
2238 : SPIRV::OpCompositeConstruct))
2240 .
addUse(GR.getSPIRVTypeID(ResType));
2241 for (
unsigned i = 0; i <
N; ++i)
2246bool SPIRVInstructionSelector::selectDiscard(
Register ResVReg,
2252 if (STI.canUseExtension(
2253 SPIRV::Extension::SPV_EXT_demote_to_helper_invocation) ||
2255 Opcode = SPIRV::OpDemoteToHelperInvocation;
2257 Opcode = SPIRV::OpKill;
2260 GR.invalidateMachineInstr(NextI);
2261 NextI->removeFromParent();
2266 return BuildMI(BB,
I,
I.getDebugLoc(),
TII.get(Opcode))
2270bool SPIRVInstructionSelector::selectCmp(
Register ResVReg,
2274 Register Cmp0 =
I.getOperand(2).getReg();
2275 Register Cmp1 =
I.getOperand(3).getReg();
2276 assert(GR.getSPIRVTypeForVReg(Cmp0)->getOpcode() ==
2277 GR.getSPIRVTypeForVReg(Cmp1)->getOpcode() &&
2278 "CMP operands should have the same type");
2279 return BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
TII.get(CmpOpc))
2281 .
addUse(GR.getSPIRVTypeID(ResType))
2287bool SPIRVInstructionSelector::selectICmp(
Register ResVReg,
2290 auto Pred =
I.getOperand(1).getPredicate();
2293 Register CmpOperand =
I.getOperand(2).getReg();
2294 if (GR.isScalarOfType(CmpOperand, SPIRV::OpTypePointer))
2296 else if (GR.isScalarOrVectorOfType(CmpOperand, SPIRV::OpTypeBool))
2300 return selectCmp(ResVReg, ResType, CmpOpc,
I);
2306 assert(
I.getOpcode() == TargetOpcode::G_FCONSTANT && OpIdx == -1 &&
2307 "Expected G_FCONSTANT");
2308 const ConstantFP *FPImm =
I.getOperand(1).getFPImm();
2315 assert(
I.getOpcode() == TargetOpcode::G_CONSTANT && OpIdx == -1 &&
2316 "Expected G_CONSTANT");
2317 addNumImm(
I.getOperand(1).getCImm()->getValue(), MIB);
2320std::pair<Register, bool>
2325 ResType ? ResType : GR.getOrCreateSPIRVIntegerType(32,
I,
TII);
2327 auto ConstInt = ConstantInt::get(LLVMTy, Val);
2328 Register NewReg = GR.find(ConstInt, GR.CurMF);
2332 GR.add(ConstInt, GR.CurMF, NewReg);
2336 MI =
BuildMI(BB,
I,
I.getDebugLoc(),
TII.get(SPIRV::OpConstantNull))
2338 .
addUse(GR.getSPIRVTypeID(SpvI32Ty));
2340 MI =
BuildMI(BB,
I,
I.getDebugLoc(),
TII.get(SPIRV::OpConstantI))
2342 .
addUse(GR.getSPIRVTypeID(SpvI32Ty))
2350bool SPIRVInstructionSelector::selectFCmp(
Register ResVReg,
2354 return selectCmp(ResVReg, ResType, CmpOp,
I);
2360 bool ZeroAsNull = STI.isOpenCLEnv();
2361 if (ResType->
getOpcode() == SPIRV::OpTypeVector)
2362 return GR.getOrCreateConstVector(0UL,
I, ResType,
TII, ZeroAsNull);
2363 return GR.getOrCreateConstInt(0,
I, ResType,
TII, ZeroAsNull);
2369 bool ZeroAsNull = STI.isOpenCLEnv();
2371 if (ResType->
getOpcode() == SPIRV::OpTypeVector)
2372 return GR.getOrCreateConstVector(VZero,
I, ResType,
TII, ZeroAsNull);
2373 return GR.getOrCreateConstFP(VZero,
I, ResType,
TII, ZeroAsNull);
2379 bool ZeroAsNull = STI.isOpenCLEnv();
2381 if (ResType->
getOpcode() == SPIRV::OpTypeVector)
2382 return GR.getOrCreateConstVector(VOne,
I, ResType,
TII, ZeroAsNull);
2383 return GR.getOrCreateConstFP(VOne,
I, ResType,
TII, ZeroAsNull);
2389 unsigned BitWidth = GR.getScalarOrVectorBitWidth(ResType);
2392 if (ResType->
getOpcode() == SPIRV::OpTypeVector)
2397bool SPIRVInstructionSelector::selectSelect(
Register ResVReg,
2400 bool IsSigned)
const {
2402 Register ZeroReg = buildZerosVal(ResType,
I);
2403 Register OneReg = buildOnesVal(IsSigned, ResType,
I);
2405 GR.isScalarOfType(
I.getOperand(1).getReg(), SPIRV::OpTypeBool);
2407 IsScalarBool ? SPIRV::OpSelectSISCond : SPIRV::OpSelectVIVCond;
2408 return BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
TII.get(Opcode))
2410 .
addUse(GR.getSPIRVTypeID(ResType))
2411 .
addUse(
I.getOperand(1).getReg())
2417bool SPIRVInstructionSelector::selectIToF(
Register ResVReg,
2420 unsigned Opcode)
const {
2421 Register SrcReg =
I.getOperand(1).getReg();
2424 if (GR.isScalarOrVectorOfType(
I.getOperand(1).getReg(), SPIRV::OpTypeBool)) {
2425 unsigned BitWidth = GR.getScalarOrVectorBitWidth(ResType);
2427 if (ResType->
getOpcode() == SPIRV::OpTypeVector) {
2429 TmpType = GR.getOrCreateSPIRVVectorType(TmpType, NumElts,
I,
TII);
2431 SrcReg =
MRI->createVirtualRegister(&SPIRV::iIDRegClass);
2432 selectSelect(SrcReg, TmpType,
I,
false);
2434 return selectOpWithSrcs(ResVReg, ResType,
I, {SrcReg}, Opcode);
2437bool SPIRVInstructionSelector::selectExt(
Register ResVReg,
2440 Register SrcReg =
I.getOperand(1).getReg();
2441 if (GR.isScalarOrVectorOfType(SrcReg, SPIRV::OpTypeBool))
2442 return selectSelect(ResVReg, ResType,
I, IsSigned);
2444 SPIRVType *SrcType = GR.getSPIRVTypeForVReg(SrcReg);
2445 if (SrcType == ResType)
2446 return BuildCOPY(ResVReg, SrcReg,
I);
2448 unsigned Opcode = IsSigned ? SPIRV::OpSConvert : SPIRV::OpUConvert;
2449 return selectUnOp(ResVReg, ResType,
I, Opcode);
2452bool SPIRVInstructionSelector::selectSUCmp(
Register ResVReg,
2455 bool IsSigned)
const {
2461 unsigned N = GR.getScalarOrVectorComponentCount(ResType);
2463 BoolType = GR.getOrCreateSPIRVVectorType(BoolType,
N,
I,
TII);
2464 Register BoolTypeReg = GR.getSPIRVTypeID(BoolType);
2468 Register IsLessEqReg =
MRI->createVirtualRegister(GR.getRegClass(ResType));
2470 GR.assignSPIRVTypeToVReg(ResType, IsLessEqReg, MIRBuilder.getMF());
2472 TII.get(IsSigned ? SPIRV::OpSLessThanEqual
2473 : SPIRV::OpULessThanEqual))
2476 .
addUse(
I.getOperand(1).getReg())
2477 .
addUse(
I.getOperand(2).getReg())
2479 Register IsLessReg =
MRI->createVirtualRegister(GR.getRegClass(ResType));
2481 GR.assignSPIRVTypeToVReg(ResType, IsLessReg, MIRBuilder.getMF());
2483 TII.get(IsSigned ? SPIRV::OpSLessThan : SPIRV::OpULessThan))
2486 .
addUse(
I.getOperand(1).getReg())
2487 .
addUse(
I.getOperand(2).getReg())
2490 Register ResTypeReg = GR.getSPIRVTypeID(ResType);
2492 MRI->createVirtualRegister(GR.getRegClass(ResType));
2494 GR.assignSPIRVTypeToVReg(ResType, NegOneOrZeroReg, MIRBuilder.getMF());
2495 unsigned SelectOpcode =
2496 N > 1 ? SPIRV::OpSelectVIVCond : SPIRV::OpSelectSISCond;
2501 .
addUse(buildOnesVal(
true, ResType,
I))
2502 .
addUse(buildZerosVal(ResType,
I))
2509 .
addUse(buildOnesVal(
false, ResType,
I))
2513bool SPIRVInstructionSelector::selectIntToBool(
Register IntReg,
2519 Register BitIntReg =
MRI->createVirtualRegister(&SPIRV::iIDRegClass);
2520 bool IsVectorTy = IntTy->
getOpcode() == SPIRV::OpTypeVector;
2521 unsigned Opcode = IsVectorTy ? SPIRV::OpBitwiseAndV : SPIRV::OpBitwiseAndS;
2523 Register One = buildOnesVal(
false, IntTy,
I);
2527 .
addUse(GR.getSPIRVTypeID(IntTy))
2533 .
addUse(GR.getSPIRVTypeID(BoolTy))
2539bool SPIRVInstructionSelector::selectTrunc(
Register ResVReg,
2542 Register IntReg =
I.getOperand(1).getReg();
2543 const SPIRVType *ArgType = GR.getSPIRVTypeForVReg(IntReg);
2544 if (GR.isScalarOrVectorOfType(ResVReg, SPIRV::OpTypeBool))
2545 return selectIntToBool(IntReg, ResVReg,
I, ArgType, ResType);
2546 if (ArgType == ResType)
2547 return BuildCOPY(ResVReg, IntReg,
I);
2548 bool IsSigned = GR.isScalarOrVectorSigned(ResType);
2549 unsigned Opcode = IsSigned ? SPIRV::OpSConvert : SPIRV::OpUConvert;
2550 return selectUnOp(ResVReg, ResType,
I, Opcode);
2553bool SPIRVInstructionSelector::selectConst(
Register ResVReg,
2557 unsigned TyOpcode = ResType->
getOpcode();
2558 assert(TyOpcode != SPIRV::OpTypePointer ||
Imm.isZero());
2560 if ((TyOpcode == SPIRV::OpTypePointer || TyOpcode == SPIRV::OpTypeEvent) &&
2562 return BuildMI(BB,
I,
I.getDebugLoc(),
TII.get(SPIRV::OpConstantNull))
2564 .
addUse(GR.getSPIRVTypeID(ResType))
2566 if (TyOpcode == SPIRV::OpTypeInt) {
2567 assert(
Imm.getBitWidth() <= 64 &&
"Unsupported integer width!");
2569 return Reg == ResVReg ?
true : BuildCOPY(ResVReg, Reg,
I);
2571 auto MIB =
BuildMI(BB,
I,
I.getDebugLoc(),
TII.get(SPIRV::OpConstantI))
2573 .
addUse(GR.getSPIRVTypeID(ResType));
2580bool SPIRVInstructionSelector::selectOpUndef(
Register ResVReg,
2583 return BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
TII.get(SPIRV::OpUndef))
2585 .
addUse(GR.getSPIRVTypeID(ResType))
2592 if (TypeInst->
getOpcode() == SPIRV::ASSIGN_TYPE) {
2595 return ImmInst->
getOpcode() == TargetOpcode::G_CONSTANT;
2597 return TypeInst->
getOpcode() == SPIRV::OpConstantI;
2602 if (TypeInst->
getOpcode() == SPIRV::OpConstantI)
2609bool SPIRVInstructionSelector::selectInsertVal(
Register ResVReg,
2613 auto MIB =
BuildMI(BB,
I,
I.getDebugLoc(),
TII.get(SPIRV::OpCompositeInsert))
2615 .
addUse(GR.getSPIRVTypeID(ResType))
2617 .
addUse(
I.getOperand(3).getReg())
2619 .
addUse(
I.getOperand(2).getReg());
2620 for (
unsigned i = 4; i <
I.getNumOperands(); i++)
2625bool SPIRVInstructionSelector::selectExtractVal(
Register ResVReg,
2629 auto MIB =
BuildMI(BB,
I,
I.getDebugLoc(),
TII.get(SPIRV::OpCompositeExtract))
2631 .
addUse(GR.getSPIRVTypeID(ResType))
2632 .
addUse(
I.getOperand(2).getReg());
2633 for (
unsigned i = 3; i <
I.getNumOperands(); i++)
2638bool SPIRVInstructionSelector::selectInsertElt(
Register ResVReg,
2642 return selectInsertVal(ResVReg, ResType,
I);
2644 return BuildMI(BB,
I,
I.getDebugLoc(),
TII.get(SPIRV::OpVectorInsertDynamic))
2646 .
addUse(GR.getSPIRVTypeID(ResType))
2647 .
addUse(
I.getOperand(2).getReg())
2648 .
addUse(
I.getOperand(3).getReg())
2649 .
addUse(
I.getOperand(4).getReg())
2653bool SPIRVInstructionSelector::selectExtractElt(
Register ResVReg,
2657 return selectExtractVal(ResVReg, ResType,
I);
2659 return BuildMI(BB,
I,
I.getDebugLoc(),
TII.get(SPIRV::OpVectorExtractDynamic))
2661 .
addUse(GR.getSPIRVTypeID(ResType))
2662 .
addUse(
I.getOperand(2).getReg())
2663 .
addUse(
I.getOperand(3).getReg())
2667bool SPIRVInstructionSelector::selectGEP(
Register ResVReg,
2670 const bool IsGEPInBounds =
I.getOperand(2).getImm();
2675 const unsigned Opcode = STI.isVulkanEnv()
2676 ? (IsGEPInBounds ? SPIRV::OpInBoundsAccessChain
2677 : SPIRV::OpAccessChain)
2678 : (IsGEPInBounds ? SPIRV::OpInBoundsPtrAccessChain
2679 : SPIRV::OpPtrAccessChain);
2681 auto Res =
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
TII.get(Opcode))
2683 .
addUse(GR.getSPIRVTypeID(ResType))
2685 .
addUse(
I.getOperand(3).getReg());
2687 const unsigned StartingIndex =
2688 (Opcode == SPIRV::OpAccessChain || Opcode == SPIRV::OpInBoundsAccessChain)
2691 for (
unsigned i = StartingIndex; i <
I.getNumExplicitOperands(); ++i)
2692 Res.addUse(
I.getOperand(i).getReg());
2693 return Res.constrainAllUses(
TII,
TRI, RBI);
2697bool SPIRVInstructionSelector::wrapIntoSpecConstantOp(
2700 unsigned Lim =
I.getNumExplicitOperands();
2701 for (
unsigned i =
I.getNumExplicitDefs() + 1; i < Lim; ++i) {
2702 Register OpReg =
I.getOperand(i).getReg();
2704 SPIRVType *OpType = GR.getSPIRVTypeForVReg(OpReg);
2706 if (!OpDefine || !OpType ||
isConstReg(
MRI, OpDefine, Visited) ||
2707 OpDefine->
getOpcode() == TargetOpcode::G_ADDRSPACE_CAST ||
2708 GR.isAggregateType(OpType)) {
2715 Register WrapReg = GR.find(OpDefine, MF);
2721 WrapReg =
MRI->createVirtualRegister(GR.getRegClass(OpType));
2722 GR.add(OpDefine, MF, WrapReg);
2726 GR.assignSPIRVTypeToVReg(OpType, WrapReg, *MF);
2730 .
addUse(GR.getSPIRVTypeID(OpType))
2740bool SPIRVInstructionSelector::selectIntrinsic(
Register ResVReg,
2746 case Intrinsic::spv_load:
2747 return selectLoad(ResVReg, ResType,
I);
2748 case Intrinsic::spv_store:
2749 return selectStore(
I);
2750 case Intrinsic::spv_extractv:
2751 return selectExtractVal(ResVReg, ResType,
I);
2752 case Intrinsic::spv_insertv:
2753 return selectInsertVal(ResVReg, ResType,
I);
2754 case Intrinsic::spv_extractelt:
2755 return selectExtractElt(ResVReg, ResType,
I);
2756 case Intrinsic::spv_insertelt:
2757 return selectInsertElt(ResVReg, ResType,
I);
2758 case Intrinsic::spv_gep:
2759 return selectGEP(ResVReg, ResType,
I);
2760 case Intrinsic::spv_unref_global:
2761 case Intrinsic::spv_init_global: {
2764 ?
MRI->getVRegDef(
I.getOperand(2).getReg())
2767 return selectGlobalValue(
MI->getOperand(0).getReg(), *
MI,
Init);
2769 case Intrinsic::spv_undef: {
2770 auto MIB =
BuildMI(BB,
I,
I.getDebugLoc(),
TII.get(SPIRV::OpUndef))
2772 .
addUse(GR.getSPIRVTypeID(ResType));
2775 case Intrinsic::spv_const_composite: {
2777 bool IsNull =
I.getNumExplicitDefs() + 1 ==
I.getNumExplicitOperands();
2779 unsigned Opcode = SPIRV::OpConstantNull;
2782 Opcode = SPIRV::OpConstantComposite;
2783 if (!wrapIntoSpecConstantOp(
I, CompositeArgs))
2786 MRI->setRegClass(ResVReg, GR.getRegClass(ResType));
2787 auto MIB =
BuildMI(BB,
I,
I.getDebugLoc(),
TII.get(Opcode))
2789 .
addUse(GR.getSPIRVTypeID(ResType));
2792 for (
Register OpReg : CompositeArgs)
2797 case Intrinsic::spv_assign_name: {
2798 auto MIB =
BuildMI(BB,
I,
I.getDebugLoc(),
TII.get(SPIRV::OpName));
2799 MIB.
addUse(
I.getOperand(
I.getNumExplicitDefs() + 1).getReg());
2800 for (
unsigned i =
I.getNumExplicitDefs() + 2;
2801 i <
I.getNumExplicitOperands(); ++i) {
2802 MIB.
addImm(
I.getOperand(i).getImm());
2806 case Intrinsic::spv_switch: {
2807 auto MIB =
BuildMI(BB,
I,
I.getDebugLoc(),
TII.get(SPIRV::OpSwitch));
2808 for (
unsigned i = 1; i <
I.getNumExplicitOperands(); ++i) {
2809 if (
I.getOperand(i).isReg())
2810 MIB.
addReg(
I.getOperand(i).getReg());
2811 else if (
I.getOperand(i).isCImm())
2812 addNumImm(
I.getOperand(i).getCImm()->getValue(), MIB);
2813 else if (
I.getOperand(i).isMBB())
2814 MIB.
addMBB(
I.getOperand(i).getMBB());
2820 case Intrinsic::spv_loop_merge:
2821 case Intrinsic::spv_selection_merge: {
2822 const auto Opcode = IID == Intrinsic::spv_selection_merge
2823 ? SPIRV::OpSelectionMerge
2824 : SPIRV::OpLoopMerge;
2825 auto MIB =
BuildMI(BB,
I,
I.getDebugLoc(),
TII.get(Opcode));
2826 for (
unsigned i = 1; i <
I.getNumExplicitOperands(); ++i) {
2827 assert(
I.getOperand(i).isMBB());
2828 MIB.
addMBB(
I.getOperand(i).getMBB());
2830 MIB.
addImm(SPIRV::SelectionControl::None);
2833 case Intrinsic::spv_cmpxchg:
2834 return selectAtomicCmpXchg(ResVReg, ResType,
I);
2835 case Intrinsic::spv_unreachable:
2836 return BuildMI(BB,
I,
I.getDebugLoc(),
TII.get(SPIRV::OpUnreachable))
2838 case Intrinsic::spv_alloca:
2839 return selectFrameIndex(ResVReg, ResType,
I);
2840 case Intrinsic::spv_alloca_array:
2841 return selectAllocaArray(ResVReg, ResType,
I);
2842 case Intrinsic::spv_assume:
2843 if (STI.canUseExtension(SPIRV::Extension::SPV_KHR_expect_assume))
2844 return BuildMI(BB,
I,
I.getDebugLoc(),
TII.get(SPIRV::OpAssumeTrueKHR))
2845 .
addUse(
I.getOperand(1).getReg())
2848 case Intrinsic::spv_expect:
2849 if (STI.canUseExtension(SPIRV::Extension::SPV_KHR_expect_assume))
2850 return BuildMI(BB,
I,
I.getDebugLoc(),
TII.get(SPIRV::OpExpectKHR))
2852 .
addUse(GR.getSPIRVTypeID(ResType))
2853 .
addUse(
I.getOperand(2).getReg())
2854 .
addUse(
I.getOperand(3).getReg())
2857 case Intrinsic::arithmetic_fence:
2858 if (STI.canUseExtension(SPIRV::Extension::SPV_EXT_arithmetic_fence))
2860 TII.get(SPIRV::OpArithmeticFenceEXT))
2862 .
addUse(GR.getSPIRVTypeID(ResType))
2863 .
addUse(
I.getOperand(2).getReg())
2866 return BuildCOPY(ResVReg,
I.getOperand(2).getReg(),
I);
2868 case Intrinsic::spv_thread_id:
2874 return loadVec3BuiltinInputID(SPIRV::BuiltIn::GlobalInvocationId, ResVReg,
2876 case Intrinsic::spv_thread_id_in_group:
2882 return loadVec3BuiltinInputID(SPIRV::BuiltIn::LocalInvocationId, ResVReg,
2884 case Intrinsic::spv_fdot:
2885 return selectFloatDot(ResVReg, ResType,
I);
2886 case Intrinsic::spv_udot:
2887 case Intrinsic::spv_sdot:
2888 if (STI.canUseExtension(SPIRV::Extension::SPV_KHR_integer_dot_product) ||
2890 return selectIntegerDot(ResVReg, ResType,
I,
2891 IID == Intrinsic::spv_sdot);
2892 return selectIntegerDotExpansion(ResVReg, ResType,
I);
2893 case Intrinsic::spv_dot4add_i8packed:
2894 if (STI.canUseExtension(SPIRV::Extension::SPV_KHR_integer_dot_product) ||
2896 return selectDot4AddPacked<true>(ResVReg, ResType,
I);
2897 return selectDot4AddPackedExpansion<true>(ResVReg, ResType,
I);
2898 case Intrinsic::spv_dot4add_u8packed:
2899 if (STI.canUseExtension(SPIRV::Extension::SPV_KHR_integer_dot_product) ||
2901 return selectDot4AddPacked<false>(ResVReg, ResType,
I);
2902 return selectDot4AddPackedExpansion<false>(ResVReg, ResType,
I);
2903 case Intrinsic::spv_all:
2904 return selectAll(ResVReg, ResType,
I);
2905 case Intrinsic::spv_any:
2906 return selectAny(ResVReg, ResType,
I);
2907 case Intrinsic::spv_cross:
2908 return selectExtInst(ResVReg, ResType,
I, CL::cross, GL::Cross);
2909 case Intrinsic::spv_lerp:
2910 return selectExtInst(ResVReg, ResType,
I, CL::mix, GL::FMix);
2911 case Intrinsic::spv_length:
2912 return selectExtInst(ResVReg, ResType,
I, CL::length, GL::Length);
2913 case Intrinsic::spv_degrees:
2914 return selectExtInst(ResVReg, ResType,
I, CL::degrees, GL::Degrees);
2915 case Intrinsic::spv_frac:
2916 return selectExtInst(ResVReg, ResType,
I, CL::fract, GL::Fract);
2917 case Intrinsic::spv_normalize:
2918 return selectExtInst(ResVReg, ResType,
I, CL::normalize, GL::Normalize);
2919 case Intrinsic::spv_rsqrt:
2920 return selectExtInst(ResVReg, ResType,
I, CL::rsqrt, GL::InverseSqrt);
2921 case Intrinsic::spv_sign:
2922 return selectSign(ResVReg, ResType,
I);
2923 case Intrinsic::spv_firstbituhigh:
2924 return selectFirstBitHigh(ResVReg, ResType,
I,
false);
2925 case Intrinsic::spv_firstbitshigh:
2926 return selectFirstBitHigh(ResVReg, ResType,
I,
true);
2927 case Intrinsic::spv_group_memory_barrier_with_group_sync: {
2929 auto MemSemConstant =
2930 buildI32Constant(SPIRV::MemorySemantics::SequentiallyConsistent,
I);
2931 Register MemSemReg = MemSemConstant.first;
2932 Result &= MemSemConstant.second;
2933 auto ScopeConstant = buildI32Constant(SPIRV::Scope::Workgroup,
I);
2934 Register ScopeReg = ScopeConstant.first;
2935 Result &= ScopeConstant.second;
2938 BuildMI(BB,
I,
I.getDebugLoc(),
TII.get(SPIRV::OpControlBarrier))
2944 case Intrinsic::spv_lifetime_start:
2945 case Intrinsic::spv_lifetime_end: {
2946 unsigned Op = IID == Intrinsic::spv_lifetime_start ? SPIRV::OpLifetimeStart
2947 : SPIRV::OpLifetimeStop;
2948 int64_t
Size =
I.getOperand(
I.getNumExplicitDefs() + 1).getImm();
2949 Register PtrReg =
I.getOperand(
I.getNumExplicitDefs() + 2).getReg();
2957 case Intrinsic::spv_saturate:
2958 return selectSaturate(ResVReg, ResType,
I);
2959 case Intrinsic::spv_nclamp:
2960 return selectExtInst(ResVReg, ResType,
I, CL::fclamp, GL::NClamp);
2961 case Intrinsic::spv_uclamp:
2962 return selectExtInst(ResVReg, ResType,
I, CL::u_clamp, GL::UClamp);
2963 case Intrinsic::spv_sclamp:
2964 return selectExtInst(ResVReg, ResType,
I, CL::s_clamp, GL::SClamp);
2965 case Intrinsic::spv_wave_active_countbits:
2966 return selectWaveActiveCountBits(ResVReg, ResType,
I);
2967 case Intrinsic::spv_wave_all:
2968 return selectWaveOpInst(ResVReg, ResType,
I, SPIRV::OpGroupNonUniformAll);
2969 case Intrinsic::spv_wave_any:
2970 return selectWaveOpInst(ResVReg, ResType,
I, SPIRV::OpGroupNonUniformAny);
2971 case Intrinsic::spv_wave_is_first_lane:
2972 return selectWaveOpInst(ResVReg, ResType,
I, SPIRV::OpGroupNonUniformElect);
2973 case Intrinsic::spv_wave_readlane:
2974 return selectWaveOpInst(ResVReg, ResType,
I,
2975 SPIRV::OpGroupNonUniformShuffle);
2976 case Intrinsic::spv_step:
2977 return selectExtInst(ResVReg, ResType,
I, CL::step, GL::Step);
2978 case Intrinsic::spv_radians:
2979 return selectExtInst(ResVReg, ResType,
I, CL::radians, GL::Radians);
2983 case Intrinsic::instrprof_increment:
2984 case Intrinsic::instrprof_increment_step:
2985 case Intrinsic::instrprof_value_profile:
2988 case Intrinsic::spv_value_md:
2990 case Intrinsic::spv_resource_handlefrombinding: {
2991 return selectHandleFromBinding(ResVReg, ResType,
I);
2993 case Intrinsic::spv_resource_store_typedbuffer: {
2994 selectImageWriteIntrinsic(
I);
2997 case Intrinsic::spv_resource_load_typedbuffer: {
2998 selectReadImageIntrinsic(ResVReg, ResType,
I);
3001 case Intrinsic::spv_discard: {
3002 return selectDiscard(ResVReg, ResType,
I);
3005 std::string DiagMsg;
3008 DiagMsg =
"Intrinsic selection not implemented: " + DiagMsg;
3015bool SPIRVInstructionSelector::selectHandleFromBinding(
Register &ResVReg,
3022 Register IndexReg =
I.getOperand(5).getReg();
3023 bool IsNonUniform = ArraySize > 1 &&
foldImm(
I.getOperand(6),
MRI);
3026 Register VarReg = buildPointerToResource(ResType, Set, Binding, ArraySize,
3027 IndexReg, IsNonUniform, MIRBuilder);
3034 return BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
TII.get(SPIRV::OpLoad))
3036 .
addUse(GR.getSPIRVTypeID(ResType))
3041void SPIRVInstructionSelector::selectReadImageIntrinsic(
3050 Register ImageReg =
I.getOperand(2).getReg();
3051 assert(
MRI->getVRegDef(ImageReg)->getParent() ==
I.getParent() &&
3052 "The image must be loaded in the same basic block as its use.");
3054 uint64_t ResultSize = GR.getScalarOrVectorComponentCount(ResType);
3055 if (ResultSize == 4) {
3056 BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
TII.get(SPIRV::OpImageRead))
3058 .
addUse(GR.getSPIRVTypeID(ResType))
3060 .
addUse(
I.getOperand(3).getReg());
3064 SPIRVType *ReadType = widenTypeToVec4(ResType,
I);
3065 Register ReadReg =
MRI->createVirtualRegister(GR.getRegClass(ReadType));
3066 BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
TII.get(SPIRV::OpImageRead))
3068 .
addUse(GR.getSPIRVTypeID(ReadType))
3070 .
addUse(
I.getOperand(3).getReg());
3072 if (ResultSize == 1) {
3074 TII.get(SPIRV::OpCompositeExtract))
3076 .
addUse(GR.getSPIRVTypeID(ResType))
3081 extractSubvector(ResVReg, ResType, ReadReg,
I);
3084void SPIRVInstructionSelector::extractSubvector(
3087 SPIRVType *InputType = GR.getResultType(ReadReg);
3088 [[maybe_unused]]
uint64_t InputSize =
3089 GR.getScalarOrVectorComponentCount(InputType);
3090 uint64_t ResultSize = GR.getScalarOrVectorComponentCount(ResType);
3091 assert(InputSize > 1 &&
"The input must be a vector.");
3092 assert(ResultSize > 1 &&
"The result must be a vector.");
3093 assert(ResultSize < InputSize &&
3094 "Cannot extract more element than there are in the input.");
3096 SPIRVType *ScalarType = GR.getScalarOrVectorComponentType(ResType);
3099 Register ComponentReg =
MRI->createVirtualRegister(ScalarRegClass);
3111 TII.get(SPIRV::OpCompositeConstruct))
3113 .
addUse(GR.getSPIRVTypeID(ResType));
3115 for (
Register ComponentReg : ComponentRegisters)
3116 MIB.
addUse(ComponentReg);
3119void SPIRVInstructionSelector::selectImageWriteIntrinsic(
3127 Register ImageReg =
I.getOperand(1).getReg();
3128 assert(
MRI->getVRegDef(ImageReg)->getParent() ==
I.getParent() &&
3129 "The image must be loaded in the same basic block as its use.");
3130 Register CoordinateReg =
I.getOperand(2).getReg();
3131 Register DataReg =
I.getOperand(3).getReg();
3132 assert(GR.getResultType(DataReg)->getOpcode() == SPIRV::OpTypeVector);
3133 assert(GR.getScalarOrVectorComponentCount(GR.getResultType(DataReg)) == 4);
3134 BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
TII.get(SPIRV::OpImageWrite))
3140Register SPIRVInstructionSelector::buildPointerToResource(
3145 return GR.getOrCreateGlobalVariableWithBinding(ResType, Set, Binding,
3148 const SPIRVType *VarType = GR.getOrCreateSPIRVArrayType(
3150 Register VarReg = GR.getOrCreateGlobalVariableWithBinding(
3151 VarType, Set, Binding, MIRBuilder);
3153 SPIRVType *ResPointerType = GR.getOrCreateSPIRVPointerType(
3154 ResType, MIRBuilder, SPIRV::StorageClass::UniformConstant);
3156 Register AcReg =
MRI->createVirtualRegister(&SPIRV::iIDRegClass);
3160 buildOpDecorate(IndexReg, MIRBuilder, SPIRV::Decoration::NonUniformEXT, {});
3161 buildOpDecorate(AcReg, MIRBuilder, SPIRV::Decoration::NonUniformEXT, {});
3166 .
addUse(GR.getSPIRVTypeID(ResPointerType))
3173bool SPIRVInstructionSelector::selectFirstBitHigh16(
Register ResVReg,
3176 bool IsSigned)
const {
3177 unsigned Opcode = IsSigned ? SPIRV::OpSConvert : SPIRV::OpUConvert;
3179 Register ExtReg =
MRI->createVirtualRegister(GR.getRegClass(ResType));
3181 selectOpWithSrcs(ExtReg, ResType,
I, {
I.getOperand(2).
getReg()}, Opcode);
3182 return Result && selectFirstBitHigh32(ResVReg, ResType,
I, ExtReg, IsSigned);
3185bool SPIRVInstructionSelector::selectFirstBitHigh32(
Register ResVReg,
3189 bool IsSigned)
const {
3190 unsigned Opcode = IsSigned ? GL::FindSMsb : GL::FindUMsb;
3191 return BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
TII.get(SPIRV::OpExtInst))
3193 .
addUse(GR.getSPIRVTypeID(ResType))
3194 .
addImm(
static_cast<uint32_t>(SPIRV::InstructionSet::GLSL_std_450))
3200bool SPIRVInstructionSelector::selectFirstBitHigh64(
Register ResVReg,
3203 bool IsSigned)
const {
3204 Register OpReg =
I.getOperand(2).getReg();
3206 unsigned count = GR.getScalarOrVectorComponentCount(ResType);
3207 SPIRVType *baseType = GR.retrieveScalarOrVectorIntType(ResType);
3210 GR.getOrCreateSPIRVVectorType(baseType, 2 *
count, MIRBuilder);
3211 Register bitcastReg =
MRI->createVirtualRegister(GR.getRegClass(postCastT));
3213 selectOpWithSrcs(bitcastReg, postCastT,
I, {OpReg}, SPIRV::OpBitcast);
3216 Register FBHReg =
MRI->createVirtualRegister(GR.getRegClass(postCastT));
3217 Result &= selectFirstBitHigh32(FBHReg, postCastT,
I, bitcastReg, IsSigned);
3220 Register HighReg =
MRI->createVirtualRegister(GR.getRegClass(ResType));
3221 Register LowReg =
MRI->createVirtualRegister(GR.getRegClass(ResType));
3223 bool ZeroAsNull = STI.isOpenCLEnv();
3224 bool isScalarRes = ResType->
getOpcode() != SPIRV::OpTypeVector;
3227 Result &= selectOpWithSrcs(
3228 HighReg, ResType,
I,
3229 {FBHReg, GR.getOrCreateConstInt(0,
I, ResType,
TII, ZeroAsNull)},
3230 SPIRV::OpVectorExtractDynamic);
3231 Result &= selectOpWithSrcs(
3233 {FBHReg, GR.getOrCreateConstInt(1,
I, ResType,
TII, ZeroAsNull)},
3234 SPIRV::OpVectorExtractDynamic);
3236 auto MIB =
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
3237 TII.get(SPIRV::OpVectorShuffle))
3239 .
addUse(GR.getSPIRVTypeID(ResType))
3244 for (j = 0;
j <
count * 2;
j += 2) {
3250 MIB =
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
3251 TII.get(SPIRV::OpVectorShuffle))
3253 .
addUse(GR.getSPIRVTypeID(ResType))
3257 for (j = 1;
j <
count * 2;
j += 2) {
3272 GR.getOrCreateConstInt((
unsigned)-1,
I, ResType,
TII, ZeroAsNull);
3273 Reg0 = GR.getOrCreateConstInt(0,
I, ResType,
TII, ZeroAsNull);
3274 Reg32 = GR.getOrCreateConstInt(32,
I, ResType,
TII, ZeroAsNull);
3275 selectOp = SPIRV::OpSelectSISCond;
3276 addOp = SPIRV::OpIAddS;
3278 BoolType = GR.getOrCreateSPIRVVectorType(BoolType,
count, MIRBuilder);
3280 GR.getOrCreateConstVector((
unsigned)-1,
I, ResType,
TII, ZeroAsNull);
3281 Reg0 = GR.getOrCreateConstVector(0,
I, ResType,
TII, ZeroAsNull);
3282 Reg32 = GR.getOrCreateConstVector(32,
I, ResType,
TII, ZeroAsNull);
3283 selectOp = SPIRV::OpSelectVIVCond;
3284 addOp = SPIRV::OpIAddV;
3288 Register BReg =
MRI->createVirtualRegister(GR.getRegClass(BoolType));
3289 Result &= selectOpWithSrcs(BReg, BoolType,
I, {HighReg, NegOneReg},
3293 Register TmpReg =
MRI->createVirtualRegister(GR.getRegClass(ResType));
3295 selectOpWithSrcs(TmpReg, ResType,
I, {BReg, LowReg, HighReg}, selectOp);
3298 Register ValReg =
MRI->createVirtualRegister(GR.getRegClass(ResType));
3299 Result &= selectOpWithSrcs(ValReg, ResType,
I, {BReg, Reg0, Reg32}, selectOp);
3302 selectOpWithSrcs(ResVReg, ResType,
I, {ValReg, TmpReg}, addOp);
3305bool SPIRVInstructionSelector::selectFirstBitHigh(
Register ResVReg,
3308 bool IsSigned)
const {
3310 Register OpReg =
I.getOperand(2).getReg();
3311 SPIRVType *OpType = GR.getSPIRVTypeForVReg(OpReg);
3313 switch (GR.getScalarOrVectorBitWidth(OpType)) {
3315 return selectFirstBitHigh16(ResVReg, ResType,
I, IsSigned);
3317 return selectFirstBitHigh32(ResVReg, ResType,
I, OpReg, IsSigned);
3319 return selectFirstBitHigh64(ResVReg, ResType,
I, IsSigned);
3322 "spv_firstbituhigh and spv_firstbitshigh only support 16,32,64 bits.");
3326bool SPIRVInstructionSelector::selectAllocaArray(
Register ResVReg,
3332 bool Res =
BuildMI(BB,
I,
I.getDebugLoc(),
3333 TII.get(SPIRV::OpVariableLengthArrayINTEL))
3335 .
addUse(GR.getSPIRVTypeID(ResType))
3336 .
addUse(
I.getOperand(2).getReg())
3338 if (!STI.isVulkanEnv()) {
3339 unsigned Alignment =
I.getOperand(3).getImm();
3345bool SPIRVInstructionSelector::selectFrameIndex(
Register ResVReg,
3351 bool Res =
BuildMI(*It->getParent(), It, It->getDebugLoc(),
3352 TII.get(SPIRV::OpVariable))
3354 .
addUse(GR.getSPIRVTypeID(ResType))
3357 if (!STI.isVulkanEnv()) {
3358 unsigned Alignment =
I.getOperand(2).getImm();
3365bool SPIRVInstructionSelector::selectBranch(
MachineInstr &
I)
const {
3372 if (PrevI !=
nullptr && PrevI->
getOpcode() == TargetOpcode::G_BRCOND) {
3373 return BuildMI(
MBB,
I,
I.getDebugLoc(),
TII.get(SPIRV::OpBranchConditional))
3376 .
addMBB(
I.getOperand(0).getMBB())
3380 .
addMBB(
I.getOperand(0).getMBB())
3384bool SPIRVInstructionSelector::selectBranchCond(
MachineInstr &
I)
const {
3397 if (NextI !=
nullptr && NextI->
getOpcode() == SPIRV::OpBranchConditional)
3404 return BuildMI(
MBB,
I,
I.getDebugLoc(),
TII.get(SPIRV::OpBranchConditional))
3405 .
addUse(
I.getOperand(0).getReg())
3406 .
addMBB(
I.getOperand(1).getMBB())
3411bool SPIRVInstructionSelector::selectPhi(
Register ResVReg,
3414 auto MIB =
BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
TII.get(SPIRV::OpPhi))
3416 .
addUse(GR.getSPIRVTypeID(ResType));
3417 const unsigned NumOps =
I.getNumOperands();
3418 for (
unsigned i = 1; i < NumOps; i += 2) {
3419 MIB.
addUse(
I.getOperand(i + 0).getReg());
3420 MIB.
addMBB(
I.getOperand(i + 1).getMBB());
3428bool SPIRVInstructionSelector::selectGlobalValue(
3438 SPIRV::AccessQualifier::ReadWrite,
false);
3439 PointerBaseType = GR.getOrCreateSPIRVArrayType(
3442 PointerBaseType = GR.getOrCreateSPIRVType(
3443 GVType, MIRBuilder, SPIRV::AccessQualifier::ReadWrite,
false);
3446 std::string GlobalIdent;
3448 unsigned &
ID = UnnamedGlobalIDs[GV];
3450 ID = UnnamedGlobalIDs.size();
3451 GlobalIdent =
"__unnamed_" +
Twine(
ID).
str();
3466 if (isa<Function>(GV)) {
3469 Register NewReg = GR.find(ConstVal, GR.CurMF);
3472 GR.add(ConstVal, GR.CurMF, NewReg);
3474 STI.canUseExtension(SPIRV::Extension::SPV_INTEL_function_pointers)
3475 ? dyn_cast<Function>(GV)
3477 SPIRVType *ResType = GR.getOrCreateSPIRVPointerType(
3478 PointerBaseType,
I,
TII,
3479 GVFun ? SPIRV::StorageClass::CodeSectionINTEL
3487 MRI->setRegClass(FuncVReg, &SPIRV::iIDRegClass);
3490 TII.get(SPIRV::OpConstantFunctionPointerINTEL))
3492 .
addUse(GR.getSPIRVTypeID(ResType))
3498 return BuildMI(BB,
I,
I.getDebugLoc(),
TII.get(SPIRV::OpConstantNull))
3500 .
addUse(GR.getSPIRVTypeID(ResType))
3503 assert(NewReg != ResVReg);
3504 return BuildCOPY(ResVReg, NewReg,
I);
3506 auto GlobalVar = cast<GlobalVariable>(GV);
3509 bool HasInit =
GlobalVar->hasInitializer() &&
3510 !isa<UndefValue>(
GlobalVar->getInitializer());
3513 if (HasInit && !
Init)
3517 SPIRV::LinkageType::LinkageType LnkType =
3519 ? SPIRV::LinkageType::Import
3521 STI.canUseExtension(SPIRV::Extension::SPV_KHR_linkonce_odr)
3522 ? SPIRV::LinkageType::LinkOnceODR
3523 : SPIRV::LinkageType::Export);
3532 GlobalVar->isConstant(), HasLnkTy, LnkType, MIRBuilder,
true);
3533 return Reg.isValid();
3536bool SPIRVInstructionSelector::selectLog10(
Register ResVReg,
3539 if (STI.canUseExtInstSet(SPIRV::InstructionSet::OpenCL_std)) {
3540 return selectExtInst(ResVReg, ResType,
I, CL::log10);
3552 Register VarReg =
MRI->createVirtualRegister(GR.getRegClass(ResType));
3554 BuildMI(BB,
I,
I.getDebugLoc(),
TII.get(SPIRV::OpExtInst))
3556 .
addUse(GR.getSPIRVTypeID(ResType))
3557 .
addImm(
static_cast<uint32_t>(SPIRV::InstructionSet::GLSL_std_450))
3559 .
add(
I.getOperand(1))
3564 ResType->
getOpcode() == SPIRV::OpTypeFloat);
3567 ResType->
getOpcode() == SPIRV::OpTypeVector
3571 GR.buildConstantFP(
APFloat(0.30103f), MIRBuilder, SpirvScalarType);
3574 auto Opcode = ResType->
getOpcode() == SPIRV::OpTypeVector
3575 ? SPIRV::OpVectorTimesScalar
3579 .
addUse(GR.getSPIRVTypeID(ResType))
3588bool SPIRVInstructionSelector::loadVec3BuiltinInputID(
3589 SPIRV::BuiltIn::BuiltIn BuiltInValue,
Register ResVReg,
3592 const SPIRVType *U32Type = GR.getOrCreateSPIRVIntegerType(32, MIRBuilder);
3594 GR.getOrCreateSPIRVVectorType(U32Type, 3, MIRBuilder);
3595 const SPIRVType *PtrType = GR.getOrCreateSPIRVPointerType(
3596 Vec3Ty, MIRBuilder, SPIRV::StorageClass::Input);
3602 GR.assignSPIRVTypeToVReg(PtrType, NewRegister, MIRBuilder.
getMF());
3606 Register Variable = GR.buildGlobalVariable(
3608 SPIRV::StorageClass::Input,
nullptr,
true,
true,
3609 SPIRV::LinkageType::Import, MIRBuilder,
false);
3613 Register LoadedRegister =
MRI->createVirtualRegister(&SPIRV::iIDRegClass);
3615 GR.assignSPIRVTypeToVReg(Vec3Ty, LoadedRegister, MIRBuilder.
getMF());
3619 BuildMI(*
I.getParent(),
I,
I.getDebugLoc(),
TII.get(SPIRV::OpLoad))
3621 .
addUse(GR.getSPIRVTypeID(Vec3Ty))
3626 assert(
I.getOperand(2).isReg());
3631 auto MIB =
BuildMI(BB,
I,
I.getDebugLoc(),
TII.get(SPIRV::OpCompositeExtract))
3633 .
addUse(GR.getSPIRVTypeID(ResType))
3642 if (
Type->getOpcode() != SPIRV::OpTypeVector)
3643 return GR.getOrCreateSPIRVVectorType(
Type, 4, MIRBuilder);
3646 if (VectorSize == 4)
3650 const SPIRVType *ScalarType = GR.getSPIRVTypeForVReg(ScalarTypeReg);
3651 return GR.getOrCreateSPIRVVectorType(ScalarType, 4, MIRBuilder);
3659 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 isDeclaration() const
Return true if the primary definition of this global value is outside of the current translation unit...
LinkageTypes getLinkage() const
unsigned getAddressSpace() const
Module * getParent()
Get the module that this global value is contained inside of...
static std::string getGlobalIdentifier(StringRef Name, GlobalValue::LinkageTypes Linkage, StringRef FileName)
Return the modified name for a global value suitable to be used as the key for a global lookup (e....
bool hasAvailableExternallyLinkage() const
@ InternalLinkage
Rename collisions when linking (static functions).
@ LinkOnceODRLinkage
Same, but only replaced by something equivalent.
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'.
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
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...