diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h @@ -204,6 +204,17 @@ 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, diff --git a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp --- a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp +++ b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp @@ -3185,12 +3185,14 @@ // 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 Ops; // Skip the merge operand at index 0 if !UseTUPseudo. @@ -3244,15 +3246,14 @@ 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; } @@ -3260,7 +3261,7 @@ 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. @@ -3274,7 +3275,7 @@ } if (IsMasked) { - assert(HasMergeOp && "Expected merge op"); + assert(HasTiedDest && "Expected tied dest"); // The vmerge instruction must be TU. if (IsTA) return false; @@ -3333,10 +3334,14 @@ 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 Ops; if (IsMasked) { @@ -3346,7 +3351,7 @@ 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)});