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);
75static std::optional<unsigned> getEEWForLoadStore(
const MachineInstr &
MI) {
107 const unsigned Log2SEW =
MI.getOperand(getSEWOpNum(
MI)).getImm();
119 if (!
MI.isRegTiedToUseOperand(0, &UseOpIdx))
127 return UseMO.
getReg() == RISCV::NoRegister || UseMO.
isUndef();
133 return MI.isCopy() &&
MI.getOperand(0).getReg().isPhysical() &&
135 TRI->getMinimalPhysRegClass(
MI.getOperand(0).getReg()));
139struct DemandedFields {
144 bool VLZeroness =
false;
148 SEWGreaterThanOrEqualAndLessThan64 =
152 SEWGreaterThanOrEqual = 1,
158 LMULLessThanOrEqualToM1 = 1,
161 bool SEWLMULRatio =
false;
162 bool TailPolicy =
false;
163 bool MaskPolicy =
false;
169 bool usedVTYPE()
const {
170 return SEW || LMUL || SEWLMULRatio || TailPolicy || MaskPolicy || VILL;
175 return VLAny || VLZeroness;
194 static DemandedFields
all() {
202 void doUnion(
const DemandedFields &
B) {
204 VLZeroness |=
B.VLZeroness;
205 SEW = std::max(SEW,
B.SEW);
206 LMUL = std::max(LMUL,
B.LMUL);
207 SEWLMULRatio |=
B.SEWLMULRatio;
208 TailPolicy |=
B.TailPolicy;
209 MaskPolicy |=
B.MaskPolicy;
213#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
221 void print(raw_ostream &OS)
const {
223 OS <<
"VLAny=" << VLAny <<
", ";
224 OS <<
"VLZeroness=" << VLZeroness <<
", ";
230 case SEWGreaterThanOrEqual:
231 OS <<
"SEWGreaterThanOrEqual";
233 case SEWGreaterThanOrEqualAndLessThan64:
234 OS <<
"SEWGreaterThanOrEqualAndLessThan64";
246 case LMULLessThanOrEqualToM1:
247 OS <<
"LMULLessThanOrEqualToM1";
254 OS <<
"SEWLMULRatio=" << SEWLMULRatio <<
", ";
255 OS <<
"TailPolicy=" << TailPolicy <<
", ";
256 OS <<
"MaskPolicy=" << MaskPolicy <<
", ";
257 OS <<
"VILL=" << VILL;
263#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
273 return Fractional || LMul == 1;
280 const DemandedFields &Used) {
282 case DemandedFields::SEWNone:
284 case DemandedFields::SEWEqual:
288 case DemandedFields::SEWGreaterThanOrEqual:
292 case DemandedFields::SEWGreaterThanOrEqualAndLessThan64:
300 case DemandedFields::LMULNone:
302 case DemandedFields::LMULEqual:
306 case DemandedFields::LMULLessThanOrEqualToM1:
312 if (
Used.SEWLMULRatio) {
317 if (Ratio1 != Ratio2)
340 if (
MI.isCall() ||
MI.isInlineAsm() ||
341 MI.readsRegister(RISCV::VL,
nullptr))
343 if (
MI.isCall() ||
MI.isInlineAsm() ||
344 MI.readsRegister(RISCV::VTYPE,
nullptr))
352 !VLOp.isReg() || !VLOp.isUndef())
357 Res.MaskPolicy =
false;
366 if (getEEWForLoadStore(
MI)) {
367 Res.SEW = DemandedFields::SEWNone;
368 Res.LMUL = DemandedFields::LMULNone;
373 Res.TailPolicy =
false;
374 Res.MaskPolicy =
false;
381 if (isMaskRegOp(
MI)) {
382 Res.SEW = DemandedFields::SEWNone;
383 Res.LMUL = DemandedFields::LMULNone;
387 if (RISCVInstrInfo::isScalarInsertInstr(
MI)) {
388 Res.LMUL = DemandedFields::LMULNone;
389 Res.SEWLMULRatio =
false;
397 if (hasUndefinedPassthru(
MI)) {
398 if (RISCVInstrInfo::isFloatScalarMoveOrScalarSplatInstr(
MI) &&
399 !
ST->hasVInstructionsF64())
400 Res.SEW = DemandedFields::SEWGreaterThanOrEqualAndLessThan64;
402 Res.SEW = DemandedFields::SEWGreaterThanOrEqual;
403 Res.TailPolicy =
false;
408 if (RISCVInstrInfo::isScalarExtractInstr(
MI)) {
410 Res.LMUL = DemandedFields::LMULNone;
411 Res.SEWLMULRatio =
false;
412 Res.TailPolicy =
false;
413 Res.MaskPolicy =
false;
427 if (RISCVInstrInfo::isVSlideInstr(
MI) && VLOp.
isImm() &&
428 VLOp.
getImm() == 1 && hasUndefinedPassthru(
MI) &&
429 !
ST->hasVLDependentLatency()) {
431 Res.VLZeroness =
true;
432 Res.LMUL = DemandedFields::LMULLessThanOrEqualToM1;
433 Res.TailPolicy =
false;
442 if (RISCVInstrInfo::isScalarSplatInstr(
MI) && VLOp.
isImm() &&
443 VLOp.
getImm() == 1 && hasUndefinedPassthru(
MI) &&
444 !
ST->hasVLDependentLatency()) {
445 Res.LMUL = DemandedFields::LMULLessThanOrEqualToM1;
446 Res.SEWLMULRatio =
false;
448 if (RISCVInstrInfo::isFloatScalarMoveOrScalarSplatInstr(
MI) &&
449 !
ST->hasVInstructionsF64())
450 Res.SEW = DemandedFields::SEWGreaterThanOrEqualAndLessThan64;
452 Res.SEW = DemandedFields::SEWGreaterThanOrEqual;
453 Res.TailPolicy =
false;
464 if (isVectorCopy(
ST->getRegisterInfo(),
MI)) {
465 Res.LMUL = DemandedFields::LMULNone;
466 Res.SEW = DemandedFields::SEWNone;
467 Res.SEWLMULRatio =
false;
468 Res.TailPolicy =
false;
469 Res.MaskPolicy =
false;
472 if (RISCVInstrInfo::isVExtractInstr(
MI)) {
475 Res.TailPolicy =
false;
501 } State = Uninitialized;
506 uint8_t TailAgnostic : 1;
507 uint8_t MaskAgnostic : 1;
508 uint8_t SEWLMULRatioOnly : 1;
512 : AVLImm(0), TailAgnostic(
false), MaskAgnostic(
false),
513 SEWLMULRatioOnly(
false) {}
515 static VSETVLIInfo getUnknown() {
521 bool isValid()
const {
return State != Uninitialized; }
522 void setUnknown() { State = Unknown; }
523 bool isUnknown()
const {
return State == Unknown; }
525 void setAVLRegDef(
const VNInfo *VNInfo,
Register AVLReg) {
527 AVLRegDef.ValNo = VNInfo;
528 AVLRegDef.DefReg = AVLReg;
532 void setAVLImm(
unsigned Imm) {
537 void setAVLVLMAX() { State = AVLIsVLMAX; }
539 bool hasAVLImm()
const {
return State == AVLIsImm; }
540 bool hasAVLReg()
const {
return State == AVLIsReg; }
541 bool hasAVLVLMAX()
const {
return State == AVLIsVLMAX; }
543 assert(hasAVLReg() && AVLRegDef.DefReg.isVirtual());
544 return AVLRegDef.DefReg;
546 unsigned getAVLImm()
const {
550 const VNInfo *getAVLVNInfo()
const {
552 return AVLRegDef.ValNo;
558 const MachineInstr *getAVLDefMI(
const LiveIntervals *LIS)
const {
560 if (!LIS || getAVLVNInfo()->isPHIDef())
567 void setAVL(
const VSETVLIInfo &
Info) {
569 if (
Info.isUnknown())
571 else if (
Info.hasAVLReg())
572 setAVLRegDef(
Info.getAVLVNInfo(),
Info.getAVLReg());
573 else if (
Info.hasAVLVLMAX())
577 setAVLImm(
Info.getAVLImm());
581 unsigned getSEW()
const {
return SEW; }
583 bool getTailAgnostic()
const {
return TailAgnostic; }
584 bool getMaskAgnostic()
const {
return MaskAgnostic; }
586 bool hasNonZeroAVL(
const LiveIntervals *LIS)
const {
588 return getAVLImm() > 0;
590 if (
auto *
DefMI = getAVLDefMI(LIS))
591 return RISCVInstrInfo::isNonZeroLoadImmediate(*
DefMI);
598 bool hasEquallyZeroAVL(
const VSETVLIInfo &
Other,
599 const LiveIntervals *LIS)
const {
600 if (hasSameAVL(
Other))
602 return (hasNonZeroAVL(LIS) &&
Other.hasNonZeroAVL(LIS));
605 bool hasSameAVLLatticeValue(
const VSETVLIInfo &
Other)
const {
606 if (hasAVLReg() &&
Other.hasAVLReg()) {
608 "we either have intervals or we don't");
610 return getAVLReg() ==
Other.getAVLReg();
611 return getAVLVNInfo()->id ==
Other.getAVLVNInfo()->id &&
612 getAVLReg() ==
Other.getAVLReg();
615 if (hasAVLImm() &&
Other.hasAVLImm())
616 return getAVLImm() ==
Other.getAVLImm();
619 return Other.hasAVLVLMAX() && hasSameVLMAX(
Other);
626 bool hasSameAVL(
const VSETVLIInfo &
Other)
const {
630 if (hasAVLReg() &&
Other.hasAVLReg()) {
632 "we either have intervals or we don't");
636 return hasSameAVLLatticeValue(
Other);
639 void setVTYPE(
unsigned VType) {
641 "Can't set VTYPE for uninitialized or unknown");
649 "Can't set VTYPE for uninitialized or unknown");
660 "Can't encode VTYPE for uninitialized or unknown");
664 bool hasSEWLMULRatioOnly()
const {
return SEWLMULRatioOnly; }
666 bool hasSameVTYPE(
const VSETVLIInfo &
Other)
const {
668 "Can't compare invalid VSETVLIInfos");
670 "Can't compare VTYPE in unknown state");
671 assert(!SEWLMULRatioOnly && !
Other.SEWLMULRatioOnly &&
672 "Can't compare when only LMUL/SEW ratio is valid.");
673 return std::tie(VLMul, SEW, TailAgnostic, MaskAgnostic) ==
680 "Can't use VTYPE for uninitialized or unknown");
688 bool hasSameVLMAX(
const VSETVLIInfo &
Other)
const {
690 "Can't compare invalid VSETVLIInfos");
692 "Can't compare VTYPE in unknown state");
696 bool hasCompatibleVTYPE(
const DemandedFields &Used,
697 const VSETVLIInfo &Require)
const {
698 return areCompatibleVTYPEs(Require.encodeVTYPE(),
encodeVTYPE(), Used);
704 bool isCompatible(
const DemandedFields &Used,
const VSETVLIInfo &Require,
705 const LiveIntervals *LIS)
const {
707 "Can't compare invalid VSETVLIInfos");
709 if (isUnknown() || Require.isUnknown())
713 if (SEWLMULRatioOnly || Require.SEWLMULRatioOnly)
716 if (
Used.VLAny && !(hasSameAVL(Require) && hasSameVLMAX(Require)))
719 if (
Used.VLZeroness && !hasEquallyZeroAVL(Require, LIS))
722 return hasCompatibleVTYPE(Used, Require);
728 return !
Other.isValid();
729 if (!
Other.isValid())
734 return Other.isUnknown();
735 if (
Other.isUnknown())
738 if (!hasSameAVLLatticeValue(
Other))
742 if (SEWLMULRatioOnly !=
Other.SEWLMULRatioOnly)
746 if (SEWLMULRatioOnly)
747 return hasSameVLMAX(
Other);
750 return hasSameVTYPE(
Other);
754 return !(*
this ==
Other);
761 if (!
Other.isValid())
769 if (isUnknown() ||
Other.isUnknown())
770 return VSETVLIInfo::getUnknown();
778 if (hasSameAVL(
Other) && hasSameVLMAX(
Other)) {
779 VSETVLIInfo MergeInfo = *
this;
780 MergeInfo.SEWLMULRatioOnly =
true;
785 return VSETVLIInfo::getUnknown();
788#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
797 void print(raw_ostream &OS)
const {
800 OS <<
"Uninitialized";
806 OS <<
"AVLImm=" << (unsigned)AVLImm;
821 <<
"SEW=e" << (unsigned)SEW <<
", "
822 <<
"TailAgnostic=" << (
bool)TailAgnostic <<
", "
823 <<
"MaskAgnostic=" << (bool)MaskAgnostic <<
", "
824 <<
"SEWLMULRatioOnly=" << (
bool)SEWLMULRatioOnly <<
"}";
829#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
847 bool InQueue =
false;
853 const RISCVSubtarget *ST;
854 const TargetInstrInfo *TII;
855 MachineRegisterInfo *MRI;
859 std::vector<BlockData> BlockInfo;
860 std::queue<const MachineBasicBlock *> WorkList;
865 RISCVInsertVSETVLI() : MachineFunctionPass(ID) {}
866 bool runOnMachineFunction(MachineFunction &MF)
override;
868 void getAnalysisUsage(AnalysisUsage &AU)
const override {
883 bool needVSETVLI(
const DemandedFields &Used,
const VSETVLIInfo &Require,
884 const VSETVLIInfo &CurInfo)
const;
885 bool needVSETVLIPHI(
const VSETVLIInfo &Require,
886 const MachineBasicBlock &
MBB)
const;
887 void insertVSETVLI(MachineBasicBlock &
MBB,
889 const VSETVLIInfo &
Info,
const VSETVLIInfo &PrevInfo);
891 void transferBefore(VSETVLIInfo &
Info,
const MachineInstr &
MI)
const;
892 void transferAfter(VSETVLIInfo &
Info,
const MachineInstr &
MI)
const;
893 bool computeVLVTYPEChanges(
const MachineBasicBlock &
MBB,
894 VSETVLIInfo &
Info)
const;
895 void computeIncomingVLVTYPE(
const MachineBasicBlock &
MBB);
896 void emitVSETVLIs(MachineBasicBlock &
MBB);
897 void doPRE(MachineBasicBlock &
MBB);
898 void insertReadVL(MachineBasicBlock &
MBB);
900 bool canMutatePriorConfig(
const MachineInstr &PrevMI,
const MachineInstr &
MI,
901 const DemandedFields &Used)
const;
902 void coalesceVSETVLIs(MachineBasicBlock &
MBB)
const;
904 VSETVLIInfo getInfoForVSETVLI(
const MachineInstr &
MI)
const;
905 VSETVLIInfo computeInfoForInstr(
const MachineInstr &
MI)
const;
906 void forwardVSETVLIAVL(VSETVLIInfo &
Info)
const;
911char RISCVInsertVSETVLI::ID = 0;
925void RISCVInsertVSETVLI::forwardVSETVLIAVL(VSETVLIInfo &
Info)
const {
926 if (!
Info.hasAVLReg())
929 if (!
DefMI || !RISCVInstrInfo::isVectorConfigInstr(*
DefMI))
931 VSETVLIInfo DefInstrInfo = getInfoForVSETVLI(*
DefMI);
932 if (!DefInstrInfo.hasSameVLMAX(
Info))
934 Info.setAVL(DefInstrInfo);
940RISCVInsertVSETVLI::getInfoForVSETVLI(
const MachineInstr &
MI)
const {
942 if (
MI.getOpcode() == RISCV::PseudoVSETIVLI) {
943 NewInfo.setAVLImm(
MI.getOperand(1).getImm());
945 assert(
MI.getOpcode() == RISCV::PseudoVSETVLI ||
946 MI.getOpcode() == RISCV::PseudoVSETVLIX0);
947 if (
MI.getOpcode() == RISCV::PseudoVSETVLIX0)
948 NewInfo.setAVLVLMAX();
949 else if (
MI.getOperand(1).isUndef())
951 NewInfo.setAVLImm(1);
954 VNInfo *VNI = getVNInfoFromReg(AVLReg,
MI, LIS);
955 NewInfo.setAVLRegDef(VNI, AVLReg);
958 NewInfo.setVTYPE(
MI.getOperand(2).getImm());
960 forwardVSETVLIAVL(NewInfo);
965static unsigned computeVLMAX(
unsigned VLEN,
unsigned SEW,
976RISCVInsertVSETVLI::computeInfoForInstr(
const MachineInstr &
MI)
const {
977 VSETVLIInfo InstrInfo;
978 const uint64_t TSFlags =
MI.getDesc().TSFlags;
980 bool TailAgnostic =
true;
981 bool MaskAgnostic =
true;
982 if (!hasUndefinedPassthru(
MI)) {
984 TailAgnostic =
false;
985 MaskAgnostic =
false;
989 const MachineOperand &
Op =
MI.getOperand(
MI.getNumExplicitOperands() - 1);
990 uint64_t Policy =
Op.getImm();
993 "Invalid Policy Value");
1004 unsigned Log2SEW =
MI.getOperand(getSEWOpNum(
MI)).getImm();
1006 unsigned SEW = Log2SEW ? 1 << Log2SEW : 8;
1010 const MachineOperand &VLOp =
MI.getOperand(getVLOpNum(
MI));
1017 const unsigned VLMAX = computeVLMAX(
ST->getRealMaxVLen(), SEW, VLMul);
1018 if (
ST->getRealMinVLen() ==
ST->getRealMaxVLen() && VLMAX <= 31)
1019 InstrInfo.setAVLImm(VLMAX);
1021 InstrInfo.setAVLVLMAX();
1024 InstrInfo.setAVLImm(Imm);
1027 InstrInfo.setAVLImm(1);
1029 VNInfo *VNI = getVNInfoFromReg(VLOp.
getReg(),
MI, LIS);
1030 InstrInfo.setAVLRegDef(VNI, VLOp.
getReg());
1033 assert(RISCVInstrInfo::isScalarExtractInstr(
MI) ||
1034 RISCVInstrInfo::isVExtractInstr(
MI));
1037 InstrInfo.setAVLImm(1);
1040 if (std::optional<unsigned> EEW = getEEWForLoadStore(
MI)) {
1041 assert(SEW == EEW &&
"Initial SEW doesn't match expected EEW");
1044 InstrInfo.setVTYPE(VLMul, SEW, TailAgnostic, MaskAgnostic);
1046 forwardVSETVLIAVL(InstrInfo);
1051void RISCVInsertVSETVLI::insertVSETVLI(MachineBasicBlock &
MBB,
1053 const VSETVLIInfo &
Info,
const VSETVLIInfo &PrevInfo) {
1055 ++NumInsertedVSETVL;
1056 if (PrevInfo.isValid() && !PrevInfo.isUnknown()) {
1059 if (
Info.hasSameAVL(PrevInfo) &&
Info.hasSameVLMAX(PrevInfo)) {
1073 if (
Info.hasSameVLMAX(PrevInfo) &&
Info.hasAVLReg()) {
1074 if (
const MachineInstr *
DefMI =
Info.getAVLDefMI(LIS);
1075 DefMI && RISCVInstrInfo::isVectorConfigInstr(*
DefMI)) {
1076 VSETVLIInfo DefInfo = getInfoForVSETVLI(*
DefMI);
1077 if (DefInfo.hasSameAVL(PrevInfo) && DefInfo.hasSameVLMAX(PrevInfo)) {
1092 if (
Info.hasAVLImm()) {
1102 if (
Info.hasAVLVLMAX()) {
1103 Register DestReg =
MRI->createVirtualRegister(&RISCV::GPRNoX0RegClass);
1116 MRI->constrainRegClass(AVLReg, &RISCV::GPRNoX0RegClass);
1125 const VNInfo *CurVNI =
Info.getAVLVNInfo();
1133 MRI->createVirtualRegister(&RISCV::GPRNoX0RegClass);
1146 MI->getOperand(1).setReg(AVLCopyReg);
1155bool RISCVInsertVSETVLI::needVSETVLI(
const DemandedFields &Used,
1156 const VSETVLIInfo &Require,
1157 const VSETVLIInfo &CurInfo)
const {
1158 if (!CurInfo.isValid() || CurInfo.isUnknown() || CurInfo.hasSEWLMULRatioOnly())
1161 if (CurInfo.isCompatible(Used, Require, LIS))
1171 const VSETVLIInfo &NewInfo,
1172 DemandedFields &Demanded) {
1173 VSETVLIInfo
Info = NewInfo;
1175 if (!Demanded.LMUL && !Demanded.SEWLMULRatio && PrevInfo.isValid() &&
1176 !PrevInfo.isUnknown()) {
1178 PrevInfo.getSEW(), PrevInfo.getVLMUL(),
Info.getSEW()))
1179 Info.setVLMul(*NewVLMul);
1180 Demanded.LMUL = DemandedFields::LMULEqual;
1189void RISCVInsertVSETVLI::transferBefore(VSETVLIInfo &
Info,
1190 const MachineInstr &
MI)
const {
1191 if (isVectorCopy(
ST->getRegisterInfo(),
MI) &&
1192 (
Info.isUnknown() || !
Info.isValid() ||
Info.hasSEWLMULRatioOnly())) {
1195 VSETVLIInfo NewInfo;
1196 NewInfo.setAVLImm(1);
1205 DemandedFields Demanded = getDemanded(
MI, ST);
1207 const VSETVLIInfo NewInfo = computeInfoForInstr(
MI);
1208 assert(NewInfo.isValid() && !NewInfo.isUnknown());
1209 if (
Info.isValid() && !needVSETVLI(Demanded, NewInfo,
Info))
1212 const VSETVLIInfo PrevInfo =
Info;
1213 if (!
Info.isValid() ||
Info.isUnknown())
1216 const VSETVLIInfo IncomingInfo =
adjustIncoming(PrevInfo, NewInfo, Demanded);
1225 bool EquallyZero = IncomingInfo.hasEquallyZeroAVL(PrevInfo, LIS) &&
1226 IncomingInfo.hasSameVLMAX(PrevInfo);
1227 if (Demanded.VLAny || (Demanded.VLZeroness && !EquallyZero))
1228 Info.setAVL(IncomingInfo);
1231 ((Demanded.LMUL || Demanded.SEWLMULRatio) ? IncomingInfo :
Info)
1233 ((Demanded.SEW || Demanded.SEWLMULRatio) ? IncomingInfo :
Info).getSEW(),
1236 (Demanded.TailPolicy ? IncomingInfo :
Info).getTailAgnostic() ||
1237 IncomingInfo.getTailAgnostic(),
1238 (Demanded.MaskPolicy ? IncomingInfo :
Info).getMaskAgnostic() ||
1239 IncomingInfo.getMaskAgnostic());
1243 if (
Info.hasSEWLMULRatioOnly()) {
1244 VSETVLIInfo RatiolessInfo = IncomingInfo;
1245 RatiolessInfo.setAVL(
Info);
1246 Info = RatiolessInfo;
1253void RISCVInsertVSETVLI::transferAfter(VSETVLIInfo &
Info,
1254 const MachineInstr &
MI)
const {
1255 if (RISCVInstrInfo::isVectorConfigInstr(
MI)) {
1256 Info = getInfoForVSETVLI(
MI);
1260 if (RISCVInstrInfo::isFaultOnlyFirstLoad(
MI)) {
1262 assert(
MI.getOperand(1).getReg().isVirtual());
1268 Info.setAVLRegDef(VNI,
MI.getOperand(1).getReg());
1270 Info.setAVLRegDef(
nullptr,
MI.getOperand(1).getReg());
1276 if (
MI.isCall() ||
MI.isInlineAsm() ||
1277 MI.modifiesRegister(RISCV::VL,
nullptr) ||
1278 MI.modifiesRegister(RISCV::VTYPE,
nullptr))
1279 Info = VSETVLIInfo::getUnknown();
1282bool RISCVInsertVSETVLI::computeVLVTYPEChanges(
const MachineBasicBlock &
MBB,
1283 VSETVLIInfo &
Info)
const {
1284 bool HadVectorOp =
false;
1287 for (
const MachineInstr &
MI :
MBB) {
1288 transferBefore(
Info,
MI);
1290 if (RISCVInstrInfo::isVectorConfigInstr(
MI) ||
1292 isVectorCopy(
ST->getRegisterInfo(),
MI))
1301void RISCVInsertVSETVLI::computeIncomingVLVTYPE(
const MachineBasicBlock &
MBB) {
1305 BBInfo.InQueue =
false;
1309 VSETVLIInfo InInfo = BBInfo.
Pred;
1312 InInfo.setUnknown();
1315 InInfo = InInfo.intersect(BlockInfo[
P->getNumber()].Exit);
1319 if (!InInfo.isValid())
1323 if (InInfo == BBInfo.
Pred)
1326 BBInfo.
Pred = InInfo;
1328 <<
" changed to " << BBInfo.
Pred <<
"\n");
1334 VSETVLIInfo TmpStatus;
1335 computeVLVTYPEChanges(
MBB, TmpStatus);
1339 if (BBInfo.
Exit == TmpStatus)
1342 BBInfo.
Exit = TmpStatus;
1344 <<
" changed to " << BBInfo.
Exit <<
"\n");
1349 if (!BlockInfo[S->getNumber()].InQueue) {
1350 BlockInfo[S->getNumber()].InQueue =
true;
1358bool RISCVInsertVSETVLI::needVSETVLIPHI(
const VSETVLIInfo &Require,
1359 const MachineBasicBlock &
MBB)
const {
1360 if (!Require.hasAVLReg())
1367 const VNInfo *Valno = Require.getAVLVNInfo();
1374 const VSETVLIInfo &PBBExit = BlockInfo[PBB->getNumber()].Exit;
1381 if (!
DefMI || !RISCVInstrInfo::isVectorConfigInstr(*
DefMI))
1386 VSETVLIInfo DefInfo = getInfoForVSETVLI(*
DefMI);
1387 if (DefInfo != PBBExit)
1393 if (PBBExit.isUnknown() || !PBBExit.hasSameVTYPE(Require))
1402void RISCVInsertVSETVLI::emitVSETVLIs(MachineBasicBlock &
MBB) {
1406 bool PrefixTransparent =
true;
1407 for (MachineInstr &
MI :
MBB) {
1408 const VSETVLIInfo PrevInfo = CurInfo;
1409 transferBefore(CurInfo,
MI);
1412 if (RISCVInstrInfo::isVectorConfigInstr(
MI)) {
1414 assert(
MI.getOperand(3).getReg() == RISCV::VL &&
1415 MI.getOperand(4).getReg() == RISCV::VTYPE &&
1416 "Unexpected operands where VL and VTYPE should be");
1417 MI.getOperand(3).setIsDead(
false);
1418 MI.getOperand(4).setIsDead(
false);
1419 PrefixTransparent =
false;
1423 isVectorCopy(
ST->getRegisterInfo(),
MI)) {
1424 if (!PrevInfo.isCompatible(DemandedFields::all(), CurInfo, LIS)) {
1425 insertVSETVLI(
MBB,
MI,
MI.getDebugLoc(), CurInfo, PrevInfo);
1426 PrefixTransparent =
false;
1432 uint64_t TSFlags =
MI.getDesc().TSFlags;
1434 if (!PrevInfo.isCompatible(DemandedFields::all(), CurInfo, LIS)) {
1442 if (!PrefixTransparent || needVSETVLIPHI(CurInfo,
MBB))
1443 insertVSETVLI(
MBB,
MI,
MI.getDebugLoc(), CurInfo, PrevInfo);
1444 PrefixTransparent =
false;
1448 MachineOperand &VLOp =
MI.getOperand(getVLOpNum(
MI));
1453 VLOp.
setReg(RISCV::NoRegister);
1468 for (MachineInstr *DeadMI : DeadMIs) {
1469 if (!
TII->isAddImmediate(*DeadMI,
Reg))
1472 DeadMI->eraseFromParent();
1483 if (
MI.isInlineAsm()) {
1490 if (
MI.isCall() ||
MI.isInlineAsm() ||
1491 MI.modifiesRegister(RISCV::VL,
nullptr) ||
1492 MI.modifiesRegister(RISCV::VTYPE,
nullptr))
1493 PrefixTransparent =
false;
1495 transferAfter(CurInfo,
MI);
1499 if (CurInfo !=
Info.Exit) {
1505 assert(CurInfo ==
Info.Exit &&
"InsertVSETVLI dataflow invariant violated");
1513void RISCVInsertVSETVLI::doPRE(MachineBasicBlock &
MBB) {
1517 MachineBasicBlock *UnavailablePred =
nullptr;
1518 VSETVLIInfo AvailableInfo;
1520 const VSETVLIInfo &PredInfo = BlockInfo[
P->getNumber()].Exit;
1521 if (PredInfo.isUnknown()) {
1522 if (UnavailablePred)
1524 UnavailablePred =
P;
1525 }
else if (!AvailableInfo.isValid()) {
1526 AvailableInfo = PredInfo;
1527 }
else if (AvailableInfo != PredInfo) {
1534 if (!UnavailablePred || !AvailableInfo.isValid())
1542 if (AvailableInfo.hasSEWLMULRatioOnly())
1552 if (AvailableInfo.hasAVLReg()) {
1553 SlotIndex
SI = AvailableInfo.getAVLVNInfo()->def;
1572 VSETVLIInfo CurInfo = AvailableInfo;
1573 int TransitionsRemoved = 0;
1574 for (
const MachineInstr &
MI :
MBB) {
1575 const VSETVLIInfo LastInfo = CurInfo;
1576 const VSETVLIInfo LastOldInfo = OldInfo;
1577 transferBefore(CurInfo,
MI);
1578 transferBefore(OldInfo,
MI);
1579 if (CurInfo == LastInfo)
1580 TransitionsRemoved++;
1581 if (LastOldInfo == OldInfo)
1582 TransitionsRemoved--;
1583 transferAfter(CurInfo,
MI);
1584 transferAfter(OldInfo,
MI);
1585 if (CurInfo == OldInfo)
1589 if (CurInfo != OldInfo || TransitionsRemoved <= 0)
1596 auto OldExit = BlockInfo[UnavailablePred->
getNumber()].Exit;
1598 << UnavailablePred->
getName() <<
" with state "
1599 << AvailableInfo <<
"\n");
1600 BlockInfo[UnavailablePred->
getNumber()].Exit = AvailableInfo;
1606 insertVSETVLI(*UnavailablePred, InsertPt,
1608 AvailableInfo, OldExit);
1613bool RISCVInsertVSETVLI::canMutatePriorConfig(
1614 const MachineInstr &PrevMI,
const MachineInstr &
MI,
1615 const DemandedFields &Used)
const {
1619 if (!RISCVInstrInfo::isVLPreservingConfig(
MI)) {
1623 if (
Used.VLZeroness) {
1624 if (RISCVInstrInfo::isVLPreservingConfig(PrevMI))
1626 if (!getInfoForVSETVLI(PrevMI).hasEquallyZeroAVL(getInfoForVSETVLI(
MI),
1631 auto &AVL =
MI.getOperand(1);
1635 if (AVL.isReg() && AVL.getReg() != RISCV::X0) {
1636 VNInfo *VNI = getVNInfoFromReg(AVL.getReg(),
MI, LIS);
1637 VNInfo *PrevVNI = getVNInfoFromReg(AVL.getReg(), PrevMI, LIS);
1638 if (!VNI || !PrevVNI || VNI != PrevVNI)
1645 auto VType =
MI.getOperand(2).getImm();
1646 return areCompatibleVTYPEs(PriorVType, VType, Used);
1649void RISCVInsertVSETVLI::coalesceVSETVLIs(MachineBasicBlock &
MBB)
const {
1650 MachineInstr *NextMI =
nullptr;
1653 DemandedFields
Used;
1658 auto dropAVLUse = [&](MachineOperand &MO) {
1659 if (!MO.isReg() || !MO.getReg().isVirtual())
1662 MO.setReg(RISCV::NoRegister);
1667 MachineInstr *VLOpDef =
MRI->getUniqueVRegDef(OldVLReg);
1668 if (VLOpDef &&
TII->isAddImmediate(*VLOpDef, OldVLReg) &&
1669 MRI->use_nodbg_empty(OldVLReg))
1675 if (!RISCVInstrInfo::isVectorConfigInstr(
MI)) {
1676 Used.doUnion(getDemanded(
MI, ST));
1677 if (
MI.isCall() ||
MI.isInlineAsm() ||
1678 MI.modifiesRegister(RISCV::VL,
nullptr) ||
1679 MI.modifiesRegister(RISCV::VTYPE,
nullptr))
1684 if (!
MI.getOperand(0).isDead())
1688 if (!
Used.usedVL() && !
Used.usedVTYPE()) {
1689 dropAVLUse(
MI.getOperand(1));
1692 MI.eraseFromParent();
1693 NumCoalescedVSETVL++;
1698 if (canMutatePriorConfig(
MI, *NextMI, Used)) {
1699 if (!RISCVInstrInfo::isVLPreservingConfig(*NextMI)) {
1702 MI.getOperand(0).setReg(DefReg);
1703 MI.getOperand(0).setIsDead(
false);
1706 dropAVLUse(
MI.getOperand(1));
1719 SlotIndex NextMISlot =
1722 LiveInterval::Segment S(MISlot, NextMISlot, DefVNI);
1724 DefVNI->
def = MISlot;
1741 NumCoalescedVSETVL++;
1746 Used = getDemanded(
MI, ST);
1751 for (
auto *
MI : ToDelete) {
1756 MI->eraseFromParent();
1760void RISCVInsertVSETVLI::insertReadVL(MachineBasicBlock &
MBB) {
1762 MachineInstr &
MI = *
I++;
1763 if (RISCVInstrInfo::isFaultOnlyFirstLoad(
MI)) {
1764 Register VLOutput =
MI.getOperand(1).getReg();
1766 if (!
MI.getOperand(1).isDead()) {
1768 TII->get(RISCV::PseudoReadVL), VLOutput);
1771 SlotIndex NewDefSI =
1777 DefVNI->
def = NewDefSI;
1781 MI.getOperand(1).setReg(RISCV::X0);
1782 MI.addRegisterDefined(RISCV::VL,
MRI->getTargetRegisterInfo());
1787bool RISCVInsertVSETVLI::runOnMachineFunction(MachineFunction &MF) {
1790 if (!
ST->hasVInstructions())
1795 TII =
ST->getInstrInfo();
1797 auto *LISWrapper = getAnalysisIfAvailable<LiveIntervalsWrapperPass>();
1798 LIS = LISWrapper ? &LISWrapper->getLIS() :
nullptr;
1800 assert(BlockInfo.empty() &&
"Expect empty block infos");
1803 bool HaveVectorOp =
false;
1806 for (
const MachineBasicBlock &
MBB : MF) {
1807 VSETVLIInfo TmpStatus;
1808 HaveVectorOp |= computeVLVTYPEChanges(
MBB, TmpStatus);
1811 BBInfo.
Exit = TmpStatus;
1813 <<
" is " << BBInfo.
Exit <<
"\n");
1818 if (!HaveVectorOp) {
1826 for (
const MachineBasicBlock &
MBB : MF) {
1827 WorkList.push(&
MBB);
1830 while (!WorkList.empty()) {
1831 const MachineBasicBlock &
MBB = *WorkList.front();
1833 computeIncomingVLVTYPE(
MBB);
1837 for (MachineBasicBlock &
MBB : MF)
1844 for (MachineBasicBlock &
MBB : MF)
1857 coalesceVSETVLIs(*
MBB);
1861 for (MachineBasicBlock &
MBB : MF)
1865 return HaveVectorOp;
1870 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 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)