[llvm] [RISCV] Introduce VLOptimizer pass (PR #108640)
Craig Topper via llvm-commits
llvm-commits at lists.llvm.org
Wed Sep 18 14:01:21 PDT 2024
================
@@ -1467,97 +1458,116 @@ bool RISCVVLOptimizer::isCandidate(const MachineInstr &MI) const {
return false;
}
+ LLVM_DEBUG(dbgs() << " Found a candidate for VL reduction: " << MI << "\n");
return true;
}
+void RISCVVLOptimizer::checkUsers(std::optional<Register> &CommonVL,
+ bool &CanReduceVL, MachineInstr &MI) {
+ // FIXME: Avoid visiting each user for each time we visit something on the
+ // worklist, combined with an extra visit from the outer loop. Restructure
+ // along lines of an instcombine style worklist which integrates the outer
+ // pass.
+ for (auto &UserOp : MRI->use_operands(MI.getOperand(0).getReg())) {
+ const MachineInstr &UserMI = *UserOp.getParent();
+ LLVM_DEBUG(dbgs() << " Checking user: " << UserMI << "\n");
+
+ // Instructions like reductions may use a vector register as a scalar
+ // register. In this case, we should treat it like a scalar register which
+ // does not impact the decision on whether to optimize VL.
+ if (isVectorOpUsedAsScalarOp(UserOp)) {
+ [[maybe_unused]] Register R = UserOp.getReg();
+ [[maybe_unused]] const TargetRegisterClass *RC = MRI->getRegClass(R);
+ assert(RISCV::VRRegClass.hasSubClassEq(RC) &&
+ "Expect LMUL 1 register class for vector as scalar operands!");
+ LLVM_DEBUG(dbgs() << " Use this operand as a scalar operand\n");
+ continue;
+ }
+
+ if (mayReadPastVL(UserMI)) {
+ LLVM_DEBUG(dbgs() << " Abort because used by unsafe instruction\n");
+ CanReduceVL = false;
+ break;
+ }
+
+ // Tied operands might pass through.
+ if (UserOp.isTied()) {
+ LLVM_DEBUG(dbgs() << " Abort because user used as tied operand\n");
+ CanReduceVL = false;
+ break;
+ }
+
+ const MCInstrDesc &Desc = UserMI.getDesc();
+ if (!RISCVII::hasVLOp(Desc.TSFlags) || !RISCVII::hasSEWOp(Desc.TSFlags)) {
+ LLVM_DEBUG(dbgs() << " Abort due to lack of VL or SEW, assume that"
+ " use VLMAX\n");
+ CanReduceVL = false;
+ break;
+ }
+
+ unsigned VLOpNum = RISCVII::getVLOpNum(Desc);
+ const MachineOperand &VLOp = UserMI.getOperand(VLOpNum);
+ // Looking for a register VL that isn't X0.
+ if (!VLOp.isReg() || VLOp.getReg() == RISCV::X0) {
+ LLVM_DEBUG(dbgs() << " Abort due to user uses X0 as VL.\n");
+ CanReduceVL = false;
+ break;
+ }
+
+ if (!CommonVL) {
+ CommonVL = VLOp.getReg();
+ } else if (*CommonVL != VLOp.getReg()) {
+ LLVM_DEBUG(dbgs() << " Abort because users have different VL\n");
+ CanReduceVL = false;
+ break;
+ }
+
+ // The SEW and LMUL of destination and source registers need to match.
+
+ // We know that MI DEF is a vector register, because that was the guard
+ // to call this function.
+ assert(isVectorRegClass(UserMI.getOperand(0).getReg(), MRI) &&
+ "Expected DEF and USE to be vector registers");
+
+ OperandInfo ConsumerInfo = getOperandInfo(UserMI, UserOp, MRI);
+ OperandInfo ProducerInfo = getOperandInfo(MI, MI.getOperand(0), MRI);
+ if (ConsumerInfo.isUnknown() || ProducerInfo.isUnknown() ||
+ !OperandInfo::EMULAndEEWAreEqual(ConsumerInfo, ProducerInfo)) {
+ LLVM_DEBUG(dbgs() << " Abort due to incompatible or unknown "
+ "information for EMUL or EEW.\n");
+ LLVM_DEBUG(dbgs() << " ConsumerInfo is: " << ConsumerInfo << "\n");
+ LLVM_DEBUG(dbgs() << " ProducerInfo is: " << ProducerInfo << "\n");
+ CanReduceVL = false;
+ break;
+ }
+ }
+}
+
bool RISCVVLOptimizer::tryReduceVL(MachineInstr &OrigMI) {
SetVector<MachineInstr *> Worklist;
Worklist.insert(&OrigMI);
bool MadeChange = false;
while (!Worklist.empty()) {
MachineInstr &MI = *Worklist.pop_back_val();
- LLVM_DEBUG(dbgs() << "Try reduce VL for " << MI << "\n");
-
+ LLVM_DEBUG(dbgs() << "Trying to reduce VL for " << MI << "\n");
+
+ // A MI may not produce a vector register when it is at the root of the
+ // traversal. For example:
+ // vec_reg_a = ..., vl_op, sew_op
+ // vec_reg_a = ..., vl_op, sew_op
+ // scalar_reg = vector_instr vec_reg_a, vec_reg_b, vl_op, sew_op
+ // We'd like to reduce the vl_op on vector_instr, despite it producing
+ // a scalar register. If the produced Dest is not a vector register (such as
+ // vcpop or vfirst), then it has no EEW or EMUL, so there is no need to
+ // check that producer and consumer LMUL and SEW of usres match.
std::optional<Register> CommonVL;
bool CanReduceVL = true;
- for (auto &UserOp : MRI->use_operands(MI.getOperand(0).getReg())) {
- const MachineInstr &UserMI = *UserOp.getParent();
- LLVM_DEBUG(dbgs() << " Check user: " << UserMI << "\n");
-
- // Instructions like reductions may use a vector register as a scalar
- // register. In this case, we should treat it like a scalar register which
- // does not impact the decision on whether to optimize VL.
- if (isVectorOpUsedAsScalarOp(UserOp)) {
- [[maybe_unused]] Register R = UserOp.getReg();
- [[maybe_unused]] const TargetRegisterClass *RC = MRI->getRegClass(R);
- assert(RISCV::VRRegClass.hasSubClassEq(RC) &&
- "Expect LMUL 1 register class for vector as scalar operands!");
- LLVM_DEBUG(dbgs() << " Use this operand as a scalar operand\n");
- continue;
- }
-
- if (mayReadPastVL(UserMI)) {
- LLVM_DEBUG(dbgs() << " Abort due to used by unsafe instruction\n");
- CanReduceVL = false;
- break;
- }
-
- // Tied operands might pass through.
- if (UserOp.isTied()) {
- LLVM_DEBUG(dbgs() << " Abort due to user use it as tied operand\n");
- CanReduceVL = false;
- break;
- }
-
- const MCInstrDesc &Desc = UserMI.getDesc();
- if (!RISCVII::hasVLOp(Desc.TSFlags) || !RISCVII::hasSEWOp(Desc.TSFlags)) {
- LLVM_DEBUG(dbgs() << " Abort due to lack of VL or SEW, assume that"
- " use VLMAX.\n");
- CanReduceVL = false;
- break;
- }
-
- unsigned VLOpNum = RISCVII::getVLOpNum(Desc);
- const MachineOperand &VLOp = UserMI.getOperand(VLOpNum);
- // Looking for a register VL that isn't X0.
- if (!VLOp.isReg() || VLOp.getReg() == RISCV::X0) {
- LLVM_DEBUG(dbgs() << " Abort due to user use X0 as VL.\n");
- CanReduceVL = false;
- break;
- }
-
- if (!CommonVL) {
- CommonVL = VLOp.getReg();
- } else if (*CommonVL != VLOp.getReg()) {
- LLVM_DEBUG(dbgs() << " Abort due to users have different VL!\n");
- CanReduceVL = false;
- break;
- }
-
- // The SEW and LMUL of destination and source registers need to match.
-
- // If the produced Dest is not a vector register, then it has no EEW or
- // EMUL, so there is no need to check that producer and consumer LMUL and
- // SEW match. We've already checked above that UserOp is a vector
- // register.
- if (!isVectorRegClass(MI.getOperand(0).getReg(), MRI)) {
- LLVM_DEBUG(dbgs() << " Abort due to register class mismatch between "
- "USE and DEF\n");
- continue;
- }
-
- OperandInfo ConsumerInfo = getOperandInfo(UserMI, UserOp, MRI);
- OperandInfo ProducerInfo = getOperandInfo(MI, MI.getOperand(0), MRI);
- if (ConsumerInfo.isUnknown() || ProducerInfo.isUnknown() ||
- !OperandInfo::EMULAndEEWAreEqual(ConsumerInfo, ProducerInfo)) {
- LLVM_DEBUG(dbgs() << " Abort due to incompatible or unknown "
- "information for EMUL or EEW.\n");
- LLVM_DEBUG(dbgs() << " ConsumerInfo is: " << ConsumerInfo << "\n");
- LLVM_DEBUG(dbgs() << " ProducerInfo is: " << ProducerInfo << "\n");
- CanReduceVL = false;
- break;
- }
+ if (isVectorRegClass(MI.getOperand(0).getReg(), MRI))
+ checkUsers(CommonVL, CanReduceVL, MI);
+ else {
+ CommonVL = MI.getOperand(RISCVII::getVLOpNum(MI.getDesc())).getReg();
----------------
topperc wrote:
Won't this change the VL to its own VL? What's the point?
https://github.com/llvm/llvm-project/pull/108640
More information about the llvm-commits
mailing list