1*0fca6ea1SDimitry Andric //===---------------- llvm/CodeGen/MatchContext.h --------------*- C++ -*-===// 2*0fca6ea1SDimitry Andric // 3*0fca6ea1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*0fca6ea1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*0fca6ea1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*0fca6ea1SDimitry Andric // 7*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===// 8*0fca6ea1SDimitry Andric // 9*0fca6ea1SDimitry Andric // This file declares the EmptyMatchContext class and VPMatchContext class. 10*0fca6ea1SDimitry Andric // 11*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===// 12*0fca6ea1SDimitry Andric 13*0fca6ea1SDimitry Andric #ifndef LLVM_LIB_CODEGEN_SELECTIONDAG_MATCHCONTEXT_H 14*0fca6ea1SDimitry Andric #define LLVM_LIB_CODEGEN_SELECTIONDAG_MATCHCONTEXT_H 15*0fca6ea1SDimitry Andric 16*0fca6ea1SDimitry Andric #include "llvm/CodeGen/SelectionDAG.h" 17*0fca6ea1SDimitry Andric #include "llvm/CodeGen/TargetLowering.h" 18*0fca6ea1SDimitry Andric 19*0fca6ea1SDimitry Andric using namespace llvm; 20*0fca6ea1SDimitry Andric 21*0fca6ea1SDimitry Andric namespace { 22*0fca6ea1SDimitry Andric class EmptyMatchContext { 23*0fca6ea1SDimitry Andric SelectionDAG &DAG; 24*0fca6ea1SDimitry Andric const TargetLowering &TLI; 25*0fca6ea1SDimitry Andric SDNode *Root; 26*0fca6ea1SDimitry Andric 27*0fca6ea1SDimitry Andric public: 28*0fca6ea1SDimitry Andric EmptyMatchContext(SelectionDAG &DAG, const TargetLowering &TLI, SDNode *Root) 29*0fca6ea1SDimitry Andric : DAG(DAG), TLI(TLI), Root(Root) {} 30*0fca6ea1SDimitry Andric 31*0fca6ea1SDimitry Andric unsigned getRootBaseOpcode() { return Root->getOpcode(); } 32*0fca6ea1SDimitry Andric bool match(SDValue OpN, unsigned Opcode) const { 33*0fca6ea1SDimitry Andric return Opcode == OpN->getOpcode(); 34*0fca6ea1SDimitry Andric } 35*0fca6ea1SDimitry Andric 36*0fca6ea1SDimitry Andric // Same as SelectionDAG::getNode(). 37*0fca6ea1SDimitry Andric template <typename... ArgT> SDValue getNode(ArgT &&...Args) { 38*0fca6ea1SDimitry Andric return DAG.getNode(std::forward<ArgT>(Args)...); 39*0fca6ea1SDimitry Andric } 40*0fca6ea1SDimitry Andric 41*0fca6ea1SDimitry Andric bool isOperationLegal(unsigned Op, EVT VT) const { 42*0fca6ea1SDimitry Andric return TLI.isOperationLegal(Op, VT); 43*0fca6ea1SDimitry Andric } 44*0fca6ea1SDimitry Andric 45*0fca6ea1SDimitry Andric bool isOperationLegalOrCustom(unsigned Op, EVT VT, 46*0fca6ea1SDimitry Andric bool LegalOnly = false) const { 47*0fca6ea1SDimitry Andric return TLI.isOperationLegalOrCustom(Op, VT, LegalOnly); 48*0fca6ea1SDimitry Andric } 49*0fca6ea1SDimitry Andric }; 50*0fca6ea1SDimitry Andric 51*0fca6ea1SDimitry Andric class VPMatchContext { 52*0fca6ea1SDimitry Andric SelectionDAG &DAG; 53*0fca6ea1SDimitry Andric const TargetLowering &TLI; 54*0fca6ea1SDimitry Andric SDValue RootMaskOp; 55*0fca6ea1SDimitry Andric SDValue RootVectorLenOp; 56*0fca6ea1SDimitry Andric SDNode *Root; 57*0fca6ea1SDimitry Andric 58*0fca6ea1SDimitry Andric public: 59*0fca6ea1SDimitry Andric VPMatchContext(SelectionDAG &DAG, const TargetLowering &TLI, SDNode *_Root) 60*0fca6ea1SDimitry Andric : DAG(DAG), TLI(TLI), RootMaskOp(), RootVectorLenOp() { 61*0fca6ea1SDimitry Andric Root = _Root; 62*0fca6ea1SDimitry Andric assert(Root->isVPOpcode()); 63*0fca6ea1SDimitry Andric if (auto RootMaskPos = ISD::getVPMaskIdx(Root->getOpcode())) 64*0fca6ea1SDimitry Andric RootMaskOp = Root->getOperand(*RootMaskPos); 65*0fca6ea1SDimitry Andric else if (Root->getOpcode() == ISD::VP_SELECT) 66*0fca6ea1SDimitry Andric RootMaskOp = DAG.getAllOnesConstant(SDLoc(Root), 67*0fca6ea1SDimitry Andric Root->getOperand(0).getValueType()); 68*0fca6ea1SDimitry Andric 69*0fca6ea1SDimitry Andric if (auto RootVLenPos = ISD::getVPExplicitVectorLengthIdx(Root->getOpcode())) 70*0fca6ea1SDimitry Andric RootVectorLenOp = Root->getOperand(*RootVLenPos); 71*0fca6ea1SDimitry Andric } 72*0fca6ea1SDimitry Andric 73*0fca6ea1SDimitry Andric unsigned getRootBaseOpcode() { 74*0fca6ea1SDimitry Andric std::optional<unsigned> Opcode = ISD::getBaseOpcodeForVP( 75*0fca6ea1SDimitry Andric Root->getOpcode(), !Root->getFlags().hasNoFPExcept()); 76*0fca6ea1SDimitry Andric assert(Opcode.has_value()); 77*0fca6ea1SDimitry Andric return *Opcode; 78*0fca6ea1SDimitry Andric } 79*0fca6ea1SDimitry Andric 80*0fca6ea1SDimitry Andric /// whether \p OpVal is a node that is functionally compatible with the 81*0fca6ea1SDimitry Andric /// NodeType \p Opc 82*0fca6ea1SDimitry Andric bool match(SDValue OpVal, unsigned Opc) const { 83*0fca6ea1SDimitry Andric if (!OpVal->isVPOpcode()) 84*0fca6ea1SDimitry Andric return OpVal->getOpcode() == Opc; 85*0fca6ea1SDimitry Andric 86*0fca6ea1SDimitry Andric auto BaseOpc = ISD::getBaseOpcodeForVP(OpVal->getOpcode(), 87*0fca6ea1SDimitry Andric !OpVal->getFlags().hasNoFPExcept()); 88*0fca6ea1SDimitry Andric if (BaseOpc != Opc) 89*0fca6ea1SDimitry Andric return false; 90*0fca6ea1SDimitry Andric 91*0fca6ea1SDimitry Andric // Make sure the mask of OpVal is true mask or is same as Root's. 92*0fca6ea1SDimitry Andric unsigned VPOpcode = OpVal->getOpcode(); 93*0fca6ea1SDimitry Andric if (auto MaskPos = ISD::getVPMaskIdx(VPOpcode)) { 94*0fca6ea1SDimitry Andric SDValue MaskOp = OpVal.getOperand(*MaskPos); 95*0fca6ea1SDimitry Andric if (RootMaskOp != MaskOp && 96*0fca6ea1SDimitry Andric !ISD::isConstantSplatVectorAllOnes(MaskOp.getNode())) 97*0fca6ea1SDimitry Andric return false; 98*0fca6ea1SDimitry Andric } 99*0fca6ea1SDimitry Andric 100*0fca6ea1SDimitry Andric // Make sure the EVL of OpVal is same as Root's. 101*0fca6ea1SDimitry Andric if (auto VLenPos = ISD::getVPExplicitVectorLengthIdx(VPOpcode)) 102*0fca6ea1SDimitry Andric if (RootVectorLenOp != OpVal.getOperand(*VLenPos)) 103*0fca6ea1SDimitry Andric return false; 104*0fca6ea1SDimitry Andric return true; 105*0fca6ea1SDimitry Andric } 106*0fca6ea1SDimitry Andric 107*0fca6ea1SDimitry Andric // Specialize based on number of operands. 108*0fca6ea1SDimitry Andric // TODO emit VP intrinsics where MaskOp/VectorLenOp != null 109*0fca6ea1SDimitry Andric // SDValue getNode(unsigned Opcode, const SDLoc &DL, EVT VT) { return 110*0fca6ea1SDimitry Andric // DAG.getNode(Opcode, DL, VT); } 111*0fca6ea1SDimitry Andric SDValue getNode(unsigned Opcode, const SDLoc &DL, EVT VT, SDValue Operand) { 112*0fca6ea1SDimitry Andric unsigned VPOpcode = ISD::getVPForBaseOpcode(Opcode); 113*0fca6ea1SDimitry Andric assert(ISD::getVPMaskIdx(VPOpcode) == 1 && 114*0fca6ea1SDimitry Andric ISD::getVPExplicitVectorLengthIdx(VPOpcode) == 2); 115*0fca6ea1SDimitry Andric return DAG.getNode(VPOpcode, DL, VT, 116*0fca6ea1SDimitry Andric {Operand, RootMaskOp, RootVectorLenOp}); 117*0fca6ea1SDimitry Andric } 118*0fca6ea1SDimitry Andric 119*0fca6ea1SDimitry Andric SDValue getNode(unsigned Opcode, const SDLoc &DL, EVT VT, SDValue N1, 120*0fca6ea1SDimitry Andric SDValue N2) { 121*0fca6ea1SDimitry Andric unsigned VPOpcode = ISD::getVPForBaseOpcode(Opcode); 122*0fca6ea1SDimitry Andric assert(ISD::getVPMaskIdx(VPOpcode) == 2 && 123*0fca6ea1SDimitry Andric ISD::getVPExplicitVectorLengthIdx(VPOpcode) == 3); 124*0fca6ea1SDimitry Andric return DAG.getNode(VPOpcode, DL, VT, {N1, N2, RootMaskOp, RootVectorLenOp}); 125*0fca6ea1SDimitry Andric } 126*0fca6ea1SDimitry Andric 127*0fca6ea1SDimitry Andric SDValue getNode(unsigned Opcode, const SDLoc &DL, EVT VT, SDValue N1, 128*0fca6ea1SDimitry Andric SDValue N2, SDValue N3) { 129*0fca6ea1SDimitry Andric unsigned VPOpcode = ISD::getVPForBaseOpcode(Opcode); 130*0fca6ea1SDimitry Andric assert(ISD::getVPMaskIdx(VPOpcode) == 3 && 131*0fca6ea1SDimitry Andric ISD::getVPExplicitVectorLengthIdx(VPOpcode) == 4); 132*0fca6ea1SDimitry Andric return DAG.getNode(VPOpcode, DL, VT, 133*0fca6ea1SDimitry Andric {N1, N2, N3, RootMaskOp, RootVectorLenOp}); 134*0fca6ea1SDimitry Andric } 135*0fca6ea1SDimitry Andric 136*0fca6ea1SDimitry Andric SDValue getNode(unsigned Opcode, const SDLoc &DL, EVT VT, SDValue Operand, 137*0fca6ea1SDimitry Andric SDNodeFlags Flags) { 138*0fca6ea1SDimitry Andric unsigned VPOpcode = ISD::getVPForBaseOpcode(Opcode); 139*0fca6ea1SDimitry Andric assert(ISD::getVPMaskIdx(VPOpcode) == 1 && 140*0fca6ea1SDimitry Andric ISD::getVPExplicitVectorLengthIdx(VPOpcode) == 2); 141*0fca6ea1SDimitry Andric return DAG.getNode(VPOpcode, DL, VT, {Operand, RootMaskOp, RootVectorLenOp}, 142*0fca6ea1SDimitry Andric Flags); 143*0fca6ea1SDimitry Andric } 144*0fca6ea1SDimitry Andric 145*0fca6ea1SDimitry Andric SDValue getNode(unsigned Opcode, const SDLoc &DL, EVT VT, SDValue N1, 146*0fca6ea1SDimitry Andric SDValue N2, SDNodeFlags Flags) { 147*0fca6ea1SDimitry Andric unsigned VPOpcode = ISD::getVPForBaseOpcode(Opcode); 148*0fca6ea1SDimitry Andric assert(ISD::getVPMaskIdx(VPOpcode) == 2 && 149*0fca6ea1SDimitry Andric ISD::getVPExplicitVectorLengthIdx(VPOpcode) == 3); 150*0fca6ea1SDimitry Andric return DAG.getNode(VPOpcode, DL, VT, {N1, N2, RootMaskOp, RootVectorLenOp}, 151*0fca6ea1SDimitry Andric Flags); 152*0fca6ea1SDimitry Andric } 153*0fca6ea1SDimitry Andric 154*0fca6ea1SDimitry Andric SDValue getNode(unsigned Opcode, const SDLoc &DL, EVT VT, SDValue N1, 155*0fca6ea1SDimitry Andric SDValue N2, SDValue N3, SDNodeFlags Flags) { 156*0fca6ea1SDimitry Andric unsigned VPOpcode = ISD::getVPForBaseOpcode(Opcode); 157*0fca6ea1SDimitry Andric assert(ISD::getVPMaskIdx(VPOpcode) == 3 && 158*0fca6ea1SDimitry Andric ISD::getVPExplicitVectorLengthIdx(VPOpcode) == 4); 159*0fca6ea1SDimitry Andric return DAG.getNode(VPOpcode, DL, VT, 160*0fca6ea1SDimitry Andric {N1, N2, N3, RootMaskOp, RootVectorLenOp}, Flags); 161*0fca6ea1SDimitry Andric } 162*0fca6ea1SDimitry Andric 163*0fca6ea1SDimitry Andric bool isOperationLegal(unsigned Op, EVT VT) const { 164*0fca6ea1SDimitry Andric unsigned VPOp = ISD::getVPForBaseOpcode(Op); 165*0fca6ea1SDimitry Andric return TLI.isOperationLegal(VPOp, VT); 166*0fca6ea1SDimitry Andric } 167*0fca6ea1SDimitry Andric 168*0fca6ea1SDimitry Andric bool isOperationLegalOrCustom(unsigned Op, EVT VT, 169*0fca6ea1SDimitry Andric bool LegalOnly = false) const { 170*0fca6ea1SDimitry Andric unsigned VPOp = ISD::getVPForBaseOpcode(Op); 171*0fca6ea1SDimitry Andric return TLI.isOperationLegalOrCustom(VPOp, VT, LegalOnly); 172*0fca6ea1SDimitry Andric } 173*0fca6ea1SDimitry Andric }; 174*0fca6ea1SDimitry Andric } // end anonymous namespace 175*0fca6ea1SDimitry Andric #endif 176