38#define DEBUG_TYPE "riscv-insert-vsetvli"
39#define RISCV_INSERT_VSETVLI_NAME "RISC-V Insert VSETVLI pass"
41STATISTIC(NumInsertedVSETVL,
"Number of VSETVL inst inserted");
42STATISTIC(NumCoalescedVSETVL,
"Number of VSETVL inst coalesced");
46 cl::desc(
"Insert vsetvlis before vmvNr.vs to ensure vtype is valid and "
62 return LI.getVNInfoBefore(
SI);
79static std::optional<unsigned> getEEWForLoadStore(
const MachineInstr &
MI) {
101 case RISCV::VSSE64_V:
111 const unsigned Log2SEW =
MI.getOperand(getSEWOpNum(
MI)).getImm();
123 if (!
MI.isRegTiedToUseOperand(0, &UseOpIdx))
131 return UseMO.
getReg() == RISCV::NoRegister || UseMO.
isUndef();
137 return MI.isCopy() &&
MI.getOperand(0).getReg().isPhysical() &&
139 TRI->getMinimalPhysRegClass(
MI.getOperand(0).getReg()));
143struct DemandedFields {
148 bool VLZeroness =
false;
152 SEWGreaterThanOrEqualAndLessThan64 =
156 SEWGreaterThanOrEqual = 1,
162 LMULLessThanOrEqualToM1 = 1,
165 bool SEWLMULRatio =
false;
166 bool TailPolicy =
false;
167 bool MaskPolicy =
false;
173 bool usedVTYPE()
const {
174 return SEW || LMUL || SEWLMULRatio || TailPolicy || MaskPolicy || VILL;
179 return VLAny || VLZeroness;
198 static DemandedFields
all() {
206 void doUnion(
const DemandedFields &
B) {
208 VLZeroness |=
B.VLZeroness;
209 SEW = std::max(SEW,
B.SEW);
210 LMUL = std::max(LMUL,
B.LMUL);
211 SEWLMULRatio |=
B.SEWLMULRatio;
212 TailPolicy |=
B.TailPolicy;
213 MaskPolicy |=
B.MaskPolicy;
217#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
225 void print(raw_ostream &OS)
const {
227 OS <<
"VLAny=" << VLAny <<
", ";
228 OS <<
"VLZeroness=" << VLZeroness <<
", ";
234 case SEWGreaterThanOrEqual:
235 OS <<
"SEWGreaterThanOrEqual";
237 case SEWGreaterThanOrEqualAndLessThan64:
238 OS <<
"SEWGreaterThanOrEqualAndLessThan64";
250 case LMULLessThanOrEqualToM1:
251 OS <<
"LMULLessThanOrEqualToM1";
258 OS <<
"SEWLMULRatio=" << SEWLMULRatio <<
", ";
259 OS <<
"TailPolicy=" << TailPolicy <<
", ";
260 OS <<
"MaskPolicy=" << MaskPolicy <<
", ";
261 OS <<
"VILL=" << VILL;
267#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
277 return Fractional || LMul == 1;
284 const DemandedFields &Used) {
286 case DemandedFields::SEWNone:
288 case DemandedFields::SEWEqual:
292 case DemandedFields::SEWGreaterThanOrEqual:
296 case DemandedFields::SEWGreaterThanOrEqualAndLessThan64:
304 case DemandedFields::LMULNone:
306 case DemandedFields::LMULEqual:
310 case DemandedFields::LMULLessThanOrEqualToM1:
316 if (
Used.SEWLMULRatio) {
321 if (Ratio1 != Ratio2)
344 if (
MI.isCall() ||
MI.isInlineAsm() ||
345 MI.readsRegister(RISCV::VL,
nullptr))
347 if (
MI.isCall() ||
MI.isInlineAsm() ||
348 MI.readsRegister(RISCV::VTYPE,
nullptr))
356 !VLOp.isReg() || !VLOp.isUndef())
361 Res.MaskPolicy =
false;
370 if (getEEWForLoadStore(
MI)) {
371 Res.SEW = DemandedFields::SEWNone;
372 Res.LMUL = DemandedFields::LMULNone;
377 Res.TailPolicy =
false;
378 Res.MaskPolicy =
false;
385 if (isMaskRegOp(
MI)) {
386 Res.SEW = DemandedFields::SEWNone;
387 Res.LMUL = DemandedFields::LMULNone;
391 if (RISCVInstrInfo::isScalarInsertInstr(
MI)) {
392 Res.LMUL = DemandedFields::LMULNone;
393 Res.SEWLMULRatio =
false;
401 if (hasUndefinedPassthru(
MI)) {
402 if (RISCVInstrInfo::isFloatScalarMoveOrScalarSplatInstr(
MI) &&
403 !
ST->hasVInstructionsF64())
404 Res.SEW = DemandedFields::SEWGreaterThanOrEqualAndLessThan64;
406 Res.SEW = DemandedFields::SEWGreaterThanOrEqual;
407 Res.TailPolicy =
false;
412 if (RISCVInstrInfo::isScalarExtractInstr(
MI)) {
414 Res.LMUL = DemandedFields::LMULNone;
415 Res.SEWLMULRatio =
false;
416 Res.TailPolicy =
false;
417 Res.MaskPolicy =
false;
431 if (RISCVInstrInfo::isVSlideInstr(
MI) && VLOp.
isImm() &&
432 VLOp.
getImm() == 1 && hasUndefinedPassthru(
MI) &&
433 !
ST->hasVLDependentLatency()) {
435 Res.VLZeroness =
true;
436 Res.LMUL = DemandedFields::LMULLessThanOrEqualToM1;
437 Res.TailPolicy =
false;
446 if (RISCVInstrInfo::isScalarSplatInstr(
MI) && VLOp.
isImm() &&
447 VLOp.
getImm() == 1 && hasUndefinedPassthru(
MI) &&
448 !
ST->hasVLDependentLatency()) {
449 Res.LMUL = DemandedFields::LMULLessThanOrEqualToM1;
450 Res.SEWLMULRatio =
false;
452 if (RISCVInstrInfo::isFloatScalarMoveOrScalarSplatInstr(
MI) &&
453 !
ST->hasVInstructionsF64())
454 Res.SEW = DemandedFields::SEWGreaterThanOrEqualAndLessThan64;
456 Res.SEW = DemandedFields::SEWGreaterThanOrEqual;
457 Res.TailPolicy =
false;
468 if (isVectorCopy(
ST->getRegisterInfo(),
MI)) {
469 Res.LMUL = DemandedFields::LMULNone;
470 Res.SEW = DemandedFields::SEWNone;
471 Res.SEWLMULRatio =
false;
472 Res.TailPolicy =
false;
473 Res.MaskPolicy =
false;
476 if (RISCVInstrInfo::isVExtractInstr(
MI)) {
479 Res.TailPolicy =
false;
505 } State = Uninitialized;
510 uint8_t TailAgnostic : 1;
511 uint8_t MaskAgnostic : 1;
512 uint8_t SEWLMULRatioOnly : 1;
516 : AVLImm(0), TailAgnostic(
false), MaskAgnostic(
false),
517 SEWLMULRatioOnly(
false) {}
519 static VSETVLIInfo getUnknown() {
525 bool isValid()
const {
return State != Uninitialized; }
526 void setUnknown() { State = Unknown; }
527 bool isUnknown()
const {
return State == Unknown; }
529 void setAVLRegDef(
const VNInfo *VNInfo,
Register AVLReg) {
531 AVLRegDef.ValNo = VNInfo;
532 AVLRegDef.DefReg = AVLReg;
536 void setAVLImm(
unsigned Imm) {
541 void setAVLVLMAX() { State = AVLIsVLMAX; }
543 bool hasAVLImm()
const {
return State == AVLIsImm; }
544 bool hasAVLReg()
const {
return State == AVLIsReg; }
545 bool hasAVLVLMAX()
const {
return State == AVLIsVLMAX; }
547 assert(hasAVLReg() && AVLRegDef.DefReg.isVirtual());
548 return AVLRegDef.DefReg;
550 unsigned getAVLImm()
const {
554 const VNInfo *getAVLVNInfo()
const {
556 return AVLRegDef.ValNo;
562 const MachineInstr *getAVLDefMI(
const LiveIntervals *LIS)
const {
564 if (!LIS || getAVLVNInfo()->isPHIDef())
571 void setAVL(
const VSETVLIInfo &
Info) {
573 if (
Info.isUnknown())
575 else if (
Info.hasAVLReg())
576 setAVLRegDef(
Info.getAVLVNInfo(),
Info.getAVLReg());
577 else if (
Info.hasAVLVLMAX())
581 setAVLImm(
Info.getAVLImm());
585 unsigned getSEW()
const {
return SEW; }
587 bool getTailAgnostic()
const {
return TailAgnostic; }
588 bool getMaskAgnostic()
const {
return MaskAgnostic; }
590 bool hasNonZeroAVL(
const LiveIntervals *LIS)
const {
592 return getAVLImm() > 0;
594 if (
auto *
DefMI = getAVLDefMI(LIS))
595 return RISCVInstrInfo::isNonZeroLoadImmediate(*
DefMI);
602 bool hasEquallyZeroAVL(
const VSETVLIInfo &
Other,
603 const LiveIntervals *LIS)
const {
604 if (hasSameAVL(
Other))
606 return (hasNonZeroAVL(LIS) &&
Other.hasNonZeroAVL(LIS));
609 bool hasSameAVLLatticeValue(
const VSETVLIInfo &
Other)
const {
610 if (hasAVLReg() &&
Other.hasAVLReg()) {
612 "we either have intervals or we don't");
614 return getAVLReg() ==
Other.getAVLReg();
615 return getAVLVNInfo()->id ==
Other.getAVLVNInfo()->id &&
616 getAVLReg() ==
Other.getAVLReg();
619 if (hasAVLImm() &&
Other.hasAVLImm())
620 return getAVLImm() ==
Other.getAVLImm();
623 return Other.hasAVLVLMAX() && hasSameVLMAX(
Other);
630 bool hasSameAVL(
const VSETVLIInfo &
Other)
const {
634 if (hasAVLReg() &&
Other.hasAVLReg()) {
636 "we either have intervals or we don't");
640 return hasSameAVLLatticeValue(
Other);
643 void setVTYPE(
unsigned VType) {
645 "Can't set VTYPE for uninitialized or unknown");
653 "Can't set VTYPE for uninitialized or unknown");
664 "Can't encode VTYPE for uninitialized or unknown");
668 bool hasSEWLMULRatioOnly()
const {
return SEWLMULRatioOnly; }
670 bool hasSameVTYPE(
const VSETVLIInfo &
Other)
const {
672 "Can't compare invalid VSETVLIInfos");
674 "Can't compare VTYPE in unknown state");
675 assert(!SEWLMULRatioOnly && !
Other.SEWLMULRatioOnly &&
676 "Can't compare when only LMUL/SEW ratio is valid.");
677 return std::tie(VLMul, SEW, TailAgnostic, MaskAgnostic) ==
684 "Can't use VTYPE for uninitialized or unknown");
692 bool hasSameVLMAX(
const VSETVLIInfo &
Other)
const {
694 "Can't compare invalid VSETVLIInfos");
696 "Can't compare VTYPE in unknown state");
700 bool hasCompatibleVTYPE(
const DemandedFields &Used,
701 const VSETVLIInfo &Require)
const {
702 return areCompatibleVTYPEs(Require.encodeVTYPE(),
encodeVTYPE(), Used);
708 bool isCompatible(
const DemandedFields &Used,
const VSETVLIInfo &Require,
709 const LiveIntervals *LIS)
const {
711 "Can't compare invalid VSETVLIInfos");
713 if (isUnknown() || Require.isUnknown())
717 if (SEWLMULRatioOnly || Require.SEWLMULRatioOnly)
720 if (
Used.VLAny && !(hasSameAVL(Require) && hasSameVLMAX(Require)))
723 if (
Used.VLZeroness && !hasEquallyZeroAVL(Require, LIS))
726 return hasCompatibleVTYPE(Used, Require);
732 return !
Other.isValid();
733 if (!
Other.isValid())
738 return Other.isUnknown();
739 if (
Other.isUnknown())
742 if (!hasSameAVLLatticeValue(
Other))
746 if (SEWLMULRatioOnly !=
Other.SEWLMULRatioOnly)
750 if (SEWLMULRatioOnly)
751 return hasSameVLMAX(
Other);
754 return hasSameVTYPE(
Other);
758 return !(*
this ==
Other);
765 if (!
Other.isValid())
773 if (isUnknown() ||
Other.isUnknown())
774 return VSETVLIInfo::getUnknown();
782 if (hasSameAVL(
Other) && hasSameVLMAX(
Other)) {
783 VSETVLIInfo MergeInfo = *
this;
784 MergeInfo.SEWLMULRatioOnly =
true;
789 return VSETVLIInfo::getUnknown();
792#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
801 void print(raw_ostream &OS)
const {
804 OS <<
"Uninitialized";
810 OS <<
"AVLImm=" << (unsigned)AVLImm;
825 <<
"SEW=e" << (unsigned)SEW <<
", "
826 <<
"TailAgnostic=" << (
bool)TailAgnostic <<
", "
827 <<
"MaskAgnostic=" << (bool)MaskAgnostic <<
", "
828 <<
"SEWLMULRatioOnly=" << (
bool)SEWLMULRatioOnly <<
"}";
833#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
851 bool InQueue =
false;
857 const RISCVSubtarget *ST;
858 const TargetInstrInfo *TII;
859 MachineRegisterInfo *MRI;
863 std::vector<BlockData> BlockInfo;
864 std::queue<const MachineBasicBlock *> WorkList;
869 RISCVInsertVSETVLI() : MachineFunctionPass(ID) {}
870 bool runOnMachineFunction(MachineFunction &MF)
override;
872 void getAnalysisUsage(AnalysisUsage &AU)
const override {
887 bool needVSETVLI(
const DemandedFields &Used,
const VSETVLIInfo &Require,
888 const VSETVLIInfo &CurInfo)
const;
889 bool needVSETVLIPHI(
const VSETVLIInfo &Require,
890 const MachineBasicBlock &
MBB)
const;
891 void insertVSETVLI(MachineBasicBlock &
MBB,
893 const VSETVLIInfo &
Info,
const VSETVLIInfo &PrevInfo);
895 void transferBefore(VSETVLIInfo &
Info,
const MachineInstr &
MI)
const;
896 void transferAfter(VSETVLIInfo &
Info,
const MachineInstr &
MI)
const;
897 bool computeVLVTYPEChanges(
const MachineBasicBlock &
MBB,
898 VSETVLIInfo &
Info)
const;
899 void computeIncomingVLVTYPE(
const MachineBasicBlock &
MBB);
900 void emitVSETVLIs(MachineBasicBlock &
MBB);
901 void doPRE(MachineBasicBlock &
MBB);
902 void insertReadVL(MachineBasicBlock &
MBB);
904 bool canMutatePriorConfig(
const MachineInstr &PrevMI,
const MachineInstr &
MI,
905 const DemandedFields &Used)
const;
906 void coalesceVSETVLIs(MachineBasicBlock &
MBB)
const;
908 VSETVLIInfo getInfoForVSETVLI(
const MachineInstr &
MI)
const;
909 VSETVLIInfo computeInfoForInstr(
const MachineInstr &
MI)
const;
910 void forwardVSETVLIAVL(VSETVLIInfo &
Info)
const;
915char RISCVInsertVSETVLI::ID = 0;
929void RISCVInsertVSETVLI::forwardVSETVLIAVL(VSETVLIInfo &
Info)
const {
930 if (!
Info.hasAVLReg())
933 if (!
DefMI || !RISCVInstrInfo::isVectorConfigInstr(*
DefMI))
935 VSETVLIInfo DefInstrInfo = getInfoForVSETVLI(*
DefMI);
936 if (!DefInstrInfo.hasSameVLMAX(
Info))
938 Info.setAVL(DefInstrInfo);
944RISCVInsertVSETVLI::getInfoForVSETVLI(
const MachineInstr &
MI)
const {
946 if (
MI.getOpcode() == RISCV::PseudoVSETIVLI) {
947 NewInfo.setAVLImm(
MI.getOperand(1).getImm());
949 assert(
MI.getOpcode() == RISCV::PseudoVSETVLI ||
950 MI.getOpcode() == RISCV::PseudoVSETVLIX0);
951 if (
MI.getOpcode() == RISCV::PseudoVSETVLIX0)
952 NewInfo.setAVLVLMAX();
953 else if (
MI.getOperand(1).isUndef())
955 NewInfo.setAVLImm(1);
958 VNInfo *VNI = getVNInfoFromReg(AVLReg,
MI, LIS);
959 NewInfo.setAVLRegDef(VNI, AVLReg);
962 NewInfo.setVTYPE(
MI.getOperand(2).getImm());
964 forwardVSETVLIAVL(NewInfo);
969static unsigned computeVLMAX(
unsigned VLEN,
unsigned SEW,
980RISCVInsertVSETVLI::computeInfoForInstr(
const MachineInstr &
MI)
const {
981 VSETVLIInfo InstrInfo;
982 const uint64_t TSFlags =
MI.getDesc().TSFlags;
984 bool TailAgnostic =
true;
985 bool MaskAgnostic =
true;
986 if (!hasUndefinedPassthru(
MI)) {
988 TailAgnostic =
false;
989 MaskAgnostic =
false;
993 const MachineOperand &
Op =
MI.getOperand(getVecPolicyOpNum(
MI));
994 uint64_t Policy =
Op.getImm();
997 "Invalid Policy Value");
1003 MaskAgnostic =
true;
1008 unsigned Log2SEW =
MI.getOperand(getSEWOpNum(
MI)).getImm();
1010 unsigned SEW = Log2SEW ? 1 << Log2SEW : 8;
1014 const MachineOperand &VLOp =
MI.getOperand(getVLOpNum(
MI));
1021 const unsigned VLMAX = computeVLMAX(
ST->getRealMaxVLen(), SEW, VLMul);
1022 if (
ST->getRealMinVLen() ==
ST->getRealMaxVLen() && VLMAX <= 31)
1023 InstrInfo.setAVLImm(VLMAX);
1025 InstrInfo.setAVLVLMAX();
1028 InstrInfo.setAVLImm(Imm);
1031 InstrInfo.setAVLImm(1);
1033 VNInfo *VNI = getVNInfoFromReg(VLOp.
getReg(),
MI, LIS);
1034 InstrInfo.setAVLRegDef(VNI, VLOp.
getReg());
1037 assert(RISCVInstrInfo::isScalarExtractInstr(
MI) ||
1038 RISCVInstrInfo::isVExtractInstr(
MI));
1041 InstrInfo.setAVLImm(1);
1044 if (std::optional<unsigned> EEW = getEEWForLoadStore(
MI)) {
1045 assert(SEW == EEW &&
"Initial SEW doesn't match expected EEW");
1048 InstrInfo.setVTYPE(VLMul, SEW, TailAgnostic, MaskAgnostic);
1050 forwardVSETVLIAVL(InstrInfo);
1055void RISCVInsertVSETVLI::insertVSETVLI(MachineBasicBlock &
MBB,
1057 const VSETVLIInfo &
Info,
const VSETVLIInfo &PrevInfo) {
1059 ++NumInsertedVSETVL;
1060 if (PrevInfo.isValid() && !PrevInfo.isUnknown()) {
1063 if (
Info.hasSameAVL(PrevInfo) &&
Info.hasSameVLMAX(PrevInfo)) {
1077 if (
Info.hasSameVLMAX(PrevInfo) &&
Info.hasAVLReg()) {
1078 if (
const MachineInstr *
DefMI =
Info.getAVLDefMI(LIS);
1079 DefMI && RISCVInstrInfo::isVectorConfigInstr(*
DefMI)) {
1080 VSETVLIInfo DefInfo = getInfoForVSETVLI(*
DefMI);
1081 if (DefInfo.hasSameAVL(PrevInfo) && DefInfo.hasSameVLMAX(PrevInfo)) {
1096 if (
Info.hasAVLImm()) {
1106 if (
Info.hasAVLVLMAX()) {
1107 Register DestReg =
MRI->createVirtualRegister(&RISCV::GPRNoX0RegClass);
1120 MRI->constrainRegClass(AVLReg, &RISCV::GPRNoX0RegClass);
1129 const VNInfo *CurVNI =
Info.getAVLVNInfo();
1137 MRI->createVirtualRegister(&RISCV::GPRNoX0RegClass);
1150 MI->getOperand(1).setReg(AVLCopyReg);
1159bool RISCVInsertVSETVLI::needVSETVLI(
const DemandedFields &Used,
1160 const VSETVLIInfo &Require,
1161 const VSETVLIInfo &CurInfo)
const {
1162 if (!CurInfo.isValid() || CurInfo.isUnknown() || CurInfo.hasSEWLMULRatioOnly())
1165 if (CurInfo.isCompatible(Used, Require, LIS))
1175 const VSETVLIInfo &NewInfo,
1176 DemandedFields &Demanded) {
1177 VSETVLIInfo
Info = NewInfo;
1179 if (!Demanded.LMUL && !Demanded.SEWLMULRatio && PrevInfo.isValid() &&
1180 !PrevInfo.isUnknown()) {
1182 PrevInfo.getSEW(), PrevInfo.getVLMUL(),
Info.getSEW()))
1183 Info.setVLMul(*NewVLMul);
1184 Demanded.LMUL = DemandedFields::LMULEqual;
1193void RISCVInsertVSETVLI::transferBefore(VSETVLIInfo &
Info,
1194 const MachineInstr &
MI)
const {
1195 if (isVectorCopy(
ST->getRegisterInfo(),
MI) &&
1196 (
Info.isUnknown() || !
Info.isValid() ||
Info.hasSEWLMULRatioOnly())) {
1199 VSETVLIInfo NewInfo;
1200 NewInfo.setAVLImm(1);
1209 DemandedFields Demanded = getDemanded(
MI, ST);
1211 const VSETVLIInfo NewInfo = computeInfoForInstr(
MI);
1212 assert(NewInfo.isValid() && !NewInfo.isUnknown());
1213 if (
Info.isValid() && !needVSETVLI(Demanded, NewInfo,
Info))
1216 const VSETVLIInfo PrevInfo =
Info;
1217 if (!
Info.isValid() ||
Info.isUnknown())
1220 const VSETVLIInfo IncomingInfo =
adjustIncoming(PrevInfo, NewInfo, Demanded);
1229 bool EquallyZero = IncomingInfo.hasEquallyZeroAVL(PrevInfo, LIS) &&
1230 IncomingInfo.hasSameVLMAX(PrevInfo);
1231 if (Demanded.VLAny || (Demanded.VLZeroness && !EquallyZero))
1232 Info.setAVL(IncomingInfo);
1235 ((Demanded.LMUL || Demanded.SEWLMULRatio) ? IncomingInfo :
Info)
1237 ((Demanded.SEW || Demanded.SEWLMULRatio) ? IncomingInfo :
Info).getSEW(),
1240 (Demanded.TailPolicy ? IncomingInfo :
Info).getTailAgnostic() ||
1241 IncomingInfo.getTailAgnostic(),
1242 (Demanded.MaskPolicy ? IncomingInfo :
Info).getMaskAgnostic() ||
1243 IncomingInfo.getMaskAgnostic());
1247 if (
Info.hasSEWLMULRatioOnly()) {
1248 VSETVLIInfo RatiolessInfo = IncomingInfo;
1249 RatiolessInfo.setAVL(
Info);
1250 Info = RatiolessInfo;
1257void RISCVInsertVSETVLI::transferAfter(VSETVLIInfo &
Info,
1258 const MachineInstr &
MI)
const {
1259 if (RISCVInstrInfo::isVectorConfigInstr(
MI)) {
1260 Info = getInfoForVSETVLI(
MI);
1264 if (RISCVInstrInfo::isFaultOnlyFirstLoad(
MI)) {
1266 assert(
MI.getOperand(1).getReg().isVirtual());
1272 Info.setAVLRegDef(VNI,
MI.getOperand(1).getReg());
1274 Info.setAVLRegDef(
nullptr,
MI.getOperand(1).getReg());
1280 if (
MI.isCall() ||
MI.isInlineAsm() ||
1281 MI.modifiesRegister(RISCV::VL,
nullptr) ||
1282 MI.modifiesRegister(RISCV::VTYPE,
nullptr))
1283 Info = VSETVLIInfo::getUnknown();
1286bool RISCVInsertVSETVLI::computeVLVTYPEChanges(
const MachineBasicBlock &
MBB,
1287 VSETVLIInfo &
Info)
const {
1288 bool HadVectorOp =
false;
1291 for (
const MachineInstr &
MI :
MBB) {
1292 transferBefore(
Info,
MI);
1294 if (RISCVInstrInfo::isVectorConfigInstr(
MI) ||
1296 isVectorCopy(
ST->getRegisterInfo(),
MI))
1305void RISCVInsertVSETVLI::computeIncomingVLVTYPE(
const MachineBasicBlock &
MBB) {
1309 BBInfo.InQueue =
false;
1313 VSETVLIInfo InInfo = BBInfo.
Pred;
1316 InInfo.setUnknown();
1319 InInfo = InInfo.intersect(BlockInfo[
P->getNumber()].Exit);
1323 if (!InInfo.isValid())
1327 if (InInfo == BBInfo.
Pred)
1330 BBInfo.
Pred = InInfo;
1332 <<
" changed to " << BBInfo.
Pred <<
"\n");
1338 VSETVLIInfo TmpStatus;
1339 computeVLVTYPEChanges(
MBB, TmpStatus);
1343 if (BBInfo.
Exit == TmpStatus)
1346 BBInfo.
Exit = TmpStatus;
1348 <<
" changed to " << BBInfo.
Exit <<
"\n");
1353 if (!BlockInfo[S->getNumber()].InQueue) {
1354 BlockInfo[S->getNumber()].InQueue =
true;
1362bool RISCVInsertVSETVLI::needVSETVLIPHI(
const VSETVLIInfo &Require,
1363 const MachineBasicBlock &
MBB)
const {
1364 if (!Require.hasAVLReg())
1371 const VNInfo *Valno = Require.getAVLVNInfo();
1378 const VSETVLIInfo &PBBExit = BlockInfo[PBB->getNumber()].Exit;
1385 if (!
DefMI || !RISCVInstrInfo::isVectorConfigInstr(*
DefMI))
1390 VSETVLIInfo DefInfo = getInfoForVSETVLI(*
DefMI);
1391 if (DefInfo != PBBExit)
1397 if (PBBExit.isUnknown() || !PBBExit.hasSameVTYPE(Require))
1406void RISCVInsertVSETVLI::emitVSETVLIs(MachineBasicBlock &
MBB) {
1410 bool PrefixTransparent =
true;
1411 for (MachineInstr &
MI :
MBB) {
1412 const VSETVLIInfo PrevInfo = CurInfo;
1413 transferBefore(CurInfo,
MI);
1416 if (RISCVInstrInfo::isVectorConfigInstr(
MI)) {
1418 assert(
MI.getOperand(3).getReg() == RISCV::VL &&
1419 MI.getOperand(4).getReg() == RISCV::VTYPE &&
1420 "Unexpected operands where VL and VTYPE should be");
1421 MI.getOperand(3).setIsDead(
false);
1422 MI.getOperand(4).setIsDead(
false);
1423 PrefixTransparent =
false;
1427 isVectorCopy(
ST->getRegisterInfo(),
MI)) {
1428 if (!PrevInfo.isCompatible(DemandedFields::all(), CurInfo, LIS)) {
1429 insertVSETVLI(
MBB,
MI,
MI.getDebugLoc(), CurInfo, PrevInfo);
1430 PrefixTransparent =
false;
1436 uint64_t TSFlags =
MI.getDesc().TSFlags;
1438 if (!PrevInfo.isCompatible(DemandedFields::all(), CurInfo, LIS)) {
1446 if (!PrefixTransparent || needVSETVLIPHI(CurInfo,
MBB))
1447 insertVSETVLI(
MBB,
MI,
MI.getDebugLoc(), CurInfo, PrevInfo);
1448 PrefixTransparent =
false;
1452 MachineOperand &VLOp =
MI.getOperand(getVLOpNum(
MI));
1457 VLOp.
setReg(RISCV::NoRegister);
1472 for (MachineInstr *DeadMI : DeadMIs) {
1473 if (!
TII->isAddImmediate(*DeadMI,
Reg))
1476 DeadMI->eraseFromParent();
1487 if (
MI.isInlineAsm()) {
1494 if (
MI.isCall() ||
MI.isInlineAsm() ||
1495 MI.modifiesRegister(RISCV::VL,
nullptr) ||
1496 MI.modifiesRegister(RISCV::VTYPE,
nullptr))
1497 PrefixTransparent =
false;
1499 transferAfter(CurInfo,
MI);
1503 if (CurInfo !=
Info.Exit) {
1509 assert(CurInfo ==
Info.Exit &&
"InsertVSETVLI dataflow invariant violated");
1517void RISCVInsertVSETVLI::doPRE(MachineBasicBlock &
MBB) {
1521 MachineBasicBlock *UnavailablePred =
nullptr;
1522 VSETVLIInfo AvailableInfo;
1524 const VSETVLIInfo &PredInfo = BlockInfo[
P->getNumber()].Exit;
1525 if (PredInfo.isUnknown()) {
1526 if (UnavailablePred)
1528 UnavailablePred =
P;
1529 }
else if (!AvailableInfo.isValid()) {
1530 AvailableInfo = PredInfo;
1531 }
else if (AvailableInfo != PredInfo) {
1538 if (!UnavailablePred || !AvailableInfo.isValid())
1546 if (AvailableInfo.hasSEWLMULRatioOnly())
1556 if (AvailableInfo.hasAVLReg()) {
1557 SlotIndex
SI = AvailableInfo.getAVLVNInfo()->def;
1576 VSETVLIInfo CurInfo = AvailableInfo;
1577 int TransitionsRemoved = 0;
1578 for (
const MachineInstr &
MI :
MBB) {
1579 const VSETVLIInfo LastInfo = CurInfo;
1580 const VSETVLIInfo LastOldInfo = OldInfo;
1581 transferBefore(CurInfo,
MI);
1582 transferBefore(OldInfo,
MI);
1583 if (CurInfo == LastInfo)
1584 TransitionsRemoved++;
1585 if (LastOldInfo == OldInfo)
1586 TransitionsRemoved--;
1587 transferAfter(CurInfo,
MI);
1588 transferAfter(OldInfo,
MI);
1589 if (CurInfo == OldInfo)
1593 if (CurInfo != OldInfo || TransitionsRemoved <= 0)
1600 auto OldExit = BlockInfo[UnavailablePred->
getNumber()].Exit;
1602 << UnavailablePred->
getName() <<
" with state "
1603 << AvailableInfo <<
"\n");
1604 BlockInfo[UnavailablePred->
getNumber()].Exit = AvailableInfo;
1610 insertVSETVLI(*UnavailablePred, InsertPt,
1612 AvailableInfo, OldExit);
1617bool RISCVInsertVSETVLI::canMutatePriorConfig(
1618 const MachineInstr &PrevMI,
const MachineInstr &
MI,
1619 const DemandedFields &Used)
const {
1623 if (!RISCVInstrInfo::isVLPreservingConfig(
MI)) {
1627 if (
Used.VLZeroness) {
1628 if (RISCVInstrInfo::isVLPreservingConfig(PrevMI))
1630 if (!getInfoForVSETVLI(PrevMI).hasEquallyZeroAVL(getInfoForVSETVLI(
MI),
1635 auto &AVL =
MI.getOperand(1);
1639 if (AVL.isReg() && AVL.getReg() != RISCV::X0) {
1640 VNInfo *VNI = getVNInfoFromReg(AVL.getReg(),
MI, LIS);
1641 VNInfo *PrevVNI = getVNInfoFromReg(AVL.getReg(), PrevMI, LIS);
1642 if (!VNI || !PrevVNI || VNI != PrevVNI)
1649 auto VType =
MI.getOperand(2).getImm();
1650 return areCompatibleVTYPEs(PriorVType, VType, Used);
1653void RISCVInsertVSETVLI::coalesceVSETVLIs(MachineBasicBlock &
MBB)
const {
1654 MachineInstr *NextMI =
nullptr;
1657 DemandedFields
Used;
1662 auto dropAVLUse = [&](MachineOperand &MO) {
1663 if (!MO.isReg() || !MO.getReg().isVirtual())
1666 MO.setReg(RISCV::NoRegister);
1671 MachineInstr *VLOpDef =
MRI->getUniqueVRegDef(OldVLReg);
1672 if (VLOpDef &&
TII->isAddImmediate(*VLOpDef, OldVLReg) &&
1673 MRI->use_nodbg_empty(OldVLReg))
1679 if (!RISCVInstrInfo::isVectorConfigInstr(
MI)) {
1680 Used.doUnion(getDemanded(
MI, ST));
1681 if (
MI.isCall() ||
MI.isInlineAsm() ||
1682 MI.modifiesRegister(RISCV::VL,
nullptr) ||
1683 MI.modifiesRegister(RISCV::VTYPE,
nullptr))
1688 if (!
MI.getOperand(0).isDead())
1692 if (!
Used.usedVL() && !
Used.usedVTYPE()) {
1693 dropAVLUse(
MI.getOperand(1));
1696 MI.eraseFromParent();
1697 NumCoalescedVSETVL++;
1702 if (canMutatePriorConfig(
MI, *NextMI, Used)) {
1703 if (!RISCVInstrInfo::isVLPreservingConfig(*NextMI)) {
1706 MI.getOperand(0).setReg(DefReg);
1707 MI.getOperand(0).setIsDead(
false);
1710 dropAVLUse(
MI.getOperand(1));
1723 SlotIndex NextMISlot =
1726 LiveInterval::Segment S(MISlot, NextMISlot, DefVNI);
1728 DefVNI->
def = MISlot;
1745 NumCoalescedVSETVL++;
1750 Used = getDemanded(
MI, ST);
1755 for (
auto *
MI : ToDelete) {
1760 MI->eraseFromParent();
1764void RISCVInsertVSETVLI::insertReadVL(MachineBasicBlock &
MBB) {
1766 MachineInstr &
MI = *
I++;
1767 if (RISCVInstrInfo::isFaultOnlyFirstLoad(
MI)) {
1768 Register VLOutput =
MI.getOperand(1).getReg();
1770 if (!
MI.getOperand(1).isDead()) {
1772 TII->get(RISCV::PseudoReadVL), VLOutput);
1775 SlotIndex NewDefSI =
1781 DefVNI->
def = NewDefSI;
1785 MI.getOperand(1).setReg(RISCV::X0);
1786 MI.addRegisterDefined(RISCV::VL,
MRI->getTargetRegisterInfo());
1791bool RISCVInsertVSETVLI::runOnMachineFunction(MachineFunction &MF) {
1794 if (!
ST->hasVInstructions())
1799 TII =
ST->getInstrInfo();
1801 auto *LISWrapper = getAnalysisIfAvailable<LiveIntervalsWrapperPass>();
1802 LIS = LISWrapper ? &LISWrapper->getLIS() :
nullptr;
1804 assert(BlockInfo.empty() &&
"Expect empty block infos");
1807 bool HaveVectorOp =
false;
1810 for (
const MachineBasicBlock &
MBB : MF) {
1811 VSETVLIInfo TmpStatus;
1812 HaveVectorOp |= computeVLVTYPEChanges(
MBB, TmpStatus);
1815 BBInfo.
Exit = TmpStatus;
1817 <<
" is " << BBInfo.
Exit <<
"\n");
1822 if (!HaveVectorOp) {
1830 for (
const MachineBasicBlock &
MBB : MF) {
1831 WorkList.push(&
MBB);
1834 while (!WorkList.empty()) {
1835 const MachineBasicBlock &
MBB = *WorkList.front();
1837 computeIncomingVLVTYPE(
MBB);
1841 for (MachineBasicBlock &
MBB : MF)
1848 for (MachineBasicBlock &
MBB : MF)
1861 coalesceVSETVLIs(*
MBB);
1865 for (MachineBasicBlock &
MBB : MF)
1869 return HaveVectorOp;
1874 return new RISCVInsertVSETVLI();
unsigned const MachineRegisterInfo * MRI
MachineInstrBuilder MachineInstrBuilder & DefMI
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
Function Alias Analysis false
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
Analysis containing CSE Info
#define LLVM_ATTRIBUTE_USED
#define LLVM_DUMP_METHOD
Mark debug helper function definitions like dump() that should not be stripped from debug builds.
static RegisterPass< DebugifyFunctionPass > DF("debugify-function", "Attach debug info to a function")
const HexagonInstrInfo * TII
Register const TargetRegisterInfo * TRI
static Interval intersect(const Interval &I1, const Interval &I2)
Promote Memory to Register
uint64_t IntrinsicInst * II
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
This file builds on the ADT/GraphTraits.h file to build a generic graph post order iterator.
static cl::opt< bool > EnsureWholeVectorRegisterMoveValidVTYPE(DEBUG_TYPE "-whole-vector-register-move-valid-vtype", cl::Hidden, cl::desc("Insert vsetvlis before vmvNr.vs to ensure vtype is valid and " "vill is cleared"), cl::init(true))
static VSETVLIInfo adjustIncoming(const VSETVLIInfo &PrevInfo, const VSETVLIInfo &NewInfo, DemandedFields &Demanded)
#define RISCV_INSERT_VSETVLI_NAME
static bool isValid(const char C)
Returns true if C is a valid mangled character: <0-9a-zA-Z_>.
SI Optimize VGPR LiveRange
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
AnalysisUsage & addUsedIfAvailable()
Add the specified Pass class to the set of analyses used by this pass.
AnalysisUsage & addPreserved()
Add the specified Pass class to the set of analyses preserved by this pass.
LLVM_ABI void setPreservesCFG()
This function should be called by the pass, iff they do not:
FunctionPass class - This class is used to implement most global optimizations.
void setWeight(float Value)
MachineInstr * getInstructionFromIndex(SlotIndex index) const
Returns the instruction associated with the given index.
SlotIndex InsertMachineInstrInMaps(MachineInstr &MI)
SlotIndexes * getSlotIndexes() const
SlotIndex getInstructionIndex(const MachineInstr &Instr) const
Returns the base index of the given instruction.
void RemoveMachineInstrFromMaps(MachineInstr &MI)
SlotIndex getMBBEndIdx(const MachineBasicBlock *mbb) const
Return the last index in the given basic block.
LiveInterval & getInterval(Register Reg)
void removeInterval(Register Reg)
Interval removal.
LLVM_ABI bool shrinkToUses(LiveInterval *li, SmallVectorImpl< MachineInstr * > *dead=nullptr)
After removing some uses of a register, shrink its live range to just the remaining uses.
LLVM_ABI void extendToIndices(LiveRange &LR, ArrayRef< SlotIndex > Indices, ArrayRef< SlotIndex > Undefs)
Extend the live range LR to reach all points in Indices.
LLVM_ABI void splitSeparateComponents(LiveInterval &LI, SmallVectorImpl< LiveInterval * > &SplitLIs)
Split separate components in LiveInterval LI into separate intervals.
MachineBasicBlock * getMBBFromIndex(SlotIndex index) const
LiveInterval & createAndComputeVirtRegInterval(Register Reg)
LLVM_ABI iterator addSegment(Segment S)
Add the specified Segment to this range, merging segments as appropriate.
const Segment * getSegmentContaining(SlotIndex Idx) const
Return the segment that contains the specified index, or null if there is none.
bool liveAt(SlotIndex index) const
VNInfo * getVNInfoBefore(SlotIndex Idx) const
getVNInfoBefore - Return the VNInfo that is live up to but not necessarily including Idx,...
bool containsOneValue() const
LLVM_ABI void removeSegment(SlotIndex Start, SlotIndex End, bool RemoveDeadValNo=false)
Remove the specified interval from this live range.
VNInfo * getVNInfoAt(SlotIndex Idx) const
getVNInfoAt - Return the VNInfo that is live at Idx, or NULL.
int getNumber() const
MachineBasicBlocks are uniquely numbered at the function level, unless they're not in a MachineFuncti...
LLVM_ABI iterator getFirstTerminator()
Returns an iterator to the first terminator instruction of this basic block.
unsigned succ_size() const
LLVM_ABI iterator getFirstNonPHI()
Returns a pointer to the first instruction in this block that is not a PHINode instruction.
LLVM_ABI DebugLoc findDebugLoc(instr_iterator MBBI)
Find the next valid DebugLoc starting at MBBI, skipping any debug instructions.
iterator_range< iterator > terminators()
iterator_range< succ_iterator > successors()
LLVM_ABI instr_iterator getFirstInstrTerminator()
Same getFirstTerminator but it ignores bundles and return an instr_iterator instead.
iterator_range< pred_iterator > predecessors()
MachineInstrBundleIterator< MachineInstr > iterator
LLVM_ABI StringRef getName() const
Return the name of the corresponding LLVM basic block, or an empty string.
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - Subclasses that override getAnalysisUsage must call this.
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
StringRef getName() const
getName - Return the name of the corresponding LLVM function.
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
unsigned getNumBlockIDs() const
getNumBlockIDs - Return the number of MBB ID's allocated.
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
const MachineInstrBuilder & addReg(Register RegNo, unsigned flags=0, unsigned SubReg=0) const
Add a new virtual register operand.
Representation of each machine instruction.
const MCInstrDesc & getDesc() const
Returns the target instruction descriptor of this MachineInstr.
LLVM_ABI void eraseFromParent()
Unlink 'this' from the containing basic block and delete it.
const MachineOperand & getOperand(unsigned i) const
MachineOperand class - Representation of each machine instruction operand.
bool isReg() const
isReg - Tests if this is a MO_Register operand.
LLVM_ABI void setReg(Register Reg)
Change the register this operand corresponds to.
bool isImm() const
isImm - Tests if this is a MO_Immediate operand.
void setIsKill(bool Val=true)
Register getReg() const
getReg - Returns the register number.
static MachineOperand CreateReg(Register Reg, bool isDef, bool isImp=false, bool isKill=false, bool isDead=false, bool isUndef=false, bool isEarlyClobber=false, unsigned SubReg=0, bool isDebug=false, bool isInternalRead=false, bool isRenamable=false)
Wrapper class representing virtual and physical registers.
constexpr bool isVirtual() const
Return true if the specified register number is in the virtual register namespace.
SlotIndex - An opaque wrapper around machine indexes.
SlotIndex getRegSlot(bool EC=false) const
Returns the register use/def slot in the current instruction for a normal or early-clobber def.
SlotIndex getInstructionIndex(const MachineInstr &MI, bool IgnoreBundle=false) const
Returns the base index for the given instruction.
void push_back(const T &Elt)
TargetRegisterInfo base class - We assume that the target defines a static array of TargetRegisterDes...
VNInfo - Value Number Information.
SlotIndex def
The index of the defining instruction.
bool isPHIDef() const
Returns true if this value is defined by a PHI instruction (or was, PHI instructions may have been el...
This class implements an extremely fast bulk output stream that can only output to a stream.
Predicate all(Predicate P0, Predicate P1)
True iff P0 and P1 are true.
static unsigned getVecPolicyOpNum(const MCInstrDesc &Desc)
static bool usesMaskPolicy(uint64_t TSFlags)
static RISCVVType::VLMUL getLMul(uint64_t TSFlags)
static unsigned getVLOpNum(const MCInstrDesc &Desc)
static bool hasVLOp(uint64_t TSFlags)
static bool hasVecPolicyOp(uint64_t TSFlags)
static unsigned getSEWOpNum(const MCInstrDesc &Desc)
static bool hasSEWOp(uint64_t TSFlags)
static bool isTailAgnostic(unsigned VType)
LLVM_ABI std::optional< VLMUL > getSameRatioLMUL(unsigned SEW, VLMUL VLMUL, unsigned EEW)
static bool isMaskAgnostic(unsigned VType)
LLVM_ABI std::pair< unsigned, bool > decodeVLMUL(VLMUL VLMul)
LLVM_ABI unsigned getSEWLMULRatio(unsigned SEW, VLMUL VLMul)
static bool isValidSEW(unsigned SEW)
LLVM_ABI unsigned encodeVTYPE(VLMUL VLMUL, unsigned SEW, bool TailAgnostic, bool MaskAgnostic, bool AltFmt=false)
static unsigned getSEW(unsigned VType)
static VLMUL getVLMUL(unsigned VType)
unsigned getRVVMCOpcode(unsigned RVVPseudoOpcode)
static constexpr int64_t VLMaxSentinel
@ Implicit
Not emitted register (e.g. carry, or temporary result).
@ Define
Register definition.
@ Kill
The last use of a register.
initializer< Ty > init(const Ty &Val)
This is an optimization pass for GlobalISel generic memory operations.
void dump(const SparseBitVector< ElementSize > &LHS, raw_ostream &out)
FunctionAddr VTableAddr Value
Printable print(const GCNRegPressure &RP, const GCNSubtarget *ST=nullptr, unsigned DynamicVGPRBlockSize=0)
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
bool operator!=(uint64_t V1, const APInt &V2)
iterator_range< early_inc_iterator_impl< detail::IterOfRange< RangeT > > > make_early_inc_range(RangeT &&Range)
Make a range that does early increment to allow mutation of the underlying range without disrupting i...
iterator_range< po_iterator< T > > post_order(const T &G)
bool operator==(const AddressRangeValuePair &LHS, const AddressRangeValuePair &RHS)
auto reverse(ContainerTy &&C)
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
FunctionPass * createRISCVInsertVSETVLIPass()
Returns an instance of the Insert VSETVLI pass.
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
DWARFExpression::Operation Op
raw_ostream & operator<<(raw_ostream &OS, const APFixedPoint &FX)
char & RISCVInsertVSETVLIID
LLVM_ABI Printable printReg(Register Reg, const TargetRegisterInfo *TRI=nullptr, unsigned SubIdx=0, const MachineRegisterInfo *MRI=nullptr)
Prints virtual and physical registers with or without a TRI instance.
LLVM_ABI Printable printMBBReference(const MachineBasicBlock &MBB)
Prints a machine basic block reference.
static bool isRVVRegClass(const TargetRegisterClass *RC)