diff options
Diffstat (limited to 'src/ARMeilleure/Diagnostics/IRDumper.cs')
| -rw-r--r-- | src/ARMeilleure/Diagnostics/IRDumper.cs | 311 |
1 files changed, 311 insertions, 0 deletions
diff --git a/src/ARMeilleure/Diagnostics/IRDumper.cs b/src/ARMeilleure/Diagnostics/IRDumper.cs new file mode 100644 index 00000000..3d1a60e5 --- /dev/null +++ b/src/ARMeilleure/Diagnostics/IRDumper.cs @@ -0,0 +1,311 @@ +using ARMeilleure.IntermediateRepresentation; +using ARMeilleure.Translation; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace ARMeilleure.Diagnostics +{ + class IRDumper + { + private const string Indentation = " "; + + private int _indentLevel; + + private readonly StringBuilder _builder; + + private readonly Dictionary<Operand, string> _localNames; + private readonly Dictionary<ulong, string> _symbolNames; + + public IRDumper(int indent) + { + _indentLevel = indent; + + _builder = new StringBuilder(); + + _localNames = new Dictionary<Operand, string>(); + _symbolNames = new Dictionary<ulong, string>(); + } + + private void Indent() + { + _builder.EnsureCapacity(_builder.Capacity + _indentLevel * Indentation.Length); + + for (int index = 0; index < _indentLevel; index++) + { + _builder.Append(Indentation); + } + } + + private void IncreaseIndentation() + { + _indentLevel++; + } + + private void DecreaseIndentation() + { + _indentLevel--; + } + + private void DumpBlockName(BasicBlock block) + { + _builder.Append("block").Append(block.Index); + } + + private void DumpBlockHeader(BasicBlock block) + { + DumpBlockName(block); + + if (block.Frequency == BasicBlockFrequency.Cold) + { + _builder.Append(" cold"); + } + + if (block.SuccessorsCount > 0) + { + _builder.Append(" ("); + + for (int i = 0; i < block.SuccessorsCount; i++) + { + DumpBlockName(block.GetSuccessor(i)); + + if (i < block.SuccessorsCount - 1) + { + _builder.Append(", "); + } + } + + _builder.Append(')'); + } + + _builder.Append(':'); + } + + private void DumpOperand(Operand operand) + { + if (operand == default) + { + _builder.Append("<NULL>"); + return; + } + + _builder.Append(GetTypeName(operand.Type)).Append(' '); + + switch (operand.Kind) + { + case OperandKind.LocalVariable: + if (!_localNames.TryGetValue(operand, out string localName)) + { + localName = $"%{_localNames.Count}"; + + _localNames.Add(operand, localName); + } + + _builder.Append(localName); + break; + + case OperandKind.Register: + Register reg = operand.GetRegister(); + + switch (reg.Type) + { + case RegisterType.Flag: _builder.Append('b'); break; + case RegisterType.FpFlag: _builder.Append('f'); break; + case RegisterType.Integer: _builder.Append('r'); break; + case RegisterType.Vector: _builder.Append('v'); break; + } + + _builder.Append(reg.Index); + break; + + case OperandKind.Constant: + string symbolName = Symbols.Get(operand.Value); + + if (symbolName != null && !_symbolNames.ContainsKey(operand.Value)) + { + _symbolNames.Add(operand.Value, symbolName); + } + + _builder.Append("0x").Append(operand.Value.ToString("X")); + break; + + case OperandKind.Memory: + var memOp = operand.GetMemory(); + + _builder.Append('['); + + DumpOperand(memOp.BaseAddress); + + if (memOp.Index != default) + { + _builder.Append(" + "); + + DumpOperand(memOp.Index); + + switch (memOp.Scale) + { + case Multiplier.x2: _builder.Append("*2"); break; + case Multiplier.x4: _builder.Append("*4"); break; + case Multiplier.x8: _builder.Append("*8"); break; + } + } + + if (memOp.Displacement != 0) + { + _builder.Append(" + 0x").Append(memOp.Displacement.ToString("X")); + } + + _builder.Append(']'); + break; + + default: + _builder.Append(operand.Type); + break; + } + } + + private void DumpNode(ControlFlowGraph cfg, Operation node) + { + for (int index = 0; index < node.DestinationsCount; index++) + { + DumpOperand(node.GetDestination(index)); + + if (index == node.DestinationsCount - 1) + { + _builder.Append(" = "); + } + else + { + _builder.Append(", "); + } + } + + switch (node) + { + case Operation operation: + if (operation.Instruction == Instruction.Phi) + { + PhiOperation phi = operation.AsPhi(); + + _builder.Append("Phi "); + + for (int index = 0; index < phi.SourcesCount; index++) + { + _builder.Append('('); + + DumpBlockName(phi.GetBlock(cfg, index)); + + _builder.Append(": "); + + DumpOperand(phi.GetSource(index)); + + _builder.Append(')'); + + if (index < phi.SourcesCount - 1) + { + _builder.Append(", "); + } + } + + break; + } + + bool comparison = false; + + _builder.Append(operation.Instruction); + + if (operation.Instruction == Instruction.Extended) + { + _builder.Append('.').Append(operation.Intrinsic); + } + else if (operation.Instruction == Instruction.BranchIf || + operation.Instruction == Instruction.Compare) + { + comparison = true; + } + + _builder.Append(' '); + + for (int index = 0; index < operation.SourcesCount; index++) + { + Operand source = operation.GetSource(index); + + if (index < operation.SourcesCount - 1) + { + DumpOperand(source); + + _builder.Append(", "); + } + else if (comparison) + { + _builder.Append((Comparison)source.AsInt32()); + } + else + { + DumpOperand(source); + } + } + break; + } + + if (_symbolNames.Count == 1) + { + _builder.Append(" ;; ").Append(_symbolNames.First().Value); + } + else if (_symbolNames.Count > 1) + { + _builder.Append(" ;;"); + + foreach ((ulong value, string name) in _symbolNames) + { + _builder.Append(" 0x").Append(value.ToString("X")).Append(" = ").Append(name); + } + } + + // Reset the set of symbols for the next Node we're going to dump. + _symbolNames.Clear(); + } + + public static string GetDump(ControlFlowGraph cfg) + { + var dumper = new IRDumper(1); + + for (BasicBlock block = cfg.Blocks.First; block != null; block = block.ListNext) + { + dumper.Indent(); + dumper.DumpBlockHeader(block); + + dumper._builder.AppendLine(); + + dumper.IncreaseIndentation(); + + for (Operation node = block.Operations.First; node != default; node = node.ListNext) + { + dumper.Indent(); + dumper.DumpNode(cfg, node); + + dumper._builder.AppendLine(); + } + + dumper.DecreaseIndentation(); + } + + return dumper._builder.ToString(); + } + + private static string GetTypeName(OperandType type) + { + return type switch + { + OperandType.None => "none", + OperandType.I32 => "i32", + OperandType.I64 => "i64", + OperandType.FP32 => "f32", + OperandType.FP64 => "f64", + OperandType.V128 => "v128", + _ => throw new ArgumentException($"Invalid operand type \"{type}\"."), + }; + } + } +}
\ No newline at end of file |
