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