IRDumper.cs 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. using ARMeilleure.IntermediateRepresentation;
  2. using ARMeilleure.Translation;
  3. using System;
  4. using System.Collections.Generic;
  5. using System.Linq;
  6. using System.Text;
  7. namespace ARMeilleure.Diagnostics
  8. {
  9. class IRDumper
  10. {
  11. private const string Indentation = " ";
  12. private int _indentLevel;
  13. private readonly StringBuilder _builder;
  14. private readonly Dictionary<Operand, string> _localNames;
  15. private readonly Dictionary<ulong, string> _symbolNames;
  16. private IRDumper(int indent)
  17. {
  18. _indentLevel = indent;
  19. _builder = new StringBuilder();
  20. _localNames = new Dictionary<Operand, string>();
  21. _symbolNames = new Dictionary<ulong, string>();
  22. }
  23. private void Indent()
  24. {
  25. _builder.EnsureCapacity(_builder.Capacity + _indentLevel * Indentation.Length);
  26. for (int index = 0; index < _indentLevel; index++)
  27. {
  28. _builder.Append(Indentation);
  29. }
  30. }
  31. private void IncreaseIndentation()
  32. {
  33. _indentLevel++;
  34. }
  35. private void DecreaseIndentation()
  36. {
  37. _indentLevel--;
  38. }
  39. private void DumpBlockName(BasicBlock block)
  40. {
  41. _builder.Append("block").Append(block.Index);
  42. }
  43. private void DumpBlockHeader(BasicBlock block)
  44. {
  45. DumpBlockName(block);
  46. if (block.Next != null)
  47. {
  48. _builder.Append(" (next ");
  49. DumpBlockName(block.Next);
  50. _builder.Append(')');
  51. }
  52. if (block.Branch != null)
  53. {
  54. _builder.Append(" (branch ");
  55. DumpBlockName(block.Branch);
  56. _builder.Append(')');
  57. }
  58. _builder.Append(':');
  59. }
  60. private void DumpOperand(Operand operand)
  61. {
  62. if (operand == null)
  63. {
  64. _builder.Append("<NULL>");
  65. return;
  66. }
  67. _builder.Append(GetTypeName(operand.Type)).Append(' ');
  68. switch (operand.Kind)
  69. {
  70. case OperandKind.LocalVariable:
  71. if (!_localNames.TryGetValue(operand, out string localName))
  72. {
  73. localName = $"%{_localNames.Count}";
  74. _localNames.Add(operand, localName);
  75. }
  76. _builder.Append(localName);
  77. break;
  78. case OperandKind.Register:
  79. Register reg = operand.GetRegister();
  80. switch (reg.Type)
  81. {
  82. case RegisterType.Flag: _builder.Append('b'); break;
  83. case RegisterType.FpFlag: _builder.Append('f'); break;
  84. case RegisterType.Integer: _builder.Append('r'); break;
  85. case RegisterType.Vector: _builder.Append('v'); break;
  86. }
  87. _builder.Append(reg.Index);
  88. break;
  89. case OperandKind.Constant:
  90. string symbolName = Symbols.Get(operand.Value);
  91. if (symbolName != null && !_symbolNames.ContainsKey(operand.Value))
  92. {
  93. _symbolNames.Add(operand.Value, symbolName);
  94. }
  95. _builder.Append("0x").Append(operand.Value.ToString("X"));
  96. break;
  97. case OperandKind.Memory:
  98. var memOp = (MemoryOperand)operand;
  99. _builder.Append('[');
  100. DumpOperand(memOp.BaseAddress);
  101. if (memOp.Index != null)
  102. {
  103. _builder.Append(" + ");
  104. DumpOperand(memOp.Index);
  105. switch (memOp.Scale)
  106. {
  107. case Multiplier.x2: _builder.Append("*2"); break;
  108. case Multiplier.x4: _builder.Append("*4"); break;
  109. case Multiplier.x8: _builder.Append("*8"); break;
  110. }
  111. }
  112. if (memOp.Displacement != 0)
  113. {
  114. _builder.Append(" + 0x").Append(memOp.Displacement.ToString("X"));
  115. }
  116. _builder.Append(']');
  117. break;
  118. default:
  119. _builder.Append(operand.Type);
  120. break;
  121. }
  122. }
  123. private void DumpNode(Node node)
  124. {
  125. for (int index = 0; index < node.DestinationsCount; index++)
  126. {
  127. DumpOperand(node.GetDestination(index));
  128. if (index == node.DestinationsCount - 1)
  129. {
  130. _builder.Append(" = ");
  131. }
  132. else
  133. {
  134. _builder.Append(", ");
  135. }
  136. }
  137. switch (node)
  138. {
  139. case PhiNode phi:
  140. _builder.Append("Phi ");
  141. for (int index = 0; index < phi.SourcesCount; index++)
  142. {
  143. _builder.Append('(');
  144. DumpBlockName(phi.GetBlock(index));
  145. _builder.Append(": ");
  146. DumpOperand(phi.GetSource(index));
  147. _builder.Append(')');
  148. if (index < phi.SourcesCount - 1)
  149. {
  150. _builder.Append(", ");
  151. }
  152. }
  153. break;
  154. case Operation operation:
  155. _builder.Append(operation.Instruction);
  156. if (operation.Instruction == Instruction.Extended)
  157. {
  158. var intrinOp = (IntrinsicOperation)operation;
  159. _builder.Append('.').Append(intrinOp.Intrinsic);
  160. }
  161. _builder.Append(' ');
  162. for (int index = 0; index < operation.SourcesCount; index++)
  163. {
  164. DumpOperand(operation.GetSource(index));
  165. if (index < operation.SourcesCount - 1)
  166. {
  167. _builder.Append(", ");
  168. }
  169. }
  170. break;
  171. }
  172. if (_symbolNames.Count == 1)
  173. {
  174. _builder.Append(" ;; ").Append(_symbolNames.First().Value);
  175. }
  176. else if (_symbolNames.Count > 1)
  177. {
  178. _builder.Append(" ;;");
  179. foreach ((ulong value, string name) in _symbolNames)
  180. {
  181. _builder.Append(" 0x").Append(value.ToString("X")).Append(" = ").Append(name);
  182. }
  183. }
  184. // Reset the set of symbols for the next Node we're going to dump.
  185. _symbolNames.Clear();
  186. }
  187. public static string GetDump(ControlFlowGraph cfg)
  188. {
  189. var dumper = new IRDumper(1);
  190. for (BasicBlock block = cfg.Blocks.First; block != null; block = block.ListNext)
  191. {
  192. dumper.Indent();
  193. dumper.DumpBlockHeader(block);
  194. dumper._builder.AppendLine();
  195. dumper.IncreaseIndentation();
  196. for (Node node = block.Operations.First; node != null; node = node.ListNext)
  197. {
  198. dumper.Indent();
  199. dumper.DumpNode(node);
  200. dumper._builder.AppendLine();
  201. }
  202. dumper.DecreaseIndentation();
  203. }
  204. return dumper._builder.ToString();
  205. }
  206. private static string GetTypeName(OperandType type)
  207. {
  208. return type switch
  209. {
  210. OperandType.None => "none",
  211. OperandType.I32 => "i32",
  212. OperandType.I64 => "i64",
  213. OperandType.FP32 => "f32",
  214. OperandType.FP64 => "f64",
  215. OperandType.V128 => "v128",
  216. _ => throw new ArgumentException($"Invalid operand type \"{type}\"."),
  217. };
  218. }
  219. }
  220. }