FunctionMatch.cs 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866
  1. using Ryujinx.Graphics.Shader.Decoders;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Runtime.CompilerServices;
  5. namespace Ryujinx.Graphics.Shader.Translation
  6. {
  7. static class FunctionMatch
  8. {
  9. private static IPatternTreeNode[] _fsiGetAddressTree = PatternTrees.GetFsiGetAddress();
  10. private static IPatternTreeNode[] _fsiGetAddressV2Tree = PatternTrees.GetFsiGetAddressV2();
  11. private static IPatternTreeNode[] _fsiIsLastWarpThreadPatternTree = PatternTrees.GetFsiIsLastWarpThread();
  12. private static IPatternTreeNode[] _fsiBeginPatternTree = PatternTrees.GetFsiBeginPattern();
  13. private static IPatternTreeNode[] _fsiEndPatternTree = PatternTrees.GetFsiEndPattern();
  14. public static void RunPass(DecodedProgram program)
  15. {
  16. byte[] externalRegs = new byte[4];
  17. bool hasGetAddress = false;
  18. foreach (DecodedFunction function in program)
  19. {
  20. if (function == program.MainFunction)
  21. {
  22. continue;
  23. }
  24. int externalReg4 = 0;
  25. TreeNode[] functionTree = BuildTree(function.Blocks);
  26. if (Matches(_fsiGetAddressTree, functionTree))
  27. {
  28. externalRegs[1] = functionTree[0].GetRd();
  29. externalRegs[2] = functionTree[2].GetRd();
  30. externalRegs[3] = functionTree[1].GetRd();
  31. externalReg4 = functionTree[3].GetRd();
  32. }
  33. else if (Matches(_fsiGetAddressV2Tree, functionTree))
  34. {
  35. externalRegs[1] = functionTree[2].GetRd();
  36. externalRegs[2] = functionTree[1].GetRd();
  37. externalRegs[3] = functionTree[0].GetRd();
  38. externalReg4 = functionTree[3].GetRd();
  39. }
  40. // Ensure the register allocation is valid.
  41. // If so, then we have a match.
  42. if (externalRegs[1] != externalRegs[2] &&
  43. externalRegs[2] != externalRegs[3] &&
  44. externalRegs[1] != externalRegs[3] &&
  45. externalRegs[1] + 1 != externalRegs[2] &&
  46. externalRegs[1] + 1 != externalRegs[3] &&
  47. externalRegs[1] + 1 == externalReg4 &&
  48. externalRegs[2] != RegisterConsts.RegisterZeroIndex &&
  49. externalRegs[3] != RegisterConsts.RegisterZeroIndex &&
  50. externalReg4 != RegisterConsts.RegisterZeroIndex)
  51. {
  52. hasGetAddress = true;
  53. function.Type = FunctionType.Unused;
  54. break;
  55. }
  56. }
  57. foreach (DecodedFunction function in program)
  58. {
  59. if (function.IsCompilerGenerated || function == program.MainFunction)
  60. {
  61. continue;
  62. }
  63. if (hasGetAddress)
  64. {
  65. TreeNode[] functionTree = BuildTree(function.Blocks);
  66. if (MatchesFsi(_fsiBeginPatternTree, program, function, functionTree, externalRegs))
  67. {
  68. function.Type = FunctionType.BuiltInFSIBegin;
  69. continue;
  70. }
  71. else if (MatchesFsi(_fsiEndPatternTree, program, function, functionTree, externalRegs))
  72. {
  73. function.Type = FunctionType.BuiltInFSIEnd;
  74. continue;
  75. }
  76. }
  77. }
  78. }
  79. private readonly struct TreeNodeUse
  80. {
  81. public TreeNode Node { get; }
  82. public int Index { get; }
  83. public bool Inverted { get; }
  84. private TreeNodeUse(int index, bool inverted, TreeNode node)
  85. {
  86. Index = index;
  87. Inverted = inverted;
  88. Node = node;
  89. }
  90. public TreeNodeUse(int index, TreeNode node) : this(index, false, node)
  91. {
  92. }
  93. public TreeNodeUse Flip()
  94. {
  95. return new TreeNodeUse(Index, !Inverted, Node);
  96. }
  97. }
  98. private enum TreeNodeType : byte
  99. {
  100. Op,
  101. Label
  102. }
  103. private class TreeNode
  104. {
  105. public readonly InstOp Op;
  106. public readonly List<TreeNodeUse> Uses;
  107. public TreeNodeType Type { get; }
  108. public byte Order { get; }
  109. public TreeNode(byte order)
  110. {
  111. Type = TreeNodeType.Label;
  112. Order = order;
  113. }
  114. public TreeNode(InstOp op, byte order)
  115. {
  116. Op = op;
  117. Uses = new List<TreeNodeUse>();
  118. Type = TreeNodeType.Op;
  119. Order = order;
  120. }
  121. public byte GetPd()
  122. {
  123. return (byte)((Op.RawOpCode >> 3) & 7);
  124. }
  125. public byte GetRd()
  126. {
  127. return (byte)Op.RawOpCode;
  128. }
  129. }
  130. private static TreeNode[] BuildTree(Block[] blocks)
  131. {
  132. List<TreeNode> nodes = new List<TreeNode>();
  133. Dictionary<ulong, TreeNode> labels = new Dictionary<ulong, TreeNode>();
  134. TreeNodeUse[] predDefs = new TreeNodeUse[RegisterConsts.PredsCount];
  135. TreeNodeUse[] gprDefs = new TreeNodeUse[RegisterConsts.GprsCount];
  136. void DefPred(byte predIndex, int index, TreeNode node)
  137. {
  138. if (predIndex != RegisterConsts.PredicateTrueIndex)
  139. {
  140. predDefs[predIndex] = new TreeNodeUse(index, node);
  141. }
  142. }
  143. void DefGpr(byte regIndex, int index, TreeNode node)
  144. {
  145. if (regIndex != RegisterConsts.RegisterZeroIndex)
  146. {
  147. gprDefs[regIndex] = new TreeNodeUse(index, node);
  148. }
  149. }
  150. TreeNodeUse UsePred(byte predIndex, bool predInv)
  151. {
  152. if (predIndex != RegisterConsts.PredicateTrueIndex)
  153. {
  154. TreeNodeUse use = predDefs[predIndex];
  155. if (use.Node != null)
  156. {
  157. nodes.Remove(use.Node);
  158. }
  159. else
  160. {
  161. use = new TreeNodeUse(-(predIndex + 2), null);
  162. }
  163. return predInv ? use.Flip() : use;
  164. }
  165. return new TreeNodeUse(-1, null);
  166. }
  167. TreeNodeUse UseGpr(byte regIndex)
  168. {
  169. if (regIndex != RegisterConsts.RegisterZeroIndex)
  170. {
  171. TreeNodeUse use = gprDefs[regIndex];
  172. if (use.Node != null)
  173. {
  174. nodes.Remove(use.Node);
  175. }
  176. else
  177. {
  178. use = new TreeNodeUse(-(regIndex + 2), null);
  179. }
  180. return use;
  181. }
  182. return new TreeNodeUse(-1, null);
  183. }
  184. byte order = 0;
  185. for (int index = 0; index < blocks.Length; index++)
  186. {
  187. Block block = blocks[index];
  188. if (block.Predecessors.Count > 1)
  189. {
  190. TreeNode label = new TreeNode(order++);
  191. nodes.Add(label);
  192. labels.Add(block.Address, label);
  193. }
  194. for (int opIndex = 0; opIndex < block.OpCodes.Count; opIndex++)
  195. {
  196. InstOp op = block.OpCodes[opIndex];
  197. TreeNode node = new TreeNode(op, IsOrderDependant(op.Name) ? order : (byte)0);
  198. // Add uses.
  199. if (!op.Props.HasFlag(InstProps.NoPred))
  200. {
  201. byte predIndex = (byte)((op.RawOpCode >> 16) & 7);
  202. bool predInv = (op.RawOpCode & 0x80000) != 0;
  203. node.Uses.Add(UsePred(predIndex, predInv));
  204. }
  205. if (op.Props.HasFlag(InstProps.Ps))
  206. {
  207. byte predIndex = (byte)((op.RawOpCode >> 39) & 7);
  208. bool predInv = (op.RawOpCode & 0x40000000000) != 0;
  209. node.Uses.Add(UsePred(predIndex, predInv));
  210. }
  211. if (op.Props.HasFlag(InstProps.Ra))
  212. {
  213. byte ra = (byte)(op.RawOpCode >> 8);
  214. node.Uses.Add(UseGpr(ra));
  215. }
  216. if ((op.Props & (InstProps.Rb | InstProps.Rb2)) != 0)
  217. {
  218. byte rb = op.Props.HasFlag(InstProps.Rb2) ? (byte)op.RawOpCode : (byte)(op.RawOpCode >> 20);
  219. node.Uses.Add(UseGpr(rb));
  220. }
  221. if (op.Props.HasFlag(InstProps.Rc))
  222. {
  223. byte rc = (byte)(op.RawOpCode >> 39);
  224. node.Uses.Add(UseGpr(rc));
  225. }
  226. if (op.Name == InstName.Bra && labels.TryGetValue(op.GetAbsoluteAddress(), out TreeNode label))
  227. {
  228. node.Uses.Add(new TreeNodeUse(0, label));
  229. }
  230. // Make definitions.
  231. int defIndex = 0;
  232. InstProps pdType = op.Props & InstProps.PdMask;
  233. if (pdType != 0)
  234. {
  235. int bit = pdType switch
  236. {
  237. InstProps.Pd => 3,
  238. InstProps.LPd => 48,
  239. InstProps.SPd => 30,
  240. InstProps.TPd => 51,
  241. InstProps.VPd => 45,
  242. _ => throw new InvalidOperationException($"Table has unknown predicate destination {pdType}.")
  243. };
  244. byte predIndex = (byte)((op.RawOpCode >> bit) & 7);
  245. DefPred(predIndex, defIndex++, node);
  246. }
  247. if (op.Props.HasFlag(InstProps.Rd))
  248. {
  249. byte rd = (byte)op.RawOpCode;
  250. DefGpr(rd, defIndex++, node);
  251. }
  252. nodes.Add(node);
  253. }
  254. }
  255. return nodes.ToArray();
  256. }
  257. private static bool IsOrderDependant(InstName name)
  258. {
  259. switch (name)
  260. {
  261. case InstName.Atom:
  262. case InstName.AtomCas:
  263. case InstName.Atoms:
  264. case InstName.AtomsCas:
  265. case InstName.Ld:
  266. case InstName.Ldg:
  267. case InstName.Ldl:
  268. case InstName.Lds:
  269. case InstName.Suatom:
  270. case InstName.SuatomB:
  271. case InstName.SuatomB2:
  272. case InstName.SuatomCas:
  273. case InstName.SuatomCasB:
  274. case InstName.Suld:
  275. case InstName.SuldB:
  276. case InstName.SuldD:
  277. case InstName.SuldDB:
  278. return true;
  279. }
  280. return false;
  281. }
  282. private interface IPatternTreeNode
  283. {
  284. List<PatternTreeNodeUse> Uses { get; }
  285. InstName Name { get; }
  286. TreeNodeType Type { get; }
  287. byte Order { get; }
  288. bool IsImm { get; }
  289. bool Matches(in InstOp opInfo);
  290. }
  291. private readonly struct PatternTreeNodeUse
  292. {
  293. public IPatternTreeNode Node { get; }
  294. public int Index { get; }
  295. public bool Inverted { get; }
  296. public PatternTreeNodeUse Inv => new PatternTreeNodeUse(Index, !Inverted, Node);
  297. private PatternTreeNodeUse(int index, bool inverted, IPatternTreeNode node)
  298. {
  299. Index = index;
  300. Inverted = inverted;
  301. Node = node;
  302. }
  303. public PatternTreeNodeUse(int index, IPatternTreeNode node) : this(index, false, node)
  304. {
  305. }
  306. }
  307. private class PatternTreeNode<T> : IPatternTreeNode
  308. {
  309. public List<PatternTreeNodeUse> Uses { get; }
  310. private readonly Func<T, bool> _match;
  311. public InstName Name { get; }
  312. public TreeNodeType Type { get; }
  313. public byte Order { get; }
  314. public bool IsImm { get; }
  315. public PatternTreeNodeUse Out => new PatternTreeNodeUse(0, this);
  316. public PatternTreeNode(InstName name, Func<T, bool> match, TreeNodeType type = TreeNodeType.Op, byte order = 0, bool isImm = false)
  317. {
  318. Name = name;
  319. _match = match;
  320. Type = type;
  321. Order = order;
  322. IsImm = isImm;
  323. Uses = new List<PatternTreeNodeUse>();
  324. }
  325. public PatternTreeNode<T> Use(PatternTreeNodeUse use)
  326. {
  327. Uses.Add(use);
  328. return this;
  329. }
  330. public PatternTreeNodeUse OutAt(int index)
  331. {
  332. return new PatternTreeNodeUse(index, this);
  333. }
  334. public bool Matches(in InstOp opInfo)
  335. {
  336. if (opInfo.Name != Name)
  337. {
  338. return false;
  339. }
  340. ulong rawOp = opInfo.RawOpCode;
  341. T op = Unsafe.As<ulong, T>(ref rawOp);
  342. if (!_match(op))
  343. {
  344. return false;
  345. }
  346. return true;
  347. }
  348. }
  349. private static bool MatchesFsi(
  350. IPatternTreeNode[] pattern,
  351. DecodedProgram program,
  352. DecodedFunction function,
  353. TreeNode[] functionTree,
  354. byte[] externalRegs)
  355. {
  356. if (function.Blocks.Length == 0)
  357. {
  358. return false;
  359. }
  360. InstOp callOp = function.Blocks[0].GetLastOp();
  361. if (callOp.Name != InstName.Cal)
  362. {
  363. return false;
  364. }
  365. DecodedFunction callTarget = program.GetFunctionByAddress(callOp.GetAbsoluteAddress());
  366. TreeNode[] callTargetTree = null;
  367. if (callTarget == null || !Matches(_fsiIsLastWarpThreadPatternTree, callTargetTree = BuildTree(callTarget.Blocks)))
  368. {
  369. return false;
  370. }
  371. externalRegs[0] = callTargetTree[0].GetPd();
  372. if (Matches(pattern, functionTree, externalRegs))
  373. {
  374. callTarget.RemoveCaller(function);
  375. return true;
  376. }
  377. return false;
  378. }
  379. private static bool Matches(IPatternTreeNode[] pTree, TreeNode[] cTree, byte[] externalRegs = null)
  380. {
  381. if (pTree.Length != cTree.Length)
  382. {
  383. return false;
  384. }
  385. for (int index = 0; index < pTree.Length; index++)
  386. {
  387. if (!Matches(pTree[index], cTree[index], externalRegs))
  388. {
  389. return false;
  390. }
  391. }
  392. return true;
  393. }
  394. private static bool Matches(IPatternTreeNode pTreeNode, TreeNode cTreeNode, byte[] externalRegs)
  395. {
  396. if (!pTreeNode.Matches(in cTreeNode.Op) ||
  397. pTreeNode.Type != cTreeNode.Type ||
  398. pTreeNode.Order != cTreeNode.Order ||
  399. pTreeNode.IsImm != cTreeNode.Op.Props.HasFlag(InstProps.Ib))
  400. {
  401. return false;
  402. }
  403. if (pTreeNode.Type == TreeNodeType.Op)
  404. {
  405. if (pTreeNode.Uses.Count != cTreeNode.Uses.Count)
  406. {
  407. return false;
  408. }
  409. for (int index = 0; index < pTreeNode.Uses.Count; index++)
  410. {
  411. var pUse = pTreeNode.Uses[index];
  412. var cUse = cTreeNode.Uses[index];
  413. if (pUse.Index <= -2)
  414. {
  415. if (externalRegs[-pUse.Index - 2] != (-cUse.Index - 2))
  416. {
  417. return false;
  418. }
  419. }
  420. else if (pUse.Index != cUse.Index)
  421. {
  422. return false;
  423. }
  424. if (pUse.Inverted != cUse.Inverted || (pUse.Node == null) != (cUse.Node == null))
  425. {
  426. return false;
  427. }
  428. if (pUse.Node != null && !Matches(pUse.Node, cUse.Node, externalRegs))
  429. {
  430. return false;
  431. }
  432. }
  433. }
  434. return true;
  435. }
  436. private static class PatternTrees
  437. {
  438. public static IPatternTreeNode[] GetFsiGetAddress()
  439. {
  440. var affinityValue = S2r(SReg.Affinity).Use(PT).Out;
  441. var orderingTicketValue = S2r(SReg.OrderingTicket).Use(PT).Out;
  442. return new IPatternTreeNode[]
  443. {
  444. Iscadd(cc: true, 2, 0, 404)
  445. .Use(PT)
  446. .Use(Iscadd(cc: false, 8)
  447. .Use(PT)
  448. .Use(Lop32i(LogicOp.And, 0xff)
  449. .Use(PT)
  450. .Use(affinityValue).Out)
  451. .Use(Lop32i(LogicOp.And, 0xff)
  452. .Use(PT)
  453. .Use(orderingTicketValue).Out).Out),
  454. ShrU32W(16)
  455. .Use(PT)
  456. .Use(orderingTicketValue),
  457. Iadd32i(0x200)
  458. .Use(PT)
  459. .Use(Lop32i(LogicOp.And, 0xfe00)
  460. .Use(PT)
  461. .Use(orderingTicketValue).Out),
  462. Iadd(x: true, 0, 405).Use(PT).Use(RZ),
  463. Ret().Use(PT)
  464. };
  465. }
  466. public static IPatternTreeNode[] GetFsiGetAddressV2()
  467. {
  468. var affinityValue = S2r(SReg.Affinity).Use(PT).Out;
  469. var orderingTicketValue = S2r(SReg.OrderingTicket).Use(PT).Out;
  470. return new IPatternTreeNode[]
  471. {
  472. ShrU32W(16)
  473. .Use(PT)
  474. .Use(orderingTicketValue),
  475. Iadd32i(0x200)
  476. .Use(PT)
  477. .Use(Lop32i(LogicOp.And, 0xfe00)
  478. .Use(PT)
  479. .Use(orderingTicketValue).Out),
  480. Iscadd(cc: true, 2, 0, 404)
  481. .Use(PT)
  482. .Use(Bfi(0x808)
  483. .Use(PT)
  484. .Use(affinityValue)
  485. .Use(Lop32i(LogicOp.And, 0xff)
  486. .Use(PT)
  487. .Use(orderingTicketValue).Out).Out),
  488. Iadd(x: true, 0, 405).Use(PT).Use(RZ),
  489. Ret().Use(PT)
  490. };
  491. }
  492. public static IPatternTreeNode[] GetFsiIsLastWarpThread()
  493. {
  494. var threadKillValue = S2r(SReg.ThreadKill).Use(PT).Out;
  495. var laneIdValue = S2r(SReg.LaneId).Use(PT).Out;
  496. return new IPatternTreeNode[]
  497. {
  498. IsetpU32(IComp.Eq)
  499. .Use(PT)
  500. .Use(PT)
  501. .Use(FloU32()
  502. .Use(PT)
  503. .Use(Vote(VoteMode.Any)
  504. .Use(PT)
  505. .Use(IsetpU32(IComp.Ne)
  506. .Use(PT)
  507. .Use(PT)
  508. .Use(Lop(negB: true, LogicOp.PassB)
  509. .Use(PT)
  510. .Use(RZ)
  511. .Use(threadKillValue).OutAt(1))
  512. .Use(RZ).Out).OutAt(1)).Out)
  513. .Use(laneIdValue),
  514. Ret().Use(PT)
  515. };
  516. }
  517. public static IPatternTreeNode[] GetFsiBeginPattern()
  518. {
  519. var addressLowValue = CallArg(1);
  520. static PatternTreeNodeUse HighU16Equals(PatternTreeNodeUse x)
  521. {
  522. var expectedValue = CallArg(3);
  523. return IsetpU32(IComp.Eq)
  524. .Use(PT)
  525. .Use(PT)
  526. .Use(ShrU32W(16).Use(PT).Use(x).Out)
  527. .Use(expectedValue).Out;
  528. }
  529. PatternTreeNode<byte> label;
  530. return new IPatternTreeNode[]
  531. {
  532. Cal(),
  533. Ret().Use(CallArg(0).Inv),
  534. Ret()
  535. .Use(HighU16Equals(LdgE(CacheOpLd.Cg, LsSize.B32)
  536. .Use(PT)
  537. .Use(addressLowValue).Out)),
  538. label = Label(),
  539. Bra()
  540. .Use(HighU16Equals(LdgE(CacheOpLd.Cg, LsSize.B32, 1)
  541. .Use(PT)
  542. .Use(addressLowValue).Out).Inv)
  543. .Use(label.Out),
  544. Ret().Use(PT)
  545. };
  546. }
  547. public static IPatternTreeNode[] GetFsiEndPattern()
  548. {
  549. var voteResult = Vote(VoteMode.All).Use(PT).Use(PT).OutAt(1);
  550. var popcResult = Popc().Use(PT).Use(voteResult).Out;
  551. var threadKillValue = S2r(SReg.ThreadKill).Use(PT).Out;
  552. var laneIdValue = S2r(SReg.LaneId).Use(PT).Out;
  553. var addressLowValue = CallArg(1);
  554. var incrementValue = CallArg(2);
  555. return new IPatternTreeNode[]
  556. {
  557. Cal(),
  558. Ret().Use(CallArg(0).Inv),
  559. Membar(Decoders.Membar.Vc).Use(PT),
  560. Ret().Use(IsetpU32(IComp.Ne)
  561. .Use(PT)
  562. .Use(PT)
  563. .Use(threadKillValue)
  564. .Use(RZ).Out),
  565. RedE(RedOp.Add, AtomSize.U32)
  566. .Use(IsetpU32(IComp.Eq)
  567. .Use(PT)
  568. .Use(PT)
  569. .Use(FloU32()
  570. .Use(PT)
  571. .Use(voteResult).Out)
  572. .Use(laneIdValue).Out)
  573. .Use(addressLowValue)
  574. .Use(Xmad(XmadCop.Cbcc, psl: true, hiloA: true, hiloB: true)
  575. .Use(PT)
  576. .Use(incrementValue)
  577. .Use(Xmad(XmadCop.Cfull, mrg: true, hiloB: true)
  578. .Use(PT)
  579. .Use(incrementValue)
  580. .Use(popcResult)
  581. .Use(RZ).Out)
  582. .Use(Xmad(XmadCop.Cfull)
  583. .Use(PT)
  584. .Use(incrementValue)
  585. .Use(popcResult)
  586. .Use(RZ).Out).Out),
  587. Ret().Use(PT)
  588. };
  589. }
  590. private static PatternTreeNode<InstBfiI> Bfi(int imm)
  591. {
  592. return new(InstName.Bfi, (op) => !op.WriteCC && op.Imm20 == imm, isImm: true);
  593. }
  594. private static PatternTreeNode<InstBra> Bra()
  595. {
  596. return new(InstName.Bra, (op) => op.Ccc == Ccc.T && !op.Ca);
  597. }
  598. private static PatternTreeNode<InstCal> Cal()
  599. {
  600. return new(InstName.Cal, (op) => !op.Ca && op.Inc);
  601. }
  602. private static PatternTreeNode<InstFloR> FloU32()
  603. {
  604. return new(InstName.Flo, (op) => !op.Signed && !op.Sh && !op.NegB && !op.WriteCC);
  605. }
  606. private static PatternTreeNode<InstIaddC> Iadd(bool x, int cbufSlot, int cbufOffset)
  607. {
  608. return new(InstName.Iadd, (op) =>
  609. !op.Sat &&
  610. !op.WriteCC &&
  611. op.X == x &&
  612. op.AvgMode == AvgMode.NoNeg &&
  613. op.CbufSlot == cbufSlot &&
  614. op.CbufOffset == cbufOffset);
  615. }
  616. private static PatternTreeNode<InstIadd32i> Iadd32i(int imm)
  617. {
  618. return new(InstName.Iadd32i, (op) => !op.Sat && !op.WriteCC && !op.X && op.AvgMode == AvgMode.NoNeg && op.Imm32 == imm);
  619. }
  620. private static PatternTreeNode<InstIscaddR> Iscadd(bool cc, int imm)
  621. {
  622. return new(InstName.Iscadd, (op) => op.WriteCC == cc && op.AvgMode == AvgMode.NoNeg && op.Imm5 == imm);
  623. }
  624. private static PatternTreeNode<InstIscaddC> Iscadd(bool cc, int imm, int cbufSlot, int cbufOffset)
  625. {
  626. return new(InstName.Iscadd, (op) =>
  627. op.WriteCC == cc &&
  628. op.AvgMode == AvgMode.NoNeg &&
  629. op.Imm5 == imm &&
  630. op.CbufSlot == cbufSlot &&
  631. op.CbufOffset == cbufOffset);
  632. }
  633. private static PatternTreeNode<InstIsetpR> IsetpU32(IComp comp)
  634. {
  635. return new(InstName.Isetp, (op) => !op.Signed && op.IComp == comp && op.Bop == BoolOp.And);
  636. }
  637. private static PatternTreeNode<byte> Label()
  638. {
  639. return new(InstName.Invalid, (op) => true, type: TreeNodeType.Label);
  640. }
  641. private static PatternTreeNode<InstLopR> Lop(bool negB, LogicOp logicOp)
  642. {
  643. return new(InstName.Lop, (op) => !op.NegA && op.NegB == negB && !op.WriteCC && !op.X && op.Lop == logicOp && op.PredicateOp == PredicateOp.F);
  644. }
  645. private static PatternTreeNode<InstLop32i> Lop32i(LogicOp logicOp, int imm)
  646. {
  647. return new(InstName.Lop32i, (op) => !op.NegA && !op.NegB && !op.X && !op.WriteCC && op.LogicOp == logicOp && op.Imm32 == imm);
  648. }
  649. private static PatternTreeNode<InstMembar> Membar(Membar membar)
  650. {
  651. return new(InstName.Membar, (op) => op.Membar == membar);
  652. }
  653. private static PatternTreeNode<InstPopcR> Popc()
  654. {
  655. return new(InstName.Popc, (op) => !op.NegB);
  656. }
  657. private static PatternTreeNode<InstRet> Ret()
  658. {
  659. return new(InstName.Ret, (op) => op.Ccc == Ccc.T);
  660. }
  661. private static PatternTreeNode<InstS2r> S2r(SReg reg)
  662. {
  663. return new(InstName.S2r, (op) => op.SReg == reg);
  664. }
  665. private static PatternTreeNode<InstShrI> ShrU32W(int imm)
  666. {
  667. return new(InstName.Shr, (op) => !op.Signed && !op.Brev && op.M && op.XMode == 0 && op.Imm20 == imm, isImm: true);
  668. }
  669. private static PatternTreeNode<InstLdg> LdgE(CacheOpLd cacheOp, LsSize size, byte order = 0)
  670. {
  671. return new(InstName.Ldg, (op) => op.E && op.CacheOp == cacheOp && op.LsSize == size, order: order);
  672. }
  673. private static PatternTreeNode<InstRed> RedE(RedOp redOp, AtomSize size, byte order = 0)
  674. {
  675. return new(InstName.Red, (op) => op.E && op.RedOp == redOp && op.RedSize == size, order: order);
  676. }
  677. private static PatternTreeNode<InstVote> Vote(VoteMode mode)
  678. {
  679. return new(InstName.Vote, (op) => op.VoteMode == mode);
  680. }
  681. private static PatternTreeNode<InstXmadR> Xmad(XmadCop cop, bool psl = false, bool mrg = false, bool hiloA = false, bool hiloB = false)
  682. {
  683. return new(InstName.Xmad, (op) => op.XmadCop == cop && op.Psl == psl && op.Mrg == mrg && op.HiloA == hiloA && op.HiloB == hiloB);
  684. }
  685. private static PatternTreeNodeUse PT => PTOrRZ();
  686. private static PatternTreeNodeUse RZ => PTOrRZ();
  687. private static PatternTreeNodeUse Undef => new PatternTreeNodeUse(0, null);
  688. private static PatternTreeNodeUse CallArg(int index)
  689. {
  690. return new PatternTreeNodeUse(-(index + 2), null);
  691. }
  692. private static PatternTreeNodeUse PTOrRZ()
  693. {
  694. return new PatternTreeNodeUse(-1, null);
  695. }
  696. }
  697. private static void PrintTreeNode(TreeNode node, string indentation)
  698. {
  699. Console.WriteLine($" {node.Op.Name}");
  700. for (int i = 0; i < node.Uses.Count; i++)
  701. {
  702. TreeNodeUse use = node.Uses[i];
  703. bool last = i == node.Uses.Count - 1;
  704. char separator = last ? '`' : '|';
  705. if (use.Node != null)
  706. {
  707. Console.Write($"{indentation} {separator}- ({(use.Inverted ? "INV " : "")}{use.Index})");
  708. PrintTreeNode(use.Node, indentation + (last ? " " : " | "));
  709. }
  710. else
  711. {
  712. Console.WriteLine($"{indentation} {separator}- ({(use.Inverted ? "INV " : "")}{use.Index}) NULL");
  713. }
  714. }
  715. }
  716. private static void PrintTreeNode(IPatternTreeNode node, string indentation)
  717. {
  718. Console.WriteLine($" {node.Name}");
  719. for (int i = 0; i < node.Uses.Count; i++)
  720. {
  721. PatternTreeNodeUse use = node.Uses[i];
  722. bool last = i == node.Uses.Count - 1;
  723. char separator = last ? '`' : '|';
  724. if (use.Node != null)
  725. {
  726. Console.Write($"{indentation} {separator}- ({(use.Inverted ? "INV " : "")}{use.Index})");
  727. PrintTreeNode(use.Node, indentation + (last ? " " : " | "));
  728. }
  729. else
  730. {
  731. Console.WriteLine($"{indentation} {separator}- ({(use.Inverted ? "INV " : "")}{use.Index}) NULL");
  732. }
  733. }
  734. }
  735. }
  736. }