@@ -50,6 +50,7 @@ class RISCVVLOptimizer : public MachineFunctionPass {
5050 StringRef getPassName () const override { return PASS_NAME; }
5151
5252private:
53+ std::optional<const MachineOperand> getVLForUser (MachineOperand &UserOp);
5354 // / Returns the largest common VL MachineOperand that may be used to optimize
5455 // / MI. Returns std::nullopt if it failed to find a suitable VL.
5556 std::optional<const MachineOperand> checkUsers (MachineInstr &MI);
@@ -97,6 +98,8 @@ struct OperandInfo {
9798 OperandInfo (std::pair<unsigned , bool > EMUL, unsigned Log2EEW)
9899 : S(State::Known), EMUL(EMUL), Log2EEW(Log2EEW) {}
99100
101+ OperandInfo (unsigned Log2EEW) : S(State::Known), Log2EEW(Log2EEW) {}
102+
100103 OperandInfo () : S(State::Unknown) {}
101104
102105 bool isUnknown () const { return S == State::Unknown; }
@@ -109,6 +112,11 @@ struct OperandInfo {
109112 A.EMUL ->second == B.EMUL ->second ;
110113 }
111114
115+ static bool EEWAreEqual (const OperandInfo &A, const OperandInfo &B) {
116+ assert (A.isKnown () && B.isKnown () && " Both operands must be known" );
117+ return A.Log2EEW == B.Log2EEW ;
118+ }
119+
112120 void print (raw_ostream &OS) const {
113121 if (isUnknown ()) {
114122 OS << " Unknown" ;
@@ -720,8 +728,8 @@ static OperandInfo getOperandInfo(const MachineOperand &MO,
720728
721729 // Vector Reduction Operations
722730 // Vector Single-Width Integer Reduction Instructions
723- // The Dest and VS1 only read element 0 of the vector register. Return unknown
724- // for these. VS2 has EEW=SEW and EMUL=LMUL.
731+ // The Dest and VS1 only read element 0 of the vector register. Return just
732+ // the EEW for these. VS2 has EEW=SEW and EMUL=LMUL.
725733 case RISCV::VREDAND_VS:
726734 case RISCV::VREDMAX_VS:
727735 case RISCV::VREDMAXU_VS:
@@ -732,7 +740,7 @@ static OperandInfo getOperandInfo(const MachineOperand &MO,
732740 case RISCV::VREDXOR_VS: {
733741 if (MO.getOperandNo () == 2 )
734742 return OperandInfo (MIVLMul, MILog2SEW);
735- return {} ;
743+ return OperandInfo (MILog2SEW) ;
736744 }
737745
738746 default :
@@ -1047,48 +1055,64 @@ bool RISCVVLOptimizer::isCandidate(const MachineInstr &MI) const {
10471055 return true ;
10481056}
10491057
1058+ std::optional<const MachineOperand>
1059+ RISCVVLOptimizer::getVLForUser (MachineOperand &UserOp) {
1060+ const MachineInstr &UserMI = *UserOp.getParent ();
1061+ const MCInstrDesc &Desc = UserMI.getDesc ();
1062+
1063+ // Instructions like reductions may use a vector register as a scalar
1064+ // register. In this case, we should treat it like a scalar register which
1065+ // does not impact the decision on whether to optimize VL. But if there is
1066+ // another user of MI and it may have VL=0, we need to be sure not to reduce
1067+ // the VL of MI to zero when the VLOp of UserOp is may be non-zero. The most
1068+ // we can reduce it to is one.
1069+ if (isVectorOpUsedAsScalarOp (UserOp)) {
1070+ [[maybe_unused]] Register R = UserOp.getReg ();
1071+ [[maybe_unused]] const TargetRegisterClass *RC = MRI->getRegClass (R);
1072+ assert (RISCV::VRRegClass.hasSubClassEq (RC) &&
1073+ " Expect LMUL 1 register class for vector as scalar operands!" );
1074+ LLVM_DEBUG (dbgs () << " Used this operand as a scalar operand\n " );
1075+ // VMV_X_S and VFMV_F_S do not have a VL opt which would cause an assert
1076+ // assert failure if we called getVLOpNum. Therefore, we will set the
1077+ // CommonVL in that case as 1, even if it could have been set to 0.
1078+ if (!RISCVII::hasVLOp (Desc.TSFlags ) || !RISCVII::hasSEWOp (Desc.TSFlags ))
1079+ return MachineOperand::CreateImm (1 );
1080+
1081+ unsigned VLOpNum = RISCVII::getVLOpNum (Desc);
1082+ const MachineOperand &VLOp = UserMI.getOperand (VLOpNum);
1083+ if (VLOp.isReg () || (VLOp.isImm () && VLOp.getImm () != 0 ))
1084+ return MachineOperand::CreateImm (1 );
1085+ LLVM_DEBUG (dbgs () << " Abort because could not determine VL of vector "
1086+ " operand used as scalar operand\n " );
1087+
1088+ return std::nullopt ;
1089+ }
1090+
1091+ if (!RISCVII::hasVLOp (Desc.TSFlags ) || !RISCVII::hasSEWOp (Desc.TSFlags )) {
1092+ LLVM_DEBUG (dbgs () << " Abort due to lack of VL, assume that"
1093+ " use VLMAX\n " );
1094+ return std::nullopt ;
1095+ }
1096+
1097+ unsigned VLOpNum = RISCVII::getVLOpNum (Desc);
1098+ const MachineOperand &VLOp = UserMI.getOperand (VLOpNum);
1099+ // Looking for an immediate or a register VL that isn't X0.
1100+ assert ((!VLOp.isReg () || VLOp.getReg () != RISCV::X0) &&
1101+ " Did not expect X0 VL" );
1102+ return VLOp;
1103+ }
1104+
10501105std::optional<const MachineOperand>
10511106RISCVVLOptimizer::checkUsers (MachineInstr &MI) {
10521107 // FIXME: Avoid visiting each user for each time we visit something on the
10531108 // worklist, combined with an extra visit from the outer loop. Restructure
10541109 // along lines of an instcombine style worklist which integrates the outer
10551110 // pass.
10561111 bool CanReduceVL = true ;
1057- const MachineOperand *CommonVL = nullptr ;
1058- const MachineOperand One = MachineOperand::CreateImm (1 );
1112+ std::optional<const MachineOperand> CommonVL;
10591113 for (auto &UserOp : MRI->use_operands (MI.getOperand (0 ).getReg ())) {
10601114 const MachineInstr &UserMI = *UserOp.getParent ();
10611115 LLVM_DEBUG (dbgs () << " Checking user: " << UserMI << " \n " );
1062-
1063- // Instructions like reductions may use a vector register as a scalar
1064- // register. In this case, we should treat it like a scalar register which
1065- // does not impact the decision on whether to optimize VL. But if there is
1066- // another user of MI and it may have VL=0, we need to be sure not to reduce
1067- // the VL of MI to zero when the VLOp of UserOp is may be non-zero. The most
1068- // we can reduce it to is one.
1069- if (isVectorOpUsedAsScalarOp (UserOp)) {
1070- [[maybe_unused]] Register R = UserOp.getReg ();
1071- [[maybe_unused]] const TargetRegisterClass *RC = MRI->getRegClass (R);
1072- assert (RISCV::VRRegClass.hasSubClassEq (RC) &&
1073- " Expect LMUL 1 register class for vector as scalar operands!" );
1074- LLVM_DEBUG (dbgs () << " Used this operand as a scalar operand\n " );
1075- const MCInstrDesc &Desc = UserMI.getDesc ();
1076- // VMV_X_S and VFMV_F_S do not have a VL opt which would cause an assert
1077- // assert failure if we called getVLOpNum. Therefore, we will set the
1078- // CommonVL in that case as 1, even if it could have been set to 0.
1079- if (!RISCVII::hasVLOp (Desc.TSFlags ) || !RISCVII::hasSEWOp (Desc.TSFlags )) {
1080- CommonVL = &One;
1081- continue ;
1082- }
1083-
1084- unsigned VLOpNum = RISCVII::getVLOpNum (Desc);
1085- const MachineOperand &VLOp = UserMI.getOperand (VLOpNum);
1086- if (VLOp.isReg () || (VLOp.isImm () && VLOp.getImm () != 0 )) {
1087- CommonVL = &One;
1088- continue ;
1089- }
1090- }
1091-
10921116 if (mayReadPastVL (UserMI)) {
10931117 LLVM_DEBUG (dbgs () << " Abort because used by unsafe instruction\n " );
10941118 CanReduceVL = false ;
@@ -1102,45 +1126,55 @@ RISCVVLOptimizer::checkUsers(MachineInstr &MI) {
11021126 break ;
11031127 }
11041128
1105- const MCInstrDesc &Desc = UserMI.getDesc ();
1106- if (!RISCVII::hasVLOp (Desc.TSFlags ) || !RISCVII::hasSEWOp (Desc.TSFlags )) {
1107- LLVM_DEBUG (dbgs () << " Abort due to lack of VL or SEW, assume that"
1108- " use VLMAX\n " );
1129+ auto VLOp = getVLForUser (UserOp);
1130+ if (!VLOp) {
11091131 CanReduceVL = false ;
11101132 break ;
11111133 }
11121134
1113- unsigned VLOpNum = RISCVII::getVLOpNum (Desc);
1114- const MachineOperand &VLOp = UserMI.getOperand (VLOpNum);
1115-
1116- // Looking for an immediate or a register VL that isn't X0.
1117- assert ((!VLOp.isReg () || VLOp.getReg () != RISCV::X0) &&
1118- " Did not expect X0 VL" );
1119-
11201135 // Use the largest VL among all the users. If we cannot determine this
11211136 // statically, then we cannot optimize the VL.
1122- if (!CommonVL || RISCV::isVLKnownLE (*CommonVL, VLOp)) {
1123- CommonVL = & VLOp;
1137+ if (!CommonVL || RISCV::isVLKnownLE (*CommonVL, * VLOp)) {
1138+ CommonVL. emplace (* VLOp) ;
11241139 LLVM_DEBUG (dbgs () << " User VL is: " << VLOp << " \n " );
1125- } else if (!RISCV::isVLKnownLE (VLOp, *CommonVL)) {
1140+ } else if (!RISCV::isVLKnownLE (* VLOp, *CommonVL)) {
11261141 LLVM_DEBUG (dbgs () << " Abort because cannot determine a common VL\n " );
11271142 CanReduceVL = false ;
11281143 break ;
11291144 }
11301145
1131- // The SEW and LMUL of destination and source registers need to match.
1146+ if (!RISCVII::hasSEWOp (UserMI.getDesc ().TSFlags )) {
1147+ LLVM_DEBUG (dbgs () << " Abort due to lack of SEW operand\n " );
1148+ CanReduceVL = false ;
1149+ break ;
1150+ }
1151+
11321152 OperandInfo ConsumerInfo = getOperandInfo (UserOp, MRI);
11331153 OperandInfo ProducerInfo = getOperandInfo (MI.getOperand (0 ), MRI);
1134- if (ConsumerInfo.isUnknown () || ProducerInfo.isUnknown () ||
1135- !OperandInfo::EMULAndEEWAreEqual (ConsumerInfo, ProducerInfo)) {
1136- LLVM_DEBUG (dbgs () << " Abort due to incompatible or unknown "
1137- " information for EMUL or EEW.\n " );
1154+ if (ConsumerInfo.isUnknown () || ProducerInfo.isUnknown ()) {
1155+ LLVM_DEBUG (dbgs () << " Abort due to unknown operand information.\n " );
1156+ LLVM_DEBUG (dbgs () << " ConsumerInfo is: " << ConsumerInfo << " \n " );
1157+ LLVM_DEBUG (dbgs () << " ProducerInfo is: " << ProducerInfo << " \n " );
1158+ CanReduceVL = false ;
1159+ break ;
1160+ }
1161+
1162+ // If the operand is used as a scalar operand, then the EEW must be
1163+ // compatible. Otherwise, the EMUL *and* EEW must be compatible.
1164+ if ((isVectorOpUsedAsScalarOp (UserOp) &&
1165+ !OperandInfo::EEWAreEqual (ConsumerInfo, ProducerInfo)) ||
1166+ (!isVectorOpUsedAsScalarOp (UserOp) &&
1167+ !OperandInfo::EMULAndEEWAreEqual (ConsumerInfo, ProducerInfo))) {
1168+ LLVM_DEBUG (
1169+ dbgs ()
1170+ << " Abort due to incompatible information for EMUL or EEW.\n " );
11381171 LLVM_DEBUG (dbgs () << " ConsumerInfo is: " << ConsumerInfo << " \n " );
11391172 LLVM_DEBUG (dbgs () << " ProducerInfo is: " << ProducerInfo << " \n " );
11401173 CanReduceVL = false ;
11411174 break ;
11421175 }
11431176 }
1177+
11441178 return CanReduceVL && CommonVL
11451179 ? std::make_optional<const MachineOperand>(*CommonVL)
11461180 : std::nullopt ;
0 commit comments