return Desc.getNumOperands() - 1;
}
+// Is the first def operand tied to the first use operand. This is true for
+// vector pseudo instructions that have a merge operand for tail/mask
+// undisturbed. It's also true for vector FMA instructions where one of the
+// operands is also the destination register. This is different than
+// RISCVII::hasMergeOp which only indicates whether the tied operand from the
+// pseudoinstruction also exists on the MC layer instruction.
+static inline bool isFirstDefTiedToFirstUse(const MCInstrDesc &Desc) {
+ return Desc.getNumDefs() < Desc.getNumOperands() &&
+ Desc.getOperandConstraint(Desc.getNumDefs(), MCOI::TIED_TO) == 0;
+}
+
// RISC-V Specific Machine Operand Flags
enum {
MO_None = 0,
// Check that we're dropping the mask operand and any policy operand
// when we transform to this unmasked pseudo. Additionally, if this
// instruction is tail agnostic, the unmasked instruction should not have a
- // merge op.
- uint64_t TSFlags = TII.get(Opc).TSFlags;
- assert((UseTUPseudo == RISCVII::hasMergeOp(TSFlags)) &&
- RISCVII::hasDummyMaskOp(TSFlags) &&
+ // tied destination.
+#ifndef NDEBUG
+ const MCInstrDesc &MCID = TII.get(Opc);
+ uint64_t TSFlags = MCID.TSFlags;
+ bool HasTiedDest = RISCVII::isFirstDefTiedToFirstUse(MCID);
+ assert(UseTUPseudo == HasTiedDest && RISCVII::hasDummyMaskOp(TSFlags) &&
"Unexpected pseudo to transform to");
- (void)TSFlags;
+#endif
SmallVector<SDValue, 8> Ops;
// Skip the merge operand at index 0 if !UseTUPseudo.
return false;
unsigned TrueOpc = True.getMachineOpcode();
-
- // Skip if True has merge operand.
- uint64_t TrueTSFlags = TII->get(TrueOpc).TSFlags;
- bool HasMergeOp = RISCVII::hasMergeOp(TrueTSFlags);
+ const MCInstrDesc &TrueMCID = TII->get(TrueOpc);
+ uint64_t TrueTSFlags = TrueMCID.TSFlags;
+ bool HasTiedDest = RISCVII::isFirstDefTiedToFirstUse(TrueMCID);
bool IsMasked = false;
const RISCV::RISCVMaskedPseudoInfo *Info =
RISCV::lookupMaskedIntrinsicByUnmaskedTA(TrueOpc);
- if (!Info && HasMergeOp) {
+ if (!Info && HasTiedDest) {
Info = RISCV::getMaskedPseudoInfo(TrueOpc);
IsMasked = true;
}
if (!Info)
return false;
- if (HasMergeOp) {
+ if (HasTiedDest) {
// The vmerge instruction must be TU.
// FIXME: This could be relaxed, but we need to handle the policy for the
// resulting op correctly.
}
if (IsMasked) {
- assert(HasMergeOp && "Expected merge op");
+ assert(HasTiedDest && "Expected tied dest");
// The vmerge instruction must be TU.
if (IsTA)
return false;
SDLoc DL(N);
unsigned MaskedOpc = Info->MaskedPseudo;
- assert(RISCVII::hasVecPolicyOp(TII->get(MaskedOpc).TSFlags) &&
+#ifndef NDEBUG
+ const MCInstrDesc &MaskedMCID = TII->get(MaskedOpc);
+ assert(RISCVII::hasVecPolicyOp(MaskedMCID.TSFlags) &&
"Expected instructions with mask have policy operand.");
- assert(RISCVII::hasMergeOp(TII->get(MaskedOpc).TSFlags) &&
- "Expected instructions with mask have merge operand.");
+ assert(MaskedMCID.getOperandConstraint(MaskedMCID.getNumDefs(),
+ MCOI::TIED_TO) == 0 &&
+ "Expected instructions with mask have a tied dest.");
+#endif
SmallVector<SDValue, 8> Ops;
if (IsMasked) {
CurDAG->getTargetConstant(Policy, DL, Subtarget->getXLenVT()));
Ops.append(True->op_begin() + TrueVLIndex + 3, True->op_end());
} else {
- if (!HasMergeOp)
+ if (!HasTiedDest)
Ops.push_back(False);
Ops.append(True->op_begin(), True->op_begin() + TrueVLIndex);
Ops.append({Mask, VL, /* SEW */ True.getOperand(TrueVLIndex + 1)});