Просмотр исходного кода

Improve IRDumper (#1135)

* Improve IRDumper

* Make Symbols.Add(ulong, ulong, ulong, string) thread safe

* Use a StringBuilder for MemoryOperand

* Add #if M_DEBUG guards

* Fix JMP_TABLE typo

* Fix using in Symbols

* Use Conditional("M_DEBUG") instead

Address gdkchan's feedback

* Use a struct instead of 4-tuple

Address gdkchan's feedback

* Place symbols in comments instead

Address gdkchan's feedback

* Use StringBuilder throughout

* Handle offsetted symbols

* Fix naming convention of Builder

* Avoid ArgumentException

* Remove unnecessary using

* Use switch expression instead

* Turn into a class

* Clean up

* Remove unnecessary using
Ficture Seven 6 лет назад
Родитель
Сommit
180ad8605d

+ 209 - 95
ARMeilleure/Diagnostics/IRDumper.cs

@@ -2,168 +2,282 @@ using ARMeilleure.IntermediateRepresentation;
 using ARMeilleure.Translation;
 using ARMeilleure.Translation;
 using System;
 using System;
 using System.Collections.Generic;
 using System.Collections.Generic;
+using System.Linq;
 using System.Text;
 using System.Text;
 
 
 namespace ARMeilleure.Diagnostics
 namespace ARMeilleure.Diagnostics
 {
 {
-    static class IRDumper
+    class IRDumper
     {
     {
         private const string Indentation = " ";
         private const string Indentation = " ";
 
 
-        public static string GetDump(ControlFlowGraph cfg)
+        private int _indentLevel;
+
+        private readonly StringBuilder _builder;
+
+        private readonly Dictionary<Operand, string> _localNames;
+        private readonly Dictionary<ulong, string> _symbolNames;
+
+        private IRDumper(int indent)
         {
         {
-            StringBuilder sb = new StringBuilder();
+            _indentLevel = indent;
 
 
-            Dictionary<Operand, string> localNames = new Dictionary<Operand, string>();
+            _builder = new StringBuilder();
 
 
-            string indentation = string.Empty;
+            _localNames = new Dictionary<Operand, string>();
+            _symbolNames = new Dictionary<ulong, string>();
+        }
+
+        private void Indent()
+        {
+            _builder.EnsureCapacity(_builder.Capacity + _indentLevel * Indentation.Length);
 
 
-            void IncreaseIndentation()
+            for (int index = 0; index < _indentLevel; index++)
             {
             {
-                indentation += Indentation;
+                _builder.Append(Indentation);
             }
             }
+        }
+
+        private void IncreaseIndentation()
+        {
+            _indentLevel++;
+        }
+
+        private void DecreaseIndentation()
+        {
+            _indentLevel--;
+        }
+
+        private void DumpBlockName(BasicBlock block)
+        {
+            _builder.Append("block").Append(block.Index);
+        }
 
 
-            void DecreaseIndentation()
+        private void DumpBlockHeader(BasicBlock block)
+        {
+            DumpBlockName(block);
+
+            if (block.Next != null)
             {
             {
-                indentation = indentation.Substring(0, indentation.Length - Indentation.Length);
+                _builder.Append(" (next ");
+                DumpBlockName(block.Next);
+                _builder.Append(')');
             }
             }
 
 
-            void AppendLine(string text)
+            if (block.Branch != null)
             {
             {
-                sb.AppendLine(indentation + text);
+                _builder.Append(" (branch ");
+                DumpBlockName(block.Branch);
+                _builder.Append(')');
             }
             }
 
 
-            IncreaseIndentation();
+            _builder.Append(':');
+        }
 
 
-            for (BasicBlock block = cfg.Blocks.First; block != null; block = block.ListNext)
+        private void DumpOperand(Operand operand)
+        {
+            if (operand == null)
             {
             {
-                string blockName = GetBlockName(block);
+                _builder.Append("<NULL>");
+                return;
+            }
 
 
-                if (block.Next != null)
-                {
-                    blockName += $" (next {GetBlockName(block.Next)})";
-                }
+            _builder.Append(GetTypeName(operand.Type)).Append(' ');
 
 
-                if (block.Branch != null)
-                {
-                    blockName += $" (branch {GetBlockName(block.Branch)})";
-                }
+            switch (operand.Kind)
+            {
+                case OperandKind.LocalVariable:
+                    if (!_localNames.TryGetValue(operand, out string localName))
+                    {
+                        localName = $"%{_localNames.Count}";
 
 
-                blockName += ":";
+                        _localNames.Add(operand, localName);
+                    }
 
 
-                AppendLine(blockName);
+                    _builder.Append(localName);
+                    break;
 
 
-                IncreaseIndentation();
+                case OperandKind.Register:
+                    Register reg = operand.GetRegister();
 
 
-                for (Node node = block.Operations.First; node != null; node = node.ListNext)
-                {
-                    string[] sources = new string[node.SourcesCount];
+                    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;
 
 
-                    string instName = string.Empty;
+                case OperandKind.Constant:
+                    string symbolName = Symbols.Get(operand.Value);
 
 
-                    if (node is PhiNode phi)
+                    if (symbolName != null && !_symbolNames.ContainsKey(operand.Value))
                     {
                     {
-                        for (int index = 0; index < sources.Length; index++)
-                        {
-                            string phiBlockName = GetBlockName(phi.GetBlock(index));
+                        _symbolNames.Add(operand.Value, symbolName);
+                    }
 
 
-                            string operName = GetOperandName(phi.GetSource(index), localNames);
+                    _builder.Append("0x").Append(operand.Value.ToString("X"));
+                    break;
 
 
-                            sources[index] = $"({phiBlockName}: {operName})";
-                        }
+                case OperandKind.Memory:
+                    var memOp = (MemoryOperand)operand;
 
 
-                        instName = "Phi";
-                    }
-                    else if (node is Operation operation)
+                    _builder.Append('[');
+
+                    DumpOperand(memOp.BaseAddress);
+
+                    if (memOp.Index != null)
                     {
                     {
-                        for (int index = 0; index < sources.Length; index++)
+                        _builder.Append(" + ");
+
+                        DumpOperand(memOp.Index);
+
+                        switch (memOp.Scale)
                         {
                         {
-                            sources[index] = GetOperandName(operation.GetSource(index), localNames);
+                            case Multiplier.x2: _builder.Append("*2"); break;
+                            case Multiplier.x4: _builder.Append("*4"); break;
+                            case Multiplier.x8: _builder.Append("*8"); break;
                         }
                         }
-
-                        instName = operation.Instruction.ToString();
                     }
                     }
 
 
-                    string allSources = string.Join(", ", sources);
-
-                    string line = instName + " " + allSources;
-
-                    if (node.Destination != null)
+                    if (memOp.Displacement != 0)
                     {
                     {
-                        line = GetOperandName(node.Destination, localNames) + " = " + line;
+                        _builder.Append(" + 0x").Append(memOp.Displacement.ToString("X"));
                     }
                     }
 
 
-                    AppendLine(line);
-                }
+                    _builder.Append(']');
+                    break;
 
 
-                DecreaseIndentation();
+                default:
+                    _builder.Append(operand.Type);
+                    break;
             }
             }
-
-            return sb.ToString();
-        }
-
-        private static string GetBlockName(BasicBlock block)
-        {
-            return $"block{block.Index}";
         }
         }
 
 
-        private static string GetOperandName(Operand operand, Dictionary<Operand, string> localNames)
+        private void DumpNode(Node node)
         {
         {
-            if (operand == null)
+            for (int index = 0; index < node.DestinationsCount; index++)
             {
             {
-                return "<NULL>";
-            }
+                DumpOperand(node.GetDestination(index));
 
 
-            string name = string.Empty;
+                if (index == node.DestinationsCount - 1)
+                {
+                    _builder.Append(" = ");
+                }
+                else
+                {
+                    _builder.Append(", ");
+                }
+            }
 
 
-            if (operand.Kind == OperandKind.LocalVariable)
+            switch (node)
             {
             {
-                if (!localNames.TryGetValue(operand, out string localName))
-                {
-                    localName = "%" + localNames.Count;
+                case PhiNode phi:
+                    _builder.Append("Phi ");
 
 
-                    localNames.Add(operand, localName);
-                }
+                    for (int index = 0; index < phi.SourcesCount; index++)
+                    {
+                        _builder.Append('(');
+
+                        DumpBlockName(phi.GetBlock(index));
+
+                        _builder.Append(": ");
+
+                        DumpOperand(phi.GetSource(index));
+
+                        _builder.Append(')');
+
+                        if (index < phi.SourcesCount - 1)
+                        {
+                            _builder.Append(", ");
+                        }
+                    }
+                    break;
+
+                case Operation operation:
+                    _builder.Append(operation.Instruction);
+
+                    if (operation.Instruction == Instruction.Extended)
+                    {
+                        var intrinOp = (IntrinsicOperation)operation;
+
+                        _builder.Append('.').Append(intrinOp.Intrinsic);
+                    }
+
+                    _builder.Append(' ');
+
+                    for (int index = 0; index < operation.SourcesCount; index++)
+                    {
+                        DumpOperand(operation.GetSource(index));
 
 
-                name = localName;
+                        if (index < operation.SourcesCount - 1)
+                        {
+                            _builder.Append(", ");
+                        }
+                    }
+                    break;
             }
             }
-            else if (operand.Kind == OperandKind.Register)
+
+            if (_symbolNames.Count == 1)
             {
             {
-                Register reg = operand.GetRegister();
+                _builder.Append(" ;; ").Append(_symbolNames.First().Value);
+            }
+            else if (_symbolNames.Count > 1)
+            {
+                _builder.Append(" ;;");
 
 
-                switch (reg.Type)
+                foreach ((ulong value, string name) in _symbolNames)
                 {
                 {
-                    case RegisterType.Flag:    name = "b" + reg.Index; break;
-                    case RegisterType.FpFlag:  name = "f" + reg.Index; break;
-                    case RegisterType.Integer: name = "r" + reg.Index; break;
-                    case RegisterType.Vector:  name = "v" + reg.Index; break;
+                    _builder.Append(" 0x").Append(value.ToString("X")).Append(" = ").Append(name);
                 }
                 }
             }
             }
-            else if (operand.Kind == OperandKind.Constant)
-            {
-                name = "0x" + operand.Value.ToString("X");
-            }
-            else
+
+            // 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)
             {
             {
-                name = operand.Kind.ToString().ToLower();
+                dumper.Indent();
+                dumper.DumpBlockHeader(block);
+
+                dumper._builder.AppendLine();
+
+                dumper.IncreaseIndentation();
+
+                for (Node node = block.Operations.First; node != null; node = node.ListNext)
+                {
+                    dumper.Indent();
+                    dumper.DumpNode(node);
+
+                    dumper._builder.AppendLine();
+                }
+
+                dumper.DecreaseIndentation();
             }
             }
 
 
-            return GetTypeName(operand.Type) + " " + name;
+            return dumper._builder.ToString();
         }
         }
 
 
         private static string GetTypeName(OperandType type)
         private static string GetTypeName(OperandType type)
         {
         {
-            switch (type)
+            return type switch
             {
             {
-                case OperandType.FP32: return "f32";
-                case OperandType.FP64: return "f64";
-                case OperandType.I32:  return "i32";
-                case OperandType.I64:  return "i64";
-                case OperandType.None: return "none";
-                case OperandType.V128: return "v128";
-            }
-
-            throw new ArgumentException($"Invalid operand type \"{type}\".");
+                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}\"."),
+            };
         }
         }
     }
     }
 }
 }

+ 84 - 0
ARMeilleure/Diagnostics/Symbols.cs

@@ -0,0 +1,84 @@
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.Diagnostics;
+
+namespace ARMeilleure.Diagnostics
+{
+    static class Symbols
+    {
+        private struct RangedSymbol
+        {
+            public readonly ulong Start;
+            public readonly ulong End;
+            public readonly ulong ElementSize;
+            public readonly string Name;
+
+            public RangedSymbol(ulong start, ulong end, ulong elemSize, string name)
+            {
+                Start = start;
+                End = end;
+                ElementSize = elemSize;
+                Name = name;
+            }
+        }
+
+        private static readonly ConcurrentDictionary<ulong, string> _symbols;
+        private static readonly List<RangedSymbol> _rangedSymbols;
+
+        static Symbols()
+        {
+            _symbols = new ConcurrentDictionary<ulong, string>();
+            _rangedSymbols = new List<RangedSymbol>();
+        }
+
+        public static string Get(ulong address)
+        {
+            string result;
+
+            if (_symbols.TryGetValue(address, out result))
+            {
+                return result;
+            }
+
+            lock (_rangedSymbols)
+            {
+                foreach (RangedSymbol symbol in _rangedSymbols)
+                {
+                    if (address >= symbol.Start && address <= symbol.End)
+                    {
+                        ulong diff = address - symbol.Start;
+                        ulong rem = diff % symbol.ElementSize;
+
+                        result = symbol.Name + "_" + diff / symbol.ElementSize;
+
+                        if (rem != 0)
+                        {
+                            result += "+" + rem;
+                        }
+
+                        _symbols.TryAdd(address, result);
+
+                        return result;
+                    }
+                }
+            }
+
+            return null;
+        }
+
+        [Conditional("M_DEBUG")]
+        public static void Add(ulong address, string name)
+        {
+            _symbols.TryAdd(address, name);
+        }
+
+        [Conditional("M_DEBUG")]
+        public static void Add(ulong address, ulong size, ulong elemSize, string name)
+        {
+            lock (_rangedSymbols)
+            {
+                _rangedSymbols.Add(new RangedSymbol(address, address + size, elemSize, name));
+            }
+        }
+    }
+}

+ 3 - 0
ARMeilleure/Translation/EmitterContext.cs

@@ -1,3 +1,4 @@
+using ARMeilleure.Diagnostics;
 using ARMeilleure.IntermediateRepresentation;
 using ARMeilleure.IntermediateRepresentation;
 using ARMeilleure.State;
 using ARMeilleure.State;
 using System;
 using System;
@@ -85,6 +86,8 @@ namespace ARMeilleure.Translation
 
 
             IntPtr ptr = Marshal.GetFunctionPointerForDelegate<Delegate>(func);
             IntPtr ptr = Marshal.GetFunctionPointerForDelegate<Delegate>(func);
 
 
+            Symbols.Add((ulong)ptr.ToInt64(), func.Method.Name);
+
             OperandType returnType = GetOperandType(func.Method.ReturnType);
             OperandType returnType = GetOperandType(func.Method.ReturnType);
 
 
             return Call(Const(ptr.ToInt64()), returnType, callArgs);
             return Call(Const(ptr.ToInt64()), returnType, callArgs);

+ 5 - 1
ARMeilleure/Translation/JumpTable.cs

@@ -1,4 +1,5 @@
-using ARMeilleure.Memory;
+using ARMeilleure.Diagnostics;
+using ARMeilleure.Memory;
 using System;
 using System;
 using System.Collections.Concurrent;
 using System.Collections.Concurrent;
 using System.Collections.Generic;
 using System.Collections.Generic;
@@ -60,6 +61,9 @@ namespace ARMeilleure.Translation
 
 
             _targets = new ConcurrentDictionary<ulong, TranslatedFunction>();
             _targets = new ConcurrentDictionary<ulong, TranslatedFunction>();
             _dependants = new ConcurrentDictionary<ulong, LinkedList<int>>();
             _dependants = new ConcurrentDictionary<ulong, LinkedList<int>>();
+
+            Symbols.Add((ulong)_jumpRegion.Pointer.ToInt64(), JumpTableByteSize, JumpTableStride, "JMP_TABLE");
+            Symbols.Add((ulong)_dynamicRegion.Pointer.ToInt64(), DynamicTableByteSize, DynamicTableStride, "DYN_TABLE");
         }
         }
 
 
         public void RegisterFunction(ulong address, TranslatedFunction func)
         public void RegisterFunction(ulong address, TranslatedFunction func)