xref: /freebsd-src/contrib/llvm-project/llvm/lib/CodeGen/SelectionDAG/MatchContext.h (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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