[llvm] [RISCV] Move performCombineVMergeAndVOps into RISCVFoldMasks (PR #71764)
Philip Reames via llvm-commits
llvm-commits at lists.llvm.org
Mon Nov 27 09:14:14 PST 2023
================
@@ -87,6 +97,258 @@ bool RISCVFoldMasks::isAllOnesMask(MachineInstr *MaskDef) {
}
}
+static unsigned getVMSetForLMul(RISCVII::VLMUL LMUL) {
+ switch (LMUL) {
+ case RISCVII::LMUL_F8:
+ return RISCV::PseudoVMSET_M_B1;
+ case RISCVII::LMUL_F4:
+ return RISCV::PseudoVMSET_M_B2;
+ case RISCVII::LMUL_F2:
+ return RISCV::PseudoVMSET_M_B4;
+ case RISCVII::LMUL_1:
+ return RISCV::PseudoVMSET_M_B8;
+ case RISCVII::LMUL_2:
+ return RISCV::PseudoVMSET_M_B16;
+ case RISCVII::LMUL_4:
+ return RISCV::PseudoVMSET_M_B32;
+ case RISCVII::LMUL_8:
+ return RISCV::PseudoVMSET_M_B64;
+ case RISCVII::LMUL_RESERVED:
+ llvm_unreachable("Unexpected LMUL");
+ }
+ llvm_unreachable("Unknown VLMUL enum");
+}
+
+// Returns true if LHS is the same register as RHS, or if LHS is undefined.
+bool RISCVFoldMasks::isOpSameAs(const MachineOperand &LHS,
+ const MachineOperand &RHS) {
+ if (LHS.getReg() == RISCV::NoRegister)
+ return true;
+ if (RHS.getReg() == RISCV::NoRegister)
+ return false;
+ return TRI->lookThruCopyLike(LHS.getReg(), MRI) ==
+ TRI->lookThruCopyLike(RHS.getReg(), MRI);
+}
+
+// Try to fold away VMERGE_VVM instructions. We handle these cases:
+// -Masked TU VMERGE_VVM combined with an unmasked TA instruction instruction
+// folds to a masked TU instruction. VMERGE_VVM must have have merge operand
+// same as false operand.
+// -Masked TA VMERGE_VVM combined with an unmasked TA instruction fold to a
+// masked TA instruction.
+// -Unmasked TU VMERGE_VVM combined with a masked MU TA instruction folds to
+// masked TU instruction. Both instructions must have the same merge operand.
+// VMERGE_VVM must have have merge operand same as false operand.
+// Note: The VMERGE_VVM forms above (TA, and TU) refer to the policy implied,
+// not the pseudo name. That is, a TA VMERGE_VVM can be either the _TU pseudo
+// form with an IMPLICIT_DEF passthrough operand or the unsuffixed (TA) pseudo
+// form.
+bool RISCVFoldMasks::foldVMergeIntoOps(MachineInstr &MI,
+ MachineInstr *MaskDef) {
+ MachineOperand *True;
+ MachineOperand *Merge;
+ MachineOperand *False;
+
+ const unsigned BaseOpc = RISCV::getRVVMCOpcode(MI.getOpcode());
+ // A vmv.v.v is equivalent to a vmerge with an all-ones mask.
+ if (BaseOpc == RISCV::VMV_V_V) {
+ Merge = &MI.getOperand(1);
+ False = &MI.getOperand(1);
+ True = &MI.getOperand(2);
+ } else if (BaseOpc == RISCV::VMERGE_VVM) {
+ Merge = &MI.getOperand(1);
+ False = &MI.getOperand(2);
+ True = &MI.getOperand(3);
+ } else
+ return false;
+
+ MachineInstr &TrueMI = *MRI->getVRegDef(True->getReg());
+
+ // We require that either merge and false are the same, or that merge
+ // is undefined.
+ if (!isOpSameAs(*Merge, *False))
+ return false;
+
+ // N must be the only user of True.
+ if (!MRI->hasOneUse(True->getReg()))
+ return false;
+
+ unsigned TrueOpc = TrueMI.getOpcode();
+ const MCInstrDesc &TrueMCID = TrueMI.getDesc();
+ bool HasTiedDest = RISCVII::isFirstDefTiedToFirstUse(TrueMCID);
+
+ bool IsMasked = false;
+ const RISCV::RISCVMaskedPseudoInfo *Info =
+ RISCV::lookupMaskedIntrinsicByUnmasked(TrueOpc);
+ if (!Info && HasTiedDest) {
+ Info = RISCV::getMaskedPseudoInfo(TrueOpc);
+ IsMasked = true;
+ }
+
+ if (!Info)
+ return false;
+
+ // When Mask is not a true mask, this transformation is illegal for some
+ // operations whose results are affected by mask, like viota.m.
+ if (Info->MaskAffectsResult && BaseOpc == RISCV::VMERGE_VVM &&
+ !isAllOnesMask(MaskDef))
+ return false;
+
+ MachineOperand &TrueMergeOp = TrueMI.getOperand(1);
+ if (HasTiedDest && TrueMergeOp.getReg() != RISCV::NoRegister) {
+ // The vmerge instruction must be TU.
+ // FIXME: This could be relaxed, but we need to handle the policy for the
+ // resulting op correctly.
+ if (Merge->getReg() == RISCV::NoRegister)
+ return false;
+ // Both the vmerge instruction and the True instruction must have the same
+ // merge operand.
+ if (!isOpSameAs(TrueMergeOp, *False))
+ return false;
+ }
+
+ if (IsMasked) {
+ assert(HasTiedDest && "Expected tied dest");
+ // The vmerge instruction must be TU.
+ if (Merge->getReg() == RISCV::NoRegister)
+ return false;
+ // The vmerge instruction must have an all 1s mask since we're going to keep
+ // the mask from the True instruction.
+ // FIXME: Support mask agnostic True instruction which would have an
+ // undef merge operand.
+ if (BaseOpc == RISCV::VMERGE_VVM && !isAllOnesMask(MaskDef))
+ return false;
+ }
+
+ // Skip if True has side effect.
+ // TODO: Support vleff and vlsegff.
+ if (TII->get(TrueOpc).hasUnmodeledSideEffects())
+ return false;
+
+ // The vector policy operand may be present for masked intrinsics
----------------
preames wrote:
Move this below the definition of the lambda so it's easier to find/follow.
https://github.com/llvm/llvm-project/pull/71764
More information about the llvm-commits
mailing list