InstGen.cs 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. using Ryujinx.Graphics.Shader.IntermediateRepresentation;
  2. using Ryujinx.Graphics.Shader.StructuredIr;
  3. using System;
  4. using static Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions.InstGenBallot;
  5. using static Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions.InstGenCall;
  6. using static Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions.InstGenHelper;
  7. using static Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions.InstGenMemory;
  8. using static Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions.InstGenPacking;
  9. using static Ryujinx.Graphics.Shader.StructuredIr.InstructionInfo;
  10. namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
  11. {
  12. static class InstGen
  13. {
  14. public static string GetExpression(CodeGenContext context, IAstNode node)
  15. {
  16. if (node is AstOperation operation)
  17. {
  18. return GetExpression(context, operation);
  19. }
  20. else if (node is AstOperand operand)
  21. {
  22. return context.OperandManager.GetExpression(operand, context.Config);
  23. }
  24. throw new ArgumentException($"Invalid node type \"{node?.GetType().Name ?? "null"}\".");
  25. }
  26. private static string GetExpression(CodeGenContext context, AstOperation operation)
  27. {
  28. Instruction inst = operation.Inst;
  29. InstInfo info = GetInstructionInfo(inst);
  30. if ((info.Type & InstType.Call) != 0)
  31. {
  32. bool atomic = (info.Type & InstType.Atomic) != 0;
  33. int arity = (int)(info.Type & InstType.ArityMask);
  34. string args = string.Empty;
  35. for (int argIndex = 0; argIndex < arity; argIndex++)
  36. {
  37. // For shared memory access, the second argument is unused and should be ignored.
  38. // It is there to make both storage and shared access have the same number of arguments.
  39. // For storage, both inputs are consumed when the argument index is 0, so we should skip it here.
  40. if (argIndex == 1 && (atomic || (inst & Instruction.MrMask) == Instruction.MrShared))
  41. {
  42. continue;
  43. }
  44. if (argIndex != 0)
  45. {
  46. args += ", ";
  47. }
  48. if (argIndex == 0 && atomic)
  49. {
  50. Instruction memRegion = inst & Instruction.MrMask;
  51. switch (memRegion)
  52. {
  53. case Instruction.MrShared: args += LoadShared(context, operation); break;
  54. case Instruction.MrStorage: args += LoadStorage(context, operation); break;
  55. default: throw new InvalidOperationException($"Invalid memory region \"{memRegion}\".");
  56. }
  57. }
  58. else
  59. {
  60. VariableType dstType = GetSrcVarType(inst, argIndex);
  61. args += GetSoureExpr(context, operation.GetSource(argIndex), dstType);
  62. }
  63. }
  64. return info.OpName + '(' + args + ')';
  65. }
  66. else if ((info.Type & InstType.Op) != 0)
  67. {
  68. string op = info.OpName;
  69. // Return may optionally have a return value (and in this case it is unary).
  70. if (inst == Instruction.Return && operation.SourcesCount != 0)
  71. {
  72. return $"{op} {GetSoureExpr(context, operation.GetSource(0), context.CurrentFunction.ReturnType)}";
  73. }
  74. int arity = (int)(info.Type & InstType.ArityMask);
  75. string[] expr = new string[arity];
  76. for (int index = 0; index < arity; index++)
  77. {
  78. IAstNode src = operation.GetSource(index);
  79. string srcExpr = GetSoureExpr(context, src, GetSrcVarType(inst, index));
  80. bool isLhs = arity == 2 && index == 0;
  81. expr[index] = Enclose(srcExpr, src, inst, info, isLhs);
  82. }
  83. switch (arity)
  84. {
  85. case 0:
  86. return op;
  87. case 1:
  88. return op + expr[0];
  89. case 2:
  90. return $"{expr[0]} {op} {expr[1]}";
  91. case 3:
  92. return $"{expr[0]} {op[0]} {expr[1]} {op[1]} {expr[2]}";
  93. }
  94. }
  95. else if ((info.Type & InstType.Special) != 0)
  96. {
  97. switch (inst)
  98. {
  99. case Instruction.Ballot:
  100. return Ballot(context, operation);
  101. case Instruction.Call:
  102. return Call(context, operation);
  103. case Instruction.ImageLoad:
  104. case Instruction.ImageStore:
  105. case Instruction.ImageAtomic:
  106. return ImageLoadOrStore(context, operation);
  107. case Instruction.LoadAttribute:
  108. return LoadAttribute(context, operation);
  109. case Instruction.LoadConstant:
  110. return LoadConstant(context, operation);
  111. case Instruction.LoadLocal:
  112. return LoadLocal(context, operation);
  113. case Instruction.LoadShared:
  114. return LoadShared(context, operation);
  115. case Instruction.LoadStorage:
  116. return LoadStorage(context, operation);
  117. case Instruction.Lod:
  118. return Lod(context, operation);
  119. case Instruction.PackDouble2x32:
  120. return PackDouble2x32(context, operation);
  121. case Instruction.PackHalf2x16:
  122. return PackHalf2x16(context, operation);
  123. case Instruction.StoreAttribute:
  124. return StoreAttribute(context, operation);
  125. case Instruction.StoreLocal:
  126. return StoreLocal(context, operation);
  127. case Instruction.StoreShared:
  128. return StoreShared(context, operation);
  129. case Instruction.StoreStorage:
  130. return StoreStorage(context, operation);
  131. case Instruction.TextureSample:
  132. return TextureSample(context, operation);
  133. case Instruction.TextureSize:
  134. return TextureSize(context, operation);
  135. case Instruction.UnpackDouble2x32:
  136. return UnpackDouble2x32(context, operation);
  137. case Instruction.UnpackHalf2x16:
  138. return UnpackHalf2x16(context, operation);
  139. }
  140. }
  141. throw new InvalidOperationException($"Unexpected instruction type \"{info.Type}\".");
  142. }
  143. }
  144. }