IRDumper.cs 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. using ARMeilleure.IntermediateRepresentation;
  2. using ARMeilleure.Translation;
  3. using System;
  4. using System.Collections.Generic;
  5. using System.Text;
  6. namespace ARMeilleure.Diagnostics
  7. {
  8. static class IRDumper
  9. {
  10. private const string Indentation = " ";
  11. public static string GetDump(ControlFlowGraph cfg)
  12. {
  13. StringBuilder sb = new StringBuilder();
  14. Dictionary<Operand, string> localNames = new Dictionary<Operand, string>();
  15. string indentation = string.Empty;
  16. void IncreaseIndentation()
  17. {
  18. indentation += Indentation;
  19. }
  20. void DecreaseIndentation()
  21. {
  22. indentation = indentation.Substring(0, indentation.Length - Indentation.Length);
  23. }
  24. void AppendLine(string text)
  25. {
  26. sb.AppendLine(indentation + text);
  27. }
  28. IncreaseIndentation();
  29. foreach (BasicBlock block in cfg.Blocks)
  30. {
  31. string blockName = GetBlockName(block);
  32. if (block.Next != null)
  33. {
  34. blockName += $" (next {GetBlockName(block.Next)})";
  35. }
  36. if (block.Branch != null)
  37. {
  38. blockName += $" (branch {GetBlockName(block.Branch)})";
  39. }
  40. blockName += ":";
  41. AppendLine(blockName);
  42. IncreaseIndentation();
  43. foreach (Node node in block.Operations)
  44. {
  45. string[] sources = new string[node.SourcesCount];
  46. string instName = string.Empty;
  47. if (node is PhiNode phi)
  48. {
  49. for (int index = 0; index < sources.Length; index++)
  50. {
  51. string phiBlockName = GetBlockName(phi.GetBlock(index));
  52. string operName = GetOperandName(phi.GetSource(index), localNames);
  53. sources[index] = $"({phiBlockName}: {operName})";
  54. }
  55. instName = "Phi";
  56. }
  57. else if (node is Operation operation)
  58. {
  59. for (int index = 0; index < sources.Length; index++)
  60. {
  61. sources[index] = GetOperandName(operation.GetSource(index), localNames);
  62. }
  63. instName = operation.Instruction.ToString();
  64. }
  65. string allSources = string.Join(", ", sources);
  66. string line = instName + " " + allSources;
  67. if (node.Destination != null)
  68. {
  69. line = GetOperandName(node.Destination, localNames) + " = " + line;
  70. }
  71. AppendLine(line);
  72. }
  73. DecreaseIndentation();
  74. }
  75. return sb.ToString();
  76. }
  77. private static string GetBlockName(BasicBlock block)
  78. {
  79. return $"block{block.Index}";
  80. }
  81. private static string GetOperandName(Operand operand, Dictionary<Operand, string> localNames)
  82. {
  83. if (operand == null)
  84. {
  85. return "<NULL>";
  86. }
  87. string name = string.Empty;
  88. if (operand.Kind == OperandKind.LocalVariable)
  89. {
  90. if (!localNames.TryGetValue(operand, out string localName))
  91. {
  92. localName = "%" + localNames.Count;
  93. localNames.Add(operand, localName);
  94. }
  95. name = localName;
  96. }
  97. else if (operand.Kind == OperandKind.Register)
  98. {
  99. Register reg = operand.GetRegister();
  100. switch (reg.Type)
  101. {
  102. case RegisterType.Flag: name = "b" + reg.Index; break;
  103. case RegisterType.Integer: name = "r" + reg.Index; break;
  104. case RegisterType.Vector: name = "v" + reg.Index; break;
  105. }
  106. }
  107. else if (operand.Kind == OperandKind.Constant)
  108. {
  109. name = "0x" + operand.Value.ToString("X");
  110. }
  111. else
  112. {
  113. name = operand.Kind.ToString().ToLower();
  114. }
  115. return GetTypeName(operand.Type) + " " + name;
  116. }
  117. private static string GetTypeName(OperandType type)
  118. {
  119. switch (type)
  120. {
  121. case OperandType.FP32: return "f32";
  122. case OperandType.FP64: return "f64";
  123. case OperandType.I32: return "i32";
  124. case OperandType.I64: return "i64";
  125. case OperandType.None: return "none";
  126. case OperandType.V128: return "v128";
  127. }
  128. throw new ArgumentException($"Invalid operand type \"{type}\".");
  129. }
  130. }
  131. }