MIPatternMatch.h 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792
  1. #pragma once
  2. #ifdef __GNUC__
  3. #pragma GCC diagnostic push
  4. #pragma GCC diagnostic ignored "-Wunused-parameter"
  5. #endif
  6. //==------ llvm/CodeGen/GlobalISel/MIPatternMatch.h -------------*- C++ -*-===//
  7. //
  8. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  9. // See https://llvm.org/LICENSE.txt for license information.
  10. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  11. //
  12. //===----------------------------------------------------------------------===//
  13. /// \file
  14. /// Contains matchers for matching SSA Machine Instructions.
  15. ///
  16. //===----------------------------------------------------------------------===//
  17. #ifndef LLVM_CODEGEN_GLOBALISEL_MIPATTERNMATCH_H
  18. #define LLVM_CODEGEN_GLOBALISEL_MIPATTERNMATCH_H
  19. #include "llvm/ADT/APInt.h"
  20. #include "llvm/CodeGen/GlobalISel/Utils.h"
  21. #include "llvm/CodeGen/MachineRegisterInfo.h"
  22. #include "llvm/IR/InstrTypes.h"
  23. namespace llvm {
  24. namespace MIPatternMatch {
  25. template <typename Reg, typename Pattern>
  26. [[nodiscard]] bool mi_match(Reg R, const MachineRegisterInfo &MRI,
  27. Pattern &&P) {
  28. return P.match(MRI, R);
  29. }
  30. template <typename Pattern>
  31. [[nodiscard]] bool mi_match(MachineInstr &MI, const MachineRegisterInfo &MRI,
  32. Pattern &&P) {
  33. return P.match(MRI, &MI);
  34. }
  35. // TODO: Extend for N use.
  36. template <typename SubPatternT> struct OneUse_match {
  37. SubPatternT SubPat;
  38. OneUse_match(const SubPatternT &SP) : SubPat(SP) {}
  39. bool match(const MachineRegisterInfo &MRI, Register Reg) {
  40. return MRI.hasOneUse(Reg) && SubPat.match(MRI, Reg);
  41. }
  42. };
  43. template <typename SubPat>
  44. inline OneUse_match<SubPat> m_OneUse(const SubPat &SP) {
  45. return SP;
  46. }
  47. template <typename SubPatternT> struct OneNonDBGUse_match {
  48. SubPatternT SubPat;
  49. OneNonDBGUse_match(const SubPatternT &SP) : SubPat(SP) {}
  50. bool match(const MachineRegisterInfo &MRI, Register Reg) {
  51. return MRI.hasOneNonDBGUse(Reg) && SubPat.match(MRI, Reg);
  52. }
  53. };
  54. template <typename SubPat>
  55. inline OneNonDBGUse_match<SubPat> m_OneNonDBGUse(const SubPat &SP) {
  56. return SP;
  57. }
  58. template <typename ConstT>
  59. inline std::optional<ConstT> matchConstant(Register,
  60. const MachineRegisterInfo &);
  61. template <>
  62. inline std::optional<APInt> matchConstant(Register Reg,
  63. const MachineRegisterInfo &MRI) {
  64. return getIConstantVRegVal(Reg, MRI);
  65. }
  66. template <>
  67. inline std::optional<int64_t> matchConstant(Register Reg,
  68. const MachineRegisterInfo &MRI) {
  69. return getIConstantVRegSExtVal(Reg, MRI);
  70. }
  71. template <typename ConstT> struct ConstantMatch {
  72. ConstT &CR;
  73. ConstantMatch(ConstT &C) : CR(C) {}
  74. bool match(const MachineRegisterInfo &MRI, Register Reg) {
  75. if (auto MaybeCst = matchConstant<ConstT>(Reg, MRI)) {
  76. CR = *MaybeCst;
  77. return true;
  78. }
  79. return false;
  80. }
  81. };
  82. inline ConstantMatch<APInt> m_ICst(APInt &Cst) {
  83. return ConstantMatch<APInt>(Cst);
  84. }
  85. inline ConstantMatch<int64_t> m_ICst(int64_t &Cst) {
  86. return ConstantMatch<int64_t>(Cst);
  87. }
  88. template <typename ConstT>
  89. inline std::optional<ConstT> matchConstantSplat(Register,
  90. const MachineRegisterInfo &);
  91. template <>
  92. inline std::optional<APInt> matchConstantSplat(Register Reg,
  93. const MachineRegisterInfo &MRI) {
  94. return getIConstantSplatVal(Reg, MRI);
  95. }
  96. template <>
  97. inline std::optional<int64_t>
  98. matchConstantSplat(Register Reg, const MachineRegisterInfo &MRI) {
  99. return getIConstantSplatSExtVal(Reg, MRI);
  100. }
  101. template <typename ConstT> struct ICstOrSplatMatch {
  102. ConstT &CR;
  103. ICstOrSplatMatch(ConstT &C) : CR(C) {}
  104. bool match(const MachineRegisterInfo &MRI, Register Reg) {
  105. if (auto MaybeCst = matchConstant<ConstT>(Reg, MRI)) {
  106. CR = *MaybeCst;
  107. return true;
  108. }
  109. if (auto MaybeCstSplat = matchConstantSplat<ConstT>(Reg, MRI)) {
  110. CR = *MaybeCstSplat;
  111. return true;
  112. }
  113. return false;
  114. };
  115. };
  116. inline ICstOrSplatMatch<APInt> m_ICstOrSplat(APInt &Cst) {
  117. return ICstOrSplatMatch<APInt>(Cst);
  118. }
  119. inline ICstOrSplatMatch<int64_t> m_ICstOrSplat(int64_t &Cst) {
  120. return ICstOrSplatMatch<int64_t>(Cst);
  121. }
  122. struct GCstAndRegMatch {
  123. std::optional<ValueAndVReg> &ValReg;
  124. GCstAndRegMatch(std::optional<ValueAndVReg> &ValReg) : ValReg(ValReg) {}
  125. bool match(const MachineRegisterInfo &MRI, Register Reg) {
  126. ValReg = getIConstantVRegValWithLookThrough(Reg, MRI);
  127. return ValReg ? true : false;
  128. }
  129. };
  130. inline GCstAndRegMatch m_GCst(std::optional<ValueAndVReg> &ValReg) {
  131. return GCstAndRegMatch(ValReg);
  132. }
  133. struct GFCstAndRegMatch {
  134. std::optional<FPValueAndVReg> &FPValReg;
  135. GFCstAndRegMatch(std::optional<FPValueAndVReg> &FPValReg)
  136. : FPValReg(FPValReg) {}
  137. bool match(const MachineRegisterInfo &MRI, Register Reg) {
  138. FPValReg = getFConstantVRegValWithLookThrough(Reg, MRI);
  139. return FPValReg ? true : false;
  140. }
  141. };
  142. inline GFCstAndRegMatch m_GFCst(std::optional<FPValueAndVReg> &FPValReg) {
  143. return GFCstAndRegMatch(FPValReg);
  144. }
  145. struct GFCstOrSplatGFCstMatch {
  146. std::optional<FPValueAndVReg> &FPValReg;
  147. GFCstOrSplatGFCstMatch(std::optional<FPValueAndVReg> &FPValReg)
  148. : FPValReg(FPValReg) {}
  149. bool match(const MachineRegisterInfo &MRI, Register Reg) {
  150. return (FPValReg = getFConstantSplat(Reg, MRI)) ||
  151. (FPValReg = getFConstantVRegValWithLookThrough(Reg, MRI));
  152. };
  153. };
  154. inline GFCstOrSplatGFCstMatch
  155. m_GFCstOrSplat(std::optional<FPValueAndVReg> &FPValReg) {
  156. return GFCstOrSplatGFCstMatch(FPValReg);
  157. }
  158. /// Matcher for a specific constant value.
  159. struct SpecificConstantMatch {
  160. int64_t RequestedVal;
  161. SpecificConstantMatch(int64_t RequestedVal) : RequestedVal(RequestedVal) {}
  162. bool match(const MachineRegisterInfo &MRI, Register Reg) {
  163. int64_t MatchedVal;
  164. return mi_match(Reg, MRI, m_ICst(MatchedVal)) && MatchedVal == RequestedVal;
  165. }
  166. };
  167. /// Matches a constant equal to \p RequestedValue.
  168. inline SpecificConstantMatch m_SpecificICst(int64_t RequestedValue) {
  169. return SpecificConstantMatch(RequestedValue);
  170. }
  171. /// Matcher for a specific constant splat.
  172. struct SpecificConstantSplatMatch {
  173. int64_t RequestedVal;
  174. SpecificConstantSplatMatch(int64_t RequestedVal)
  175. : RequestedVal(RequestedVal) {}
  176. bool match(const MachineRegisterInfo &MRI, Register Reg) {
  177. return isBuildVectorConstantSplat(Reg, MRI, RequestedVal,
  178. /* AllowUndef */ false);
  179. }
  180. };
  181. /// Matches a constant splat of \p RequestedValue.
  182. inline SpecificConstantSplatMatch m_SpecificICstSplat(int64_t RequestedValue) {
  183. return SpecificConstantSplatMatch(RequestedValue);
  184. }
  185. /// Matcher for a specific constant or constant splat.
  186. struct SpecificConstantOrSplatMatch {
  187. int64_t RequestedVal;
  188. SpecificConstantOrSplatMatch(int64_t RequestedVal)
  189. : RequestedVal(RequestedVal) {}
  190. bool match(const MachineRegisterInfo &MRI, Register Reg) {
  191. int64_t MatchedVal;
  192. if (mi_match(Reg, MRI, m_ICst(MatchedVal)) && MatchedVal == RequestedVal)
  193. return true;
  194. return isBuildVectorConstantSplat(Reg, MRI, RequestedVal,
  195. /* AllowUndef */ false);
  196. }
  197. };
  198. /// Matches a \p RequestedValue constant or a constant splat of \p
  199. /// RequestedValue.
  200. inline SpecificConstantOrSplatMatch
  201. m_SpecificICstOrSplat(int64_t RequestedValue) {
  202. return SpecificConstantOrSplatMatch(RequestedValue);
  203. }
  204. ///{
  205. /// Convenience matchers for specific integer values.
  206. inline SpecificConstantMatch m_ZeroInt() { return SpecificConstantMatch(0); }
  207. inline SpecificConstantMatch m_AllOnesInt() {
  208. return SpecificConstantMatch(-1);
  209. }
  210. ///}
  211. /// Matcher for a specific register.
  212. struct SpecificRegisterMatch {
  213. Register RequestedReg;
  214. SpecificRegisterMatch(Register RequestedReg) : RequestedReg(RequestedReg) {}
  215. bool match(const MachineRegisterInfo &MRI, Register Reg) {
  216. return Reg == RequestedReg;
  217. }
  218. };
  219. /// Matches a register only if it is equal to \p RequestedReg.
  220. inline SpecificRegisterMatch m_SpecificReg(Register RequestedReg) {
  221. return SpecificRegisterMatch(RequestedReg);
  222. }
  223. // TODO: Rework this for different kinds of MachineOperand.
  224. // Currently assumes the Src for a match is a register.
  225. // We might want to support taking in some MachineOperands and call getReg on
  226. // that.
  227. struct operand_type_match {
  228. bool match(const MachineRegisterInfo &MRI, Register Reg) { return true; }
  229. bool match(const MachineRegisterInfo &MRI, MachineOperand *MO) {
  230. return MO->isReg();
  231. }
  232. };
  233. inline operand_type_match m_Reg() { return operand_type_match(); }
  234. /// Matching combinators.
  235. template <typename... Preds> struct And {
  236. template <typename MatchSrc>
  237. bool match(const MachineRegisterInfo &MRI, MatchSrc &&src) {
  238. return true;
  239. }
  240. };
  241. template <typename Pred, typename... Preds>
  242. struct And<Pred, Preds...> : And<Preds...> {
  243. Pred P;
  244. And(Pred &&p, Preds &&... preds)
  245. : And<Preds...>(std::forward<Preds>(preds)...), P(std::forward<Pred>(p)) {
  246. }
  247. template <typename MatchSrc>
  248. bool match(const MachineRegisterInfo &MRI, MatchSrc &&src) {
  249. return P.match(MRI, src) && And<Preds...>::match(MRI, src);
  250. }
  251. };
  252. template <typename... Preds> struct Or {
  253. template <typename MatchSrc>
  254. bool match(const MachineRegisterInfo &MRI, MatchSrc &&src) {
  255. return false;
  256. }
  257. };
  258. template <typename Pred, typename... Preds>
  259. struct Or<Pred, Preds...> : Or<Preds...> {
  260. Pred P;
  261. Or(Pred &&p, Preds &&... preds)
  262. : Or<Preds...>(std::forward<Preds>(preds)...), P(std::forward<Pred>(p)) {}
  263. template <typename MatchSrc>
  264. bool match(const MachineRegisterInfo &MRI, MatchSrc &&src) {
  265. return P.match(MRI, src) || Or<Preds...>::match(MRI, src);
  266. }
  267. };
  268. template <typename... Preds> And<Preds...> m_all_of(Preds &&... preds) {
  269. return And<Preds...>(std::forward<Preds>(preds)...);
  270. }
  271. template <typename... Preds> Or<Preds...> m_any_of(Preds &&... preds) {
  272. return Or<Preds...>(std::forward<Preds>(preds)...);
  273. }
  274. template <typename BindTy> struct bind_helper {
  275. static bool bind(const MachineRegisterInfo &MRI, BindTy &VR, BindTy &V) {
  276. VR = V;
  277. return true;
  278. }
  279. };
  280. template <> struct bind_helper<MachineInstr *> {
  281. static bool bind(const MachineRegisterInfo &MRI, MachineInstr *&MI,
  282. Register Reg) {
  283. MI = MRI.getVRegDef(Reg);
  284. if (MI)
  285. return true;
  286. return false;
  287. }
  288. static bool bind(const MachineRegisterInfo &MRI, MachineInstr *&MI,
  289. MachineInstr *Inst) {
  290. MI = Inst;
  291. return MI;
  292. }
  293. };
  294. template <> struct bind_helper<LLT> {
  295. static bool bind(const MachineRegisterInfo &MRI, LLT Ty, Register Reg) {
  296. Ty = MRI.getType(Reg);
  297. if (Ty.isValid())
  298. return true;
  299. return false;
  300. }
  301. };
  302. template <> struct bind_helper<const ConstantFP *> {
  303. static bool bind(const MachineRegisterInfo &MRI, const ConstantFP *&F,
  304. Register Reg) {
  305. F = getConstantFPVRegVal(Reg, MRI);
  306. if (F)
  307. return true;
  308. return false;
  309. }
  310. };
  311. template <typename Class> struct bind_ty {
  312. Class &VR;
  313. bind_ty(Class &V) : VR(V) {}
  314. template <typename ITy> bool match(const MachineRegisterInfo &MRI, ITy &&V) {
  315. return bind_helper<Class>::bind(MRI, VR, V);
  316. }
  317. };
  318. inline bind_ty<Register> m_Reg(Register &R) { return R; }
  319. inline bind_ty<MachineInstr *> m_MInstr(MachineInstr *&MI) { return MI; }
  320. inline bind_ty<LLT> m_Type(LLT Ty) { return Ty; }
  321. inline bind_ty<CmpInst::Predicate> m_Pred(CmpInst::Predicate &P) { return P; }
  322. inline operand_type_match m_Pred() { return operand_type_match(); }
  323. struct ImplicitDefMatch {
  324. bool match(const MachineRegisterInfo &MRI, Register Reg) {
  325. MachineInstr *TmpMI;
  326. if (mi_match(Reg, MRI, m_MInstr(TmpMI)))
  327. return TmpMI->getOpcode() == TargetOpcode::G_IMPLICIT_DEF;
  328. return false;
  329. }
  330. };
  331. inline ImplicitDefMatch m_GImplicitDef() { return ImplicitDefMatch(); }
  332. // Helper for matching G_FCONSTANT
  333. inline bind_ty<const ConstantFP *> m_GFCst(const ConstantFP *&C) { return C; }
  334. // General helper for all the binary generic MI such as G_ADD/G_SUB etc
  335. template <typename LHS_P, typename RHS_P, unsigned Opcode,
  336. bool Commutable = false>
  337. struct BinaryOp_match {
  338. LHS_P L;
  339. RHS_P R;
  340. BinaryOp_match(const LHS_P &LHS, const RHS_P &RHS) : L(LHS), R(RHS) {}
  341. template <typename OpTy>
  342. bool match(const MachineRegisterInfo &MRI, OpTy &&Op) {
  343. MachineInstr *TmpMI;
  344. if (mi_match(Op, MRI, m_MInstr(TmpMI))) {
  345. if (TmpMI->getOpcode() == Opcode && TmpMI->getNumOperands() == 3) {
  346. return (L.match(MRI, TmpMI->getOperand(1).getReg()) &&
  347. R.match(MRI, TmpMI->getOperand(2).getReg())) ||
  348. (Commutable && (R.match(MRI, TmpMI->getOperand(1).getReg()) &&
  349. L.match(MRI, TmpMI->getOperand(2).getReg())));
  350. }
  351. }
  352. return false;
  353. }
  354. };
  355. // Helper for (commutative) binary generic MI that checks Opcode.
  356. template <typename LHS_P, typename RHS_P, bool Commutable = false>
  357. struct BinaryOpc_match {
  358. unsigned Opc;
  359. LHS_P L;
  360. RHS_P R;
  361. BinaryOpc_match(unsigned Opcode, const LHS_P &LHS, const RHS_P &RHS)
  362. : Opc(Opcode), L(LHS), R(RHS) {}
  363. template <typename OpTy>
  364. bool match(const MachineRegisterInfo &MRI, OpTy &&Op) {
  365. MachineInstr *TmpMI;
  366. if (mi_match(Op, MRI, m_MInstr(TmpMI))) {
  367. if (TmpMI->getOpcode() == Opc && TmpMI->getNumDefs() == 1 &&
  368. TmpMI->getNumOperands() == 3) {
  369. return (L.match(MRI, TmpMI->getOperand(1).getReg()) &&
  370. R.match(MRI, TmpMI->getOperand(2).getReg())) ||
  371. (Commutable && (R.match(MRI, TmpMI->getOperand(1).getReg()) &&
  372. L.match(MRI, TmpMI->getOperand(2).getReg())));
  373. }
  374. }
  375. return false;
  376. }
  377. };
  378. template <typename LHS, typename RHS>
  379. inline BinaryOpc_match<LHS, RHS, false> m_BinOp(unsigned Opcode, const LHS &L,
  380. const RHS &R) {
  381. return BinaryOpc_match<LHS, RHS, false>(Opcode, L, R);
  382. }
  383. template <typename LHS, typename RHS>
  384. inline BinaryOpc_match<LHS, RHS, true>
  385. m_CommutativeBinOp(unsigned Opcode, const LHS &L, const RHS &R) {
  386. return BinaryOpc_match<LHS, RHS, true>(Opcode, L, R);
  387. }
  388. template <typename LHS, typename RHS>
  389. inline BinaryOp_match<LHS, RHS, TargetOpcode::G_ADD, true>
  390. m_GAdd(const LHS &L, const RHS &R) {
  391. return BinaryOp_match<LHS, RHS, TargetOpcode::G_ADD, true>(L, R);
  392. }
  393. template <typename LHS, typename RHS>
  394. inline BinaryOp_match<LHS, RHS, TargetOpcode::G_BUILD_VECTOR, false>
  395. m_GBuildVector(const LHS &L, const RHS &R) {
  396. return BinaryOp_match<LHS, RHS, TargetOpcode::G_BUILD_VECTOR, false>(L, R);
  397. }
  398. template <typename LHS, typename RHS>
  399. inline BinaryOp_match<LHS, RHS, TargetOpcode::G_BUILD_VECTOR_TRUNC, false>
  400. m_GBuildVectorTrunc(const LHS &L, const RHS &R) {
  401. return BinaryOp_match<LHS, RHS, TargetOpcode::G_BUILD_VECTOR_TRUNC, false>(L,
  402. R);
  403. }
  404. template <typename LHS, typename RHS>
  405. inline BinaryOp_match<LHS, RHS, TargetOpcode::G_PTR_ADD, false>
  406. m_GPtrAdd(const LHS &L, const RHS &R) {
  407. return BinaryOp_match<LHS, RHS, TargetOpcode::G_PTR_ADD, false>(L, R);
  408. }
  409. template <typename LHS, typename RHS>
  410. inline BinaryOp_match<LHS, RHS, TargetOpcode::G_SUB> m_GSub(const LHS &L,
  411. const RHS &R) {
  412. return BinaryOp_match<LHS, RHS, TargetOpcode::G_SUB>(L, R);
  413. }
  414. template <typename LHS, typename RHS>
  415. inline BinaryOp_match<LHS, RHS, TargetOpcode::G_MUL, true>
  416. m_GMul(const LHS &L, const RHS &R) {
  417. return BinaryOp_match<LHS, RHS, TargetOpcode::G_MUL, true>(L, R);
  418. }
  419. template <typename LHS, typename RHS>
  420. inline BinaryOp_match<LHS, RHS, TargetOpcode::G_FADD, true>
  421. m_GFAdd(const LHS &L, const RHS &R) {
  422. return BinaryOp_match<LHS, RHS, TargetOpcode::G_FADD, true>(L, R);
  423. }
  424. template <typename LHS, typename RHS>
  425. inline BinaryOp_match<LHS, RHS, TargetOpcode::G_FMUL, true>
  426. m_GFMul(const LHS &L, const RHS &R) {
  427. return BinaryOp_match<LHS, RHS, TargetOpcode::G_FMUL, true>(L, R);
  428. }
  429. template <typename LHS, typename RHS>
  430. inline BinaryOp_match<LHS, RHS, TargetOpcode::G_FSUB, false>
  431. m_GFSub(const LHS &L, const RHS &R) {
  432. return BinaryOp_match<LHS, RHS, TargetOpcode::G_FSUB, false>(L, R);
  433. }
  434. template <typename LHS, typename RHS>
  435. inline BinaryOp_match<LHS, RHS, TargetOpcode::G_AND, true>
  436. m_GAnd(const LHS &L, const RHS &R) {
  437. return BinaryOp_match<LHS, RHS, TargetOpcode::G_AND, true>(L, R);
  438. }
  439. template <typename LHS, typename RHS>
  440. inline BinaryOp_match<LHS, RHS, TargetOpcode::G_XOR, true>
  441. m_GXor(const LHS &L, const RHS &R) {
  442. return BinaryOp_match<LHS, RHS, TargetOpcode::G_XOR, true>(L, R);
  443. }
  444. template <typename LHS, typename RHS>
  445. inline BinaryOp_match<LHS, RHS, TargetOpcode::G_OR, true> m_GOr(const LHS &L,
  446. const RHS &R) {
  447. return BinaryOp_match<LHS, RHS, TargetOpcode::G_OR, true>(L, R);
  448. }
  449. template <typename LHS, typename RHS>
  450. inline BinaryOp_match<LHS, RHS, TargetOpcode::G_SHL, false>
  451. m_GShl(const LHS &L, const RHS &R) {
  452. return BinaryOp_match<LHS, RHS, TargetOpcode::G_SHL, false>(L, R);
  453. }
  454. template <typename LHS, typename RHS>
  455. inline BinaryOp_match<LHS, RHS, TargetOpcode::G_LSHR, false>
  456. m_GLShr(const LHS &L, const RHS &R) {
  457. return BinaryOp_match<LHS, RHS, TargetOpcode::G_LSHR, false>(L, R);
  458. }
  459. template <typename LHS, typename RHS>
  460. inline BinaryOp_match<LHS, RHS, TargetOpcode::G_ASHR, false>
  461. m_GAShr(const LHS &L, const RHS &R) {
  462. return BinaryOp_match<LHS, RHS, TargetOpcode::G_ASHR, false>(L, R);
  463. }
  464. template <typename LHS, typename RHS>
  465. inline BinaryOp_match<LHS, RHS, TargetOpcode::G_SMAX, false>
  466. m_GSMax(const LHS &L, const RHS &R) {
  467. return BinaryOp_match<LHS, RHS, TargetOpcode::G_SMAX, false>(L, R);
  468. }
  469. template <typename LHS, typename RHS>
  470. inline BinaryOp_match<LHS, RHS, TargetOpcode::G_SMIN, false>
  471. m_GSMin(const LHS &L, const RHS &R) {
  472. return BinaryOp_match<LHS, RHS, TargetOpcode::G_SMIN, false>(L, R);
  473. }
  474. // Helper for unary instructions (G_[ZSA]EXT/G_TRUNC) etc
  475. template <typename SrcTy, unsigned Opcode> struct UnaryOp_match {
  476. SrcTy L;
  477. UnaryOp_match(const SrcTy &LHS) : L(LHS) {}
  478. template <typename OpTy>
  479. bool match(const MachineRegisterInfo &MRI, OpTy &&Op) {
  480. MachineInstr *TmpMI;
  481. if (mi_match(Op, MRI, m_MInstr(TmpMI))) {
  482. if (TmpMI->getOpcode() == Opcode && TmpMI->getNumOperands() == 2) {
  483. return L.match(MRI, TmpMI->getOperand(1).getReg());
  484. }
  485. }
  486. return false;
  487. }
  488. };
  489. template <typename SrcTy>
  490. inline UnaryOp_match<SrcTy, TargetOpcode::G_ANYEXT>
  491. m_GAnyExt(const SrcTy &Src) {
  492. return UnaryOp_match<SrcTy, TargetOpcode::G_ANYEXT>(Src);
  493. }
  494. template <typename SrcTy>
  495. inline UnaryOp_match<SrcTy, TargetOpcode::G_SEXT> m_GSExt(const SrcTy &Src) {
  496. return UnaryOp_match<SrcTy, TargetOpcode::G_SEXT>(Src);
  497. }
  498. template <typename SrcTy>
  499. inline UnaryOp_match<SrcTy, TargetOpcode::G_ZEXT> m_GZExt(const SrcTy &Src) {
  500. return UnaryOp_match<SrcTy, TargetOpcode::G_ZEXT>(Src);
  501. }
  502. template <typename SrcTy>
  503. inline UnaryOp_match<SrcTy, TargetOpcode::G_FPEXT> m_GFPExt(const SrcTy &Src) {
  504. return UnaryOp_match<SrcTy, TargetOpcode::G_FPEXT>(Src);
  505. }
  506. template <typename SrcTy>
  507. inline UnaryOp_match<SrcTy, TargetOpcode::G_TRUNC> m_GTrunc(const SrcTy &Src) {
  508. return UnaryOp_match<SrcTy, TargetOpcode::G_TRUNC>(Src);
  509. }
  510. template <typename SrcTy>
  511. inline UnaryOp_match<SrcTy, TargetOpcode::G_BITCAST>
  512. m_GBitcast(const SrcTy &Src) {
  513. return UnaryOp_match<SrcTy, TargetOpcode::G_BITCAST>(Src);
  514. }
  515. template <typename SrcTy>
  516. inline UnaryOp_match<SrcTy, TargetOpcode::G_PTRTOINT>
  517. m_GPtrToInt(const SrcTy &Src) {
  518. return UnaryOp_match<SrcTy, TargetOpcode::G_PTRTOINT>(Src);
  519. }
  520. template <typename SrcTy>
  521. inline UnaryOp_match<SrcTy, TargetOpcode::G_INTTOPTR>
  522. m_GIntToPtr(const SrcTy &Src) {
  523. return UnaryOp_match<SrcTy, TargetOpcode::G_INTTOPTR>(Src);
  524. }
  525. template <typename SrcTy>
  526. inline UnaryOp_match<SrcTy, TargetOpcode::G_FPTRUNC>
  527. m_GFPTrunc(const SrcTy &Src) {
  528. return UnaryOp_match<SrcTy, TargetOpcode::G_FPTRUNC>(Src);
  529. }
  530. template <typename SrcTy>
  531. inline UnaryOp_match<SrcTy, TargetOpcode::G_FABS> m_GFabs(const SrcTy &Src) {
  532. return UnaryOp_match<SrcTy, TargetOpcode::G_FABS>(Src);
  533. }
  534. template <typename SrcTy>
  535. inline UnaryOp_match<SrcTy, TargetOpcode::G_FNEG> m_GFNeg(const SrcTy &Src) {
  536. return UnaryOp_match<SrcTy, TargetOpcode::G_FNEG>(Src);
  537. }
  538. template <typename SrcTy>
  539. inline UnaryOp_match<SrcTy, TargetOpcode::COPY> m_Copy(SrcTy &&Src) {
  540. return UnaryOp_match<SrcTy, TargetOpcode::COPY>(std::forward<SrcTy>(Src));
  541. }
  542. template <typename SrcTy>
  543. inline UnaryOp_match<SrcTy, TargetOpcode::G_FSQRT> m_GFSqrt(const SrcTy &Src) {
  544. return UnaryOp_match<SrcTy, TargetOpcode::G_FSQRT>(Src);
  545. }
  546. // General helper for generic MI compares, i.e. G_ICMP and G_FCMP
  547. // TODO: Allow checking a specific predicate.
  548. template <typename Pred_P, typename LHS_P, typename RHS_P, unsigned Opcode,
  549. bool Commutable = false>
  550. struct CompareOp_match {
  551. Pred_P P;
  552. LHS_P L;
  553. RHS_P R;
  554. CompareOp_match(const Pred_P &Pred, const LHS_P &LHS, const RHS_P &RHS)
  555. : P(Pred), L(LHS), R(RHS) {}
  556. template <typename OpTy>
  557. bool match(const MachineRegisterInfo &MRI, OpTy &&Op) {
  558. MachineInstr *TmpMI;
  559. if (!mi_match(Op, MRI, m_MInstr(TmpMI)) || TmpMI->getOpcode() != Opcode)
  560. return false;
  561. auto TmpPred =
  562. static_cast<CmpInst::Predicate>(TmpMI->getOperand(1).getPredicate());
  563. if (!P.match(MRI, TmpPred))
  564. return false;
  565. Register LHS = TmpMI->getOperand(2).getReg();
  566. Register RHS = TmpMI->getOperand(3).getReg();
  567. if (L.match(MRI, LHS) && R.match(MRI, RHS))
  568. return true;
  569. if (Commutable && L.match(MRI, RHS) && R.match(MRI, LHS) &&
  570. P.match(MRI, CmpInst::getSwappedPredicate(TmpPred)))
  571. return true;
  572. return false;
  573. }
  574. };
  575. template <typename Pred, typename LHS, typename RHS>
  576. inline CompareOp_match<Pred, LHS, RHS, TargetOpcode::G_ICMP>
  577. m_GICmp(const Pred &P, const LHS &L, const RHS &R) {
  578. return CompareOp_match<Pred, LHS, RHS, TargetOpcode::G_ICMP>(P, L, R);
  579. }
  580. template <typename Pred, typename LHS, typename RHS>
  581. inline CompareOp_match<Pred, LHS, RHS, TargetOpcode::G_FCMP>
  582. m_GFCmp(const Pred &P, const LHS &L, const RHS &R) {
  583. return CompareOp_match<Pred, LHS, RHS, TargetOpcode::G_FCMP>(P, L, R);
  584. }
  585. /// G_ICMP matcher that also matches commuted compares.
  586. /// E.g.
  587. ///
  588. /// m_c_GICmp(m_Pred(...), m_GAdd(...), m_GSub(...))
  589. ///
  590. /// Could match both of:
  591. ///
  592. /// icmp ugt (add x, y) (sub a, b)
  593. /// icmp ult (sub a, b) (add x, y)
  594. template <typename Pred, typename LHS, typename RHS>
  595. inline CompareOp_match<Pred, LHS, RHS, TargetOpcode::G_ICMP, true>
  596. m_c_GICmp(const Pred &P, const LHS &L, const RHS &R) {
  597. return CompareOp_match<Pred, LHS, RHS, TargetOpcode::G_ICMP, true>(P, L, R);
  598. }
  599. /// G_FCMP matcher that also matches commuted compares.
  600. /// E.g.
  601. ///
  602. /// m_c_GFCmp(m_Pred(...), m_FAdd(...), m_GFMul(...))
  603. ///
  604. /// Could match both of:
  605. ///
  606. /// fcmp ogt (fadd x, y) (fmul a, b)
  607. /// fcmp olt (fmul a, b) (fadd x, y)
  608. template <typename Pred, typename LHS, typename RHS>
  609. inline CompareOp_match<Pred, LHS, RHS, TargetOpcode::G_FCMP, true>
  610. m_c_GFCmp(const Pred &P, const LHS &L, const RHS &R) {
  611. return CompareOp_match<Pred, LHS, RHS, TargetOpcode::G_FCMP, true>(P, L, R);
  612. }
  613. // Helper for checking if a Reg is of specific type.
  614. struct CheckType {
  615. LLT Ty;
  616. CheckType(const LLT Ty) : Ty(Ty) {}
  617. bool match(const MachineRegisterInfo &MRI, Register Reg) {
  618. return MRI.getType(Reg) == Ty;
  619. }
  620. };
  621. inline CheckType m_SpecificType(LLT Ty) { return Ty; }
  622. template <typename Src0Ty, typename Src1Ty, typename Src2Ty, unsigned Opcode>
  623. struct TernaryOp_match {
  624. Src0Ty Src0;
  625. Src1Ty Src1;
  626. Src2Ty Src2;
  627. TernaryOp_match(const Src0Ty &Src0, const Src1Ty &Src1, const Src2Ty &Src2)
  628. : Src0(Src0), Src1(Src1), Src2(Src2) {}
  629. template <typename OpTy>
  630. bool match(const MachineRegisterInfo &MRI, OpTy &&Op) {
  631. MachineInstr *TmpMI;
  632. if (mi_match(Op, MRI, m_MInstr(TmpMI))) {
  633. if (TmpMI->getOpcode() == Opcode && TmpMI->getNumOperands() == 4) {
  634. return (Src0.match(MRI, TmpMI->getOperand(1).getReg()) &&
  635. Src1.match(MRI, TmpMI->getOperand(2).getReg()) &&
  636. Src2.match(MRI, TmpMI->getOperand(3).getReg()));
  637. }
  638. }
  639. return false;
  640. }
  641. };
  642. template <typename Src0Ty, typename Src1Ty, typename Src2Ty>
  643. inline TernaryOp_match<Src0Ty, Src1Ty, Src2Ty,
  644. TargetOpcode::G_INSERT_VECTOR_ELT>
  645. m_GInsertVecElt(const Src0Ty &Src0, const Src1Ty &Src1, const Src2Ty &Src2) {
  646. return TernaryOp_match<Src0Ty, Src1Ty, Src2Ty,
  647. TargetOpcode::G_INSERT_VECTOR_ELT>(Src0, Src1, Src2);
  648. }
  649. template <typename Src0Ty, typename Src1Ty, typename Src2Ty>
  650. inline TernaryOp_match<Src0Ty, Src1Ty, Src2Ty, TargetOpcode::G_SELECT>
  651. m_GISelect(const Src0Ty &Src0, const Src1Ty &Src1, const Src2Ty &Src2) {
  652. return TernaryOp_match<Src0Ty, Src1Ty, Src2Ty, TargetOpcode::G_SELECT>(
  653. Src0, Src1, Src2);
  654. }
  655. /// Matches a register negated by a G_SUB.
  656. /// G_SUB 0, %negated_reg
  657. template <typename SrcTy>
  658. inline BinaryOp_match<SpecificConstantMatch, SrcTy, TargetOpcode::G_SUB>
  659. m_Neg(const SrcTy &&Src) {
  660. return m_GSub(m_ZeroInt(), Src);
  661. }
  662. /// Matches a register not-ed by a G_XOR.
  663. /// G_XOR %not_reg, -1
  664. template <typename SrcTy>
  665. inline BinaryOp_match<SrcTy, SpecificConstantMatch, TargetOpcode::G_XOR, true>
  666. m_Not(const SrcTy &&Src) {
  667. return m_GXor(Src, m_AllOnesInt());
  668. }
  669. } // namespace MIPatternMatch
  670. } // namespace llvm
  671. #endif
  672. #ifdef __GNUC__
  673. #pragma GCC diagnostic pop
  674. #endif