InstEmitFlow.cs 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. using Ryujinx.Graphics.Shader.Decoders;
  2. using Ryujinx.Graphics.Shader.IntermediateRepresentation;
  3. using Ryujinx.Graphics.Shader.Translation;
  4. using System.Collections.Generic;
  5. using System.Linq;
  6. using static Ryujinx.Graphics.Shader.IntermediateRepresentation.OperandHelper;
  7. namespace Ryujinx.Graphics.Shader.Instructions
  8. {
  9. static partial class InstEmit
  10. {
  11. public static void Bra(EmitterContext context)
  12. {
  13. EmitBranch(context, context.CurrBlock.Branch.Address);
  14. }
  15. public static void Brk(EmitterContext context)
  16. {
  17. EmitBrkOrSync(context);
  18. }
  19. public static void Exit(EmitterContext context)
  20. {
  21. OpCodeExit op = (OpCodeExit)context.CurrOp;
  22. // TODO: Figure out how this is supposed to work in the
  23. // presence of other condition codes.
  24. if (op.Condition == Condition.Always)
  25. {
  26. context.Return();
  27. }
  28. }
  29. public static void Kil(EmitterContext context)
  30. {
  31. context.Discard();
  32. }
  33. public static void Pbk(EmitterContext context)
  34. {
  35. EmitPbkOrSsy(context);
  36. }
  37. public static void Ssy(EmitterContext context)
  38. {
  39. EmitPbkOrSsy(context);
  40. }
  41. public static void Sync(EmitterContext context)
  42. {
  43. EmitBrkOrSync(context);
  44. }
  45. private static void EmitPbkOrSsy(EmitterContext context)
  46. {
  47. OpCodeSsy op = (OpCodeSsy)context.CurrOp;
  48. foreach (KeyValuePair<OpCodeSync, Operand> kv in op.Syncs)
  49. {
  50. OpCodeSync opSync = kv.Key;
  51. Operand local = kv.Value;
  52. int ssyIndex = opSync.Targets[op];
  53. context.Copy(local, Const(ssyIndex));
  54. }
  55. }
  56. private static void EmitBrkOrSync(EmitterContext context)
  57. {
  58. OpCodeSync op = (OpCodeSync)context.CurrOp;
  59. if (op.Targets.Count == 1)
  60. {
  61. // If we have only one target, then the SSY is basically
  62. // a branch, we can produce better codegen for this case.
  63. OpCodeSsy opSsy = op.Targets.Keys.First();
  64. EmitBranch(context, opSsy.GetAbsoluteAddress());
  65. }
  66. else
  67. {
  68. foreach (KeyValuePair<OpCodeSsy, int> kv in op.Targets)
  69. {
  70. OpCodeSsy opSsy = kv.Key;
  71. Operand label = context.GetLabel(opSsy.GetAbsoluteAddress());
  72. Operand local = opSsy.Syncs[op];
  73. int ssyIndex = kv.Value;
  74. context.BranchIfTrue(label, context.ICompareEqual(local, Const(ssyIndex)));
  75. }
  76. }
  77. }
  78. private static void EmitBranch(EmitterContext context, ulong address)
  79. {
  80. // If we're branching to the next instruction, then the branch
  81. // is useless and we can ignore it.
  82. if (address == context.CurrOp.Address + 8)
  83. {
  84. return;
  85. }
  86. Operand label = context.GetLabel(address);
  87. Operand pred = Register(context.CurrOp.Predicate);
  88. if (context.CurrOp.Predicate.IsPT)
  89. {
  90. context.Branch(label);
  91. }
  92. else if (context.CurrOp.InvertPredicate)
  93. {
  94. context.BranchIfFalse(label, pred);
  95. }
  96. else
  97. {
  98. context.BranchIfTrue(label, pred);
  99. }
  100. }
  101. }
  102. }