IRDumper.cs
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 8 namespace ARMeilleure.Diagnostics 9 { 10 class IRDumper 11 { 12 private const string Indentation = " "; 13 14 private int _indentLevel; 15 16 private readonly StringBuilder _builder; 17 18 private readonly Dictionary<Operand, string> _localNames; 19 private readonly Dictionary<ulong, string> _symbolNames; 20 21 public IRDumper(int indent) 22 { 23 _indentLevel = indent; 24 25 _builder = new StringBuilder(); 26 27 _localNames = new Dictionary<Operand, string>(); 28 _symbolNames = new Dictionary<ulong, string>(); 29 } 30 31 private void Indent() 32 { 33 _builder.EnsureCapacity(_builder.Capacity + _indentLevel * Indentation.Length); 34 35 for (int index = 0; index < _indentLevel; index++) 36 { 37 #pragma warning disable CA1834 // Use StringBuilder.Append(char) for single character strings 38 _builder.Append(Indentation); 39 #pragma warning restore CA1834 40 } 41 } 42 43 private void IncreaseIndentation() 44 { 45 _indentLevel++; 46 } 47 48 private void DecreaseIndentation() 49 { 50 _indentLevel--; 51 } 52 53 private void DumpBlockName(BasicBlock block) 54 { 55 _builder.Append("block").Append(block.Index); 56 } 57 58 private void DumpBlockHeader(BasicBlock block) 59 { 60 DumpBlockName(block); 61 62 if (block.Frequency == BasicBlockFrequency.Cold) 63 { 64 _builder.Append(" cold"); 65 } 66 67 if (block.SuccessorsCount > 0) 68 { 69 _builder.Append(" ("); 70 71 for (int i = 0; i < block.SuccessorsCount; i++) 72 { 73 DumpBlockName(block.GetSuccessor(i)); 74 75 if (i < block.SuccessorsCount - 1) 76 { 77 _builder.Append(", "); 78 } 79 } 80 81 _builder.Append(')'); 82 } 83 84 _builder.Append(':'); 85 } 86 87 private void DumpOperand(Operand operand) 88 { 89 if (operand == default) 90 { 91 _builder.Append("<NULL>"); 92 return; 93 } 94 95 _builder.Append(GetTypeName(operand.Type)).Append(' '); 96 97 switch (operand.Kind) 98 { 99 case OperandKind.LocalVariable: 100 if (!_localNames.TryGetValue(operand, out string localName)) 101 { 102 localName = $"%{_localNames.Count}"; 103 104 _localNames.Add(operand, localName); 105 } 106 107 _builder.Append(localName); 108 break; 109 110 case OperandKind.Register: 111 Register reg = operand.GetRegister(); 112 113 switch (reg.Type) 114 { 115 case RegisterType.Flag: 116 _builder.Append('b'); 117 break; 118 case RegisterType.FpFlag: 119 _builder.Append('f'); 120 break; 121 case RegisterType.Integer: 122 _builder.Append('r'); 123 break; 124 case RegisterType.Vector: 125 _builder.Append('v'); 126 break; 127 } 128 129 _builder.Append(reg.Index); 130 break; 131 132 case OperandKind.Constant: 133 string symbolName = Symbols.Get(operand.Value); 134 135 if (symbolName != null && !_symbolNames.ContainsKey(operand.Value)) 136 { 137 _symbolNames.Add(operand.Value, symbolName); 138 } 139 140 _builder.Append("0x").Append(operand.Value.ToString("X")); 141 break; 142 143 case OperandKind.Memory: 144 var memOp = operand.GetMemory(); 145 146 _builder.Append('['); 147 148 DumpOperand(memOp.BaseAddress); 149 150 if (memOp.Index != default) 151 { 152 _builder.Append(" + "); 153 154 DumpOperand(memOp.Index); 155 156 switch (memOp.Scale) 157 { 158 case Multiplier.x2: 159 _builder.Append("*2"); 160 break; 161 case Multiplier.x4: 162 _builder.Append("*4"); 163 break; 164 case Multiplier.x8: 165 _builder.Append("*8"); 166 break; 167 } 168 } 169 170 if (memOp.Displacement != 0) 171 { 172 _builder.Append(" + 0x").Append(memOp.Displacement.ToString("X")); 173 } 174 175 _builder.Append(']'); 176 break; 177 178 default: 179 _builder.Append(operand.Type); 180 break; 181 } 182 } 183 184 private void DumpNode(ControlFlowGraph cfg, Operation node) 185 { 186 for (int index = 0; index < node.DestinationsCount; index++) 187 { 188 DumpOperand(node.GetDestination(index)); 189 190 if (index == node.DestinationsCount - 1) 191 { 192 _builder.Append(" = "); 193 } 194 else 195 { 196 _builder.Append(", "); 197 } 198 } 199 200 switch (node) 201 { 202 case Operation operation: 203 if (operation.Instruction == Instruction.Phi) 204 { 205 PhiOperation phi = operation.AsPhi(); 206 207 _builder.Append("Phi "); 208 209 for (int index = 0; index < phi.SourcesCount; index++) 210 { 211 _builder.Append('('); 212 213 DumpBlockName(phi.GetBlock(cfg, index)); 214 215 _builder.Append(": "); 216 217 DumpOperand(phi.GetSource(index)); 218 219 _builder.Append(')'); 220 221 if (index < phi.SourcesCount - 1) 222 { 223 _builder.Append(", "); 224 } 225 } 226 227 break; 228 } 229 230 bool comparison = false; 231 232 _builder.Append(operation.Instruction); 233 234 if (operation.Instruction == Instruction.Extended) 235 { 236 _builder.Append('.').Append(operation.Intrinsic); 237 } 238 else if (operation.Instruction == Instruction.BranchIf || 239 operation.Instruction == Instruction.Compare) 240 { 241 comparison = true; 242 } 243 244 _builder.Append(' '); 245 246 for (int index = 0; index < operation.SourcesCount; index++) 247 { 248 Operand source = operation.GetSource(index); 249 250 if (index < operation.SourcesCount - 1) 251 { 252 DumpOperand(source); 253 254 _builder.Append(", "); 255 } 256 else if (comparison) 257 { 258 _builder.Append((Comparison)source.AsInt32()); 259 } 260 else 261 { 262 DumpOperand(source); 263 } 264 } 265 break; 266 } 267 268 if (_symbolNames.Count == 1) 269 { 270 _builder.Append(" ;; ").Append(_symbolNames.First().Value); 271 } 272 else if (_symbolNames.Count > 1) 273 { 274 _builder.Append(" ;;"); 275 276 foreach ((ulong value, string name) in _symbolNames) 277 { 278 _builder.Append(" 0x").Append(value.ToString("X")).Append(" = ").Append(name); 279 } 280 } 281 282 // Reset the set of symbols for the next Node we're going to dump. 283 _symbolNames.Clear(); 284 } 285 286 public static string GetDump(ControlFlowGraph cfg) 287 { 288 var dumper = new IRDumper(1); 289 290 for (BasicBlock block = cfg.Blocks.First; block != null; block = block.ListNext) 291 { 292 dumper.Indent(); 293 dumper.DumpBlockHeader(block); 294 295 dumper._builder.AppendLine(); 296 297 dumper.IncreaseIndentation(); 298 299 for (Operation node = block.Operations.First; node != default; node = node.ListNext) 300 { 301 dumper.Indent(); 302 dumper.DumpNode(cfg, node); 303 304 dumper._builder.AppendLine(); 305 } 306 307 dumper.DecreaseIndentation(); 308 } 309 310 return dumper._builder.ToString(); 311 } 312 313 private static string GetTypeName(OperandType type) 314 { 315 return type switch 316 { 317 OperandType.None => "none", 318 OperandType.I32 => "i32", 319 OperandType.I64 => "i64", 320 OperandType.FP32 => "f32", 321 OperandType.FP64 => "f64", 322 OperandType.V128 => "v128", 323 _ => throw new ArgumentException($"Invalid operand type \"{type}\"."), 324 }; 325 } 326 } 327 }