Skip to content

Commit 1b56b2b

Browse files
author
Yeting Kuo
committed
[RISCV] Transform VMERGE_VVM_<LMUL>_TU with all ones mask to VADD_VI_<LMUL>_TU.
The transformation is benefit because vmerge.vvm always needs mask operand but vadd.vi may not. Reviewed By: craig.topper Differential Revision: https://reviews.llvm.org/D133255
1 parent dd53a0b commit 1b56b2b

File tree

3 files changed

+251
-103
lines changed

3 files changed

+251
-103
lines changed

llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp

Lines changed: 156 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -2505,18 +2505,8 @@ bool RISCVDAGToDAGISel::doPeepholeSExtW(SDNode *N) {
25052505
return false;
25062506
}
25072507

2508-
// Optimize masked RVV pseudo instructions with a known all-ones mask to their
2509-
// corresponding "unmasked" pseudo versions. The mask we're interested in will
2510-
// take the form of a V0 physical register operand, with a glued
2511-
// register-setting instruction.
2512-
bool RISCVDAGToDAGISel::doPeepholeMaskedRVV(SDNode *N) {
2513-
const RISCV::RISCVMaskedPseudoInfo *I =
2514-
RISCV::getMaskedPseudoInfo(N->getMachineOpcode());
2515-
if (!I)
2516-
return false;
2517-
2518-
unsigned MaskOpIdx = I->MaskOpIdx;
2519-
2508+
// Return true if we can make sure mask of N is all-ones mask.
2509+
static bool usesAllOnesMask(SDNode *N, unsigned MaskOpIdx) {
25202510
// Check that we're using V0 as a mask register.
25212511
if (!isa<RegisterSDNode>(N->getOperand(MaskOpIdx)) ||
25222512
cast<RegisterSDNode>(N->getOperand(MaskOpIdx))->getReg() != RISCV::V0)
@@ -2546,7 +2536,23 @@ bool RISCVDAGToDAGISel::doPeepholeMaskedRVV(SDNode *N) {
25462536
// TODO: Check that the VMSET is the expected bitwidth? The pseudo has
25472537
// undefined behaviour if it's the wrong bitwidth, so we could choose to
25482538
// assume that it's all-ones? Same applies to its VL.
2549-
if (!MaskSetter->isMachineOpcode() || !IsVMSet(MaskSetter.getMachineOpcode()))
2539+
return MaskSetter->isMachineOpcode() &&
2540+
IsVMSet(MaskSetter.getMachineOpcode());
2541+
}
2542+
2543+
// Optimize masked RVV pseudo instructions with a known all-ones mask to their
2544+
// corresponding "unmasked" pseudo versions. The mask we're interested in will
2545+
// take the form of a V0 physical register operand, with a glued
2546+
// register-setting instruction.
2547+
bool RISCVDAGToDAGISel::doPeepholeMaskedRVV(SDNode *N) {
2548+
const RISCV::RISCVMaskedPseudoInfo *I =
2549+
RISCV::getMaskedPseudoInfo(N->getMachineOpcode());
2550+
if (!I)
2551+
return false;
2552+
2553+
unsigned MaskOpIdx = I->MaskOpIdx;
2554+
2555+
if (!usesAllOnesMask(N, MaskOpIdx))
25502556
return false;
25512557

25522558
// Retrieve the tail policy operand index, if any.
@@ -2600,6 +2606,7 @@ bool RISCVDAGToDAGISel::doPeepholeMaskedRVV(SDNode *N) {
26002606
}
26012607

26022608
// Transitively apply any node glued to our new node.
2609+
const auto *Glued = N->getGluedNode();
26032610
if (auto *TGlued = Glued->getGluedNode())
26042611
Ops.push_back(SDValue(TGlued, TGlued->getNumValues() - 1));
26052612

@@ -2614,121 +2621,167 @@ bool RISCVDAGToDAGISel::doPeepholeMaskedRVV(SDNode *N) {
26142621
// peephole only deals with VMERGE_VVM which is TU and has false operand same as
26152622
// its true operand now. E.g. (VMERGE_VVM_M1_TU False, False, (VADD_M1 ...),
26162623
// ...) -> (VADD_VV_M1_MASK)
2617-
bool RISCVDAGToDAGISel::doPeepholeMergeVVMFold() {
2618-
bool MadeChange = false;
2619-
SelectionDAG::allnodes_iterator Position = CurDAG->allnodes_end();
2624+
bool RISCVDAGToDAGISel::performCombineVMergeAndVOps(SDNode *N) {
2625+
SDValue Merge = N->getOperand(0);
2626+
SDValue True = N->getOperand(2);
2627+
SDValue Mask = N->getOperand(3);
2628+
SDValue VL = N->getOperand(4);
26202629

2621-
while (Position != CurDAG->allnodes_begin()) {
2622-
SDNode *N = &*--Position;
2623-
if (N->use_empty() || !N->isMachineOpcode())
2624-
continue;
2630+
assert(True.getResNo() == 0 &&
2631+
"Expect True is the first output of an instruction.");
26252632

2626-
auto IsVMergeTU = [](unsigned Opcode) {
2627-
return Opcode == RISCV::PseudoVMERGE_VVM_MF8_TU ||
2628-
Opcode == RISCV::PseudoVMERGE_VVM_MF4_TU ||
2629-
Opcode == RISCV::PseudoVMERGE_VVM_MF2_TU ||
2630-
Opcode == RISCV::PseudoVMERGE_VVM_M1_TU ||
2631-
Opcode == RISCV::PseudoVMERGE_VVM_M2_TU ||
2632-
Opcode == RISCV::PseudoVMERGE_VVM_M4_TU ||
2633-
Opcode == RISCV::PseudoVMERGE_VVM_M8_TU;
2634-
};
2633+
// Need N is the exactly one using True.
2634+
if (!True.hasOneUse())
2635+
return false;
26352636

2636-
unsigned Opc = N->getMachineOpcode();
2637-
// TODO: Also deal with TA VMerge nodes.
2638-
if (!IsVMergeTU(Opc))
2639-
continue;
2637+
if (!True.isMachineOpcode())
2638+
return false;
26402639

2641-
SDValue Merge = N->getOperand(0);
2642-
SDValue False = N->getOperand(1);
2643-
SDValue True = N->getOperand(2);
2644-
SDValue Mask = N->getOperand(3);
2645-
SDValue VL = N->getOperand(4);
2640+
unsigned TrueOpc = True.getMachineOpcode();
26462641

2647-
if (Merge != False)
2648-
continue;
2642+
// Skip if True has merge operand.
2643+
// TODO: Deal with True having same merge operand with N.
2644+
if (RISCVII::hasMergeOp(TII->get(TrueOpc).TSFlags))
2645+
return false;
26492646

2650-
assert(True.getResNo() == 0 &&
2651-
"Expect True is the first output of an instruction.");
2647+
// Skip if True has side effect.
2648+
// TODO: Support velff and vlsegff.
2649+
if (TII->get(TrueOpc).hasUnmodeledSideEffects())
2650+
return false;
26522651

2653-
// Need N is the exactly one using True.
2654-
if (!True.hasOneUse())
2655-
continue;
2652+
// Only deal with True when True is unmasked intrinsic now.
2653+
const RISCV::RISCVMaskedPseudoInfo *Info =
2654+
RISCV::lookupMaskedIntrinsicByUnmaskedTA(TrueOpc);
26562655

2657-
if (!True.isMachineOpcode())
2658-
continue;
2656+
if (!Info)
2657+
return false;
26592658

2660-
unsigned TrueOpc = True.getMachineOpcode();
2659+
// The last operand of unmasked intrinsic should be sew or chain.
2660+
bool HasChainOp =
2661+
True.getOperand(True.getNumOperands() - 1).getValueType() == MVT::Other;
26612662

2662-
// Skip if True has merge operand.
2663-
// TODO: Deal with True having same merge operand with N.
2664-
if (RISCVII::hasMergeOp(TII->get(TrueOpc).TSFlags))
2665-
continue;
2663+
// Need True has same VL with N.
2664+
unsigned TrueVLIndex = True.getNumOperands() - HasChainOp - 2;
2665+
SDValue TrueVL = True.getOperand(TrueVLIndex);
26662666

2667-
// Skip if True has side effect.
2668-
// TODO: Support velff and vlsegff.
2669-
if (TII->get(TrueOpc).hasUnmodeledSideEffects())
2670-
continue;
2667+
auto IsNoFPExcept = [this](SDValue N) {
2668+
return !this->mayRaiseFPException(N.getNode()) ||
2669+
N->getFlags().hasNoFPExcept();
2670+
};
26712671

2672-
// Only deal with True when True is unmasked intrinsic now.
2673-
const RISCV::RISCVMaskedPseudoInfo *Info =
2674-
RISCV::lookupMaskedIntrinsicByUnmaskedTA(TrueOpc);
2672+
// Allow the peephole for non-exception True with VLMAX vector length, since
2673+
// all the values after VL of N are dependent on Merge. VLMAX should be
2674+
// lowered to (XLenVT -1).
2675+
if (TrueVL != VL && !(IsNoFPExcept(True) && isAllOnesConstant(TrueVL)))
2676+
return false;
26752677

2676-
if (!Info)
2677-
continue;
2678+
SDLoc DL(N);
2679+
unsigned MaskedOpc = Info->MaskedPseudo;
2680+
assert(RISCVII::hasVecPolicyOp(TII->get(MaskedOpc).TSFlags) &&
2681+
"Expected instructions with mask have policy operand.");
26782682

2679-
// The last operand of unmasked intrinsic should be sew or chain.
2680-
bool HasChainOp =
2681-
True.getOperand(True.getNumOperands() - 1).getValueType() == MVT::Other;
2683+
SmallVector<SDValue, 8> Ops;
2684+
Ops.push_back(Merge);
2685+
Ops.append(True->op_begin(), True->op_begin() + TrueVLIndex);
2686+
Ops.append({Mask, VL, /* SEW */ True.getOperand(TrueVLIndex + 1)});
2687+
Ops.push_back(
2688+
CurDAG->getTargetConstant(/* TUMU */ 0, DL, Subtarget->getXLenVT()));
26822689

2683-
// Need True has same VL with N.
2684-
unsigned TrueVLIndex = True.getNumOperands() - HasChainOp - 2;
2685-
SDValue TrueVL = True.getOperand(TrueVLIndex);
2690+
// Result node should have chain operand of True.
2691+
if (HasChainOp)
2692+
Ops.push_back(True.getOperand(True.getNumOperands() - 1));
26862693

2687-
auto IsNoFPExcept = [this](SDValue N) {
2688-
return !this->mayRaiseFPException(N.getNode()) ||
2689-
N->getFlags().hasNoFPExcept();
2690-
};
2694+
// Result node should take over glued node of N.
2695+
if (N->getGluedNode())
2696+
Ops.push_back(N->getOperand(N->getNumOperands() - 1));
26912697

2692-
// Allow the peephole for non-exception True with VLMAX vector length, since
2693-
// all the values after VL of N are dependent on Merge. VLMAX should be
2694-
// lowered to (XLenVT -1).
2695-
if (TrueVL != VL && !(IsNoFPExcept(True) && isAllOnesConstant(TrueVL)))
2696-
continue;
2698+
SDNode *Result =
2699+
CurDAG->getMachineNode(MaskedOpc, DL, True->getVTList(), Ops);
2700+
Result->setFlags(True->getFlags());
26972701

2698-
SDLoc DL(N);
2699-
unsigned MaskedOpc = Info->MaskedPseudo;
2700-
assert(RISCVII::hasVecPolicyOp(TII->get(MaskedOpc).TSFlags) &&
2701-
"Expected instructions with mask have policy operand.");
2702+
// Replace vmerge.vvm node by Result.
2703+
ReplaceUses(SDValue(N, 0), SDValue(Result, 0));
27022704

2703-
SmallVector<SDValue, 8> Ops;
2704-
Ops.push_back(Merge);
2705-
Ops.append(True->op_begin(), True->op_begin() + TrueVLIndex);
2706-
Ops.append({Mask, VL, /* SEW */ True.getOperand(TrueVLIndex + 1)});
2707-
Ops.push_back(
2708-
CurDAG->getTargetConstant(/* TUMU */ 0, DL, Subtarget->getXLenVT()));
2705+
// Replace another value of True. E.g. chain and VL.
2706+
for (unsigned Idx = 1; Idx < True->getNumValues(); ++Idx)
2707+
ReplaceUses(True.getValue(Idx), SDValue(Result, Idx));
27092708

2710-
// Result node should have chain operand of True.
2711-
if (HasChainOp)
2712-
Ops.push_back(True.getOperand(True.getNumOperands() - 1));
2709+
// Try to transform Result to unmasked intrinsic.
2710+
doPeepholeMaskedRVV(Result);
2711+
return true;
2712+
}
27132713

2714-
// Result node should take over glued node of N.
2715-
if (N->getGluedNode())
2716-
Ops.push_back(N->getOperand(N->getNumOperands() - 1));
2714+
// Transform (VMERGE_VVM_<LMUL>_TU false, false, true, allones, vl, sew) to
2715+
// (VADD_VI_<LMUL>_TU false, true, 0, vl, sew). It may decrease uses of VMSET.
2716+
bool RISCVDAGToDAGISel::performVMergeToVAdd(SDNode *N) {
2717+
unsigned NewOpc;
2718+
switch (N->getMachineOpcode()) {
2719+
default:
2720+
llvm_unreachable("Expected VMERGE_VVM_<LMUL>_TU instruction.");
2721+
case RISCV::PseudoVMERGE_VVM_MF8_TU:
2722+
NewOpc = RISCV::PseudoVADD_VI_MF8_TU;
2723+
break;
2724+
case RISCV::PseudoVMERGE_VVM_MF4_TU:
2725+
NewOpc = RISCV::PseudoVADD_VI_MF4_TU;
2726+
break;
2727+
case RISCV::PseudoVMERGE_VVM_MF2_TU:
2728+
NewOpc = RISCV::PseudoVADD_VI_MF2_TU;
2729+
break;
2730+
case RISCV::PseudoVMERGE_VVM_M1_TU:
2731+
NewOpc = RISCV::PseudoVADD_VI_M1_TU;
2732+
break;
2733+
case RISCV::PseudoVMERGE_VVM_M2_TU:
2734+
NewOpc = RISCV::PseudoVADD_VI_M2_TU;
2735+
break;
2736+
case RISCV::PseudoVMERGE_VVM_M4_TU:
2737+
NewOpc = RISCV::PseudoVADD_VI_M4_TU;
2738+
break;
2739+
case RISCV::PseudoVMERGE_VVM_M8_TU:
2740+
NewOpc = RISCV::PseudoVADD_VI_M8_TU;
2741+
break;
2742+
}
27172743

2718-
SDNode *Result =
2719-
CurDAG->getMachineNode(MaskedOpc, DL, True->getVTList(), Ops);
2720-
Result->setFlags(True->getFlags());
2744+
if (!usesAllOnesMask(N, /* MaskOpIdx */ 3))
2745+
return false;
27212746

2722-
// Replace vmerge.vvm node by Result.
2723-
ReplaceUses(SDValue(N, 0), SDValue(Result, 0));
2747+
SDLoc DL(N);
2748+
EVT VT = N->getValueType(0);
2749+
SDValue Ops[] = {N->getOperand(1), N->getOperand(2),
2750+
CurDAG->getTargetConstant(0, DL, Subtarget->getXLenVT()),
2751+
N->getOperand(4), N->getOperand(5)};
2752+
SDNode *Result = CurDAG->getMachineNode(NewOpc, DL, VT, Ops);
2753+
ReplaceUses(N, Result);
2754+
return true;
2755+
}
2756+
2757+
bool RISCVDAGToDAGISel::doPeepholeMergeVVMFold() {
2758+
bool MadeChange = false;
2759+
SelectionDAG::allnodes_iterator Position = CurDAG->allnodes_end();
27242760

2725-
// Replace another value of True. E.g. chain and VL.
2726-
for (unsigned Idx = 1; Idx < True->getNumValues(); ++Idx)
2727-
ReplaceUses(True.getValue(Idx), SDValue(Result, Idx));
2761+
while (Position != CurDAG->allnodes_begin()) {
2762+
SDNode *N = &*--Position;
2763+
if (N->use_empty() || !N->isMachineOpcode())
2764+
continue;
2765+
2766+
auto IsVMergeTU = [](unsigned Opcode) {
2767+
return Opcode == RISCV::PseudoVMERGE_VVM_MF8_TU ||
2768+
Opcode == RISCV::PseudoVMERGE_VVM_MF4_TU ||
2769+
Opcode == RISCV::PseudoVMERGE_VVM_MF2_TU ||
2770+
Opcode == RISCV::PseudoVMERGE_VVM_M1_TU ||
2771+
Opcode == RISCV::PseudoVMERGE_VVM_M2_TU ||
2772+
Opcode == RISCV::PseudoVMERGE_VVM_M4_TU ||
2773+
Opcode == RISCV::PseudoVMERGE_VVM_M8_TU;
2774+
};
2775+
2776+
unsigned Opc = N->getMachineOpcode();
2777+
// The following optimizations require that the merge operand of N is same
2778+
// as the false operand of N.
2779+
// TODO: Also deal with TA VMerge nodes.
2780+
if (!IsVMergeTU(Opc) || N->getOperand(0) != N->getOperand(1))
2781+
continue;
27282782

2729-
// Try to transform Result to unmasked intrinsic.
2730-
doPeepholeMaskedRVV(Result);
2731-
MadeChange = true;
2783+
MadeChange |= performCombineVMergeAndVOps(N);
2784+
MadeChange |= performVMergeToVAdd(N);
27322785
}
27332786
return MadeChange;
27342787
}

llvm/lib/Target/RISCV/RISCVISelDAGToDAG.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,8 @@ class RISCVDAGToDAGISel : public SelectionDAGISel {
133133
bool doPeepholeSExtW(SDNode *Node);
134134
bool doPeepholeMaskedRVV(SDNode *Node);
135135
bool doPeepholeMergeVVMFold();
136+
bool performVMergeToVAdd(SDNode *N);
137+
bool performCombineVMergeAndVOps(SDNode *N);
136138
};
137139

138140
namespace RISCV {

0 commit comments

Comments
 (0)