aboutsummaryrefslogtreecommitdiff
path: root/src/ARMeilleure/Diagnostics
diff options
context:
space:
mode:
authorTSR Berry <20988865+TSRBerry@users.noreply.github.com>2023-04-08 01:22:00 +0200
committerMary <thog@protonmail.com>2023-04-27 23:51:14 +0200
commitcee712105850ac3385cd0091a923438167433f9f (patch)
tree4a5274b21d8b7f938c0d0ce18736d3f2993b11b1 /src/ARMeilleure/Diagnostics
parentcd124bda587ef09668a971fa1cac1c3f0cfc9f21 (diff)
Move solution and projects to src
Diffstat (limited to 'src/ARMeilleure/Diagnostics')
-rw-r--r--src/ARMeilleure/Diagnostics/IRDumper.cs311
-rw-r--r--src/ARMeilleure/Diagnostics/Logger.cs56
-rw-r--r--src/ARMeilleure/Diagnostics/PassName.cs19
-rw-r--r--src/ARMeilleure/Diagnostics/Symbols.cs84
-rw-r--r--src/ARMeilleure/Diagnostics/TranslatorEventSource.cs67
5 files changed, 537 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
diff --git a/src/ARMeilleure/Diagnostics/Logger.cs b/src/ARMeilleure/Diagnostics/Logger.cs
new file mode 100644
index 00000000..07a60667
--- /dev/null
+++ b/src/ARMeilleure/Diagnostics/Logger.cs
@@ -0,0 +1,56 @@
+using ARMeilleure.Translation;
+using System;
+using System.Diagnostics;
+
+namespace ARMeilleure.Diagnostics
+{
+ static class Logger
+ {
+ private static long _startTime;
+
+ private static long[] _accumulatedTime;
+
+ static Logger()
+ {
+ _accumulatedTime = new long[(int)PassName.Count];
+ }
+
+ [Conditional("M_DEBUG")]
+ public static void StartPass(PassName name)
+ {
+ WriteOutput(name + " pass started...");
+
+ _startTime = Stopwatch.GetTimestamp();
+ }
+
+ [Conditional("M_DEBUG")]
+ public static void EndPass(PassName name, ControlFlowGraph cfg)
+ {
+ EndPass(name);
+
+ WriteOutput("IR after " + name + " pass:");
+
+ WriteOutput(IRDumper.GetDump(cfg));
+ }
+
+ [Conditional("M_DEBUG")]
+ public static void EndPass(PassName name)
+ {
+ long elapsedTime = Stopwatch.GetTimestamp() - _startTime;
+
+ _accumulatedTime[(int)name] += elapsedTime;
+
+ WriteOutput($"{name} pass ended after {GetMilliseconds(_accumulatedTime[(int)name])} ms...");
+ }
+
+ private static long GetMilliseconds(long ticks)
+ {
+ return (long)(((double)ticks / Stopwatch.Frequency) * 1000);
+ }
+
+ private static void WriteOutput(string text)
+ {
+ Console.WriteLine(text);
+ }
+ }
+} \ No newline at end of file
diff --git a/src/ARMeilleure/Diagnostics/PassName.cs b/src/ARMeilleure/Diagnostics/PassName.cs
new file mode 100644
index 00000000..e34bf0d2
--- /dev/null
+++ b/src/ARMeilleure/Diagnostics/PassName.cs
@@ -0,0 +1,19 @@
+namespace ARMeilleure.Diagnostics
+{
+ enum PassName
+ {
+ Decoding,
+ Translation,
+ RegisterUsage,
+ TailMerge,
+ Dominance,
+ SsaConstruction,
+ RegisterToLocal,
+ Optimization,
+ PreAllocation,
+ RegisterAllocation,
+ CodeGeneration,
+
+ Count
+ }
+} \ No newline at end of file
diff --git a/src/ARMeilleure/Diagnostics/Symbols.cs b/src/ARMeilleure/Diagnostics/Symbols.cs
new file mode 100644
index 00000000..6bde62f5
--- /dev/null
+++ b/src/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 readonly 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));
+ }
+ }
+ }
+}
diff --git a/src/ARMeilleure/Diagnostics/TranslatorEventSource.cs b/src/ARMeilleure/Diagnostics/TranslatorEventSource.cs
new file mode 100644
index 00000000..a4f17844
--- /dev/null
+++ b/src/ARMeilleure/Diagnostics/TranslatorEventSource.cs
@@ -0,0 +1,67 @@
+using System.Diagnostics.Tracing;
+using System.Threading;
+
+namespace ARMeilleure.Diagnostics
+{
+ [EventSource(Name = "ARMeilleure")]
+ class TranslatorEventSource : EventSource
+ {
+ public static readonly TranslatorEventSource Log = new();
+
+ private int _rejitQueue;
+ private ulong _funcTabSize;
+ private ulong _funcTabLeafSize;
+ private PollingCounter _rejitQueueCounter;
+ private PollingCounter _funcTabSizeCounter;
+ private PollingCounter _funcTabLeafSizeCounter;
+
+ public TranslatorEventSource()
+ {
+ _rejitQueueCounter = new PollingCounter("rejit-queue-length", this, () => _rejitQueue)
+ {
+ DisplayName = "Rejit Queue Length"
+ };
+
+ _funcTabSizeCounter = new PollingCounter("addr-tab-alloc", this, () => _funcTabSize / 1024d / 1024d)
+ {
+ DisplayName = "AddressTable Total Bytes Allocated",
+ DisplayUnits = "MiB"
+ };
+
+ _funcTabLeafSizeCounter = new PollingCounter("addr-tab-leaf-alloc", this, () => _funcTabLeafSize / 1024d / 1024d)
+ {
+ DisplayName = "AddressTable Total Leaf Bytes Allocated",
+ DisplayUnits = "MiB"
+ };
+ }
+
+ public void RejitQueueAdd(int count)
+ {
+ Interlocked.Add(ref _rejitQueue, count);
+ }
+
+ public void AddressTableAllocated(int bytes, bool leaf)
+ {
+ _funcTabSize += (uint)bytes;
+
+ if (leaf)
+ {
+ _funcTabLeafSize += (uint)bytes;
+ }
+ }
+
+ protected override void Dispose(bool disposing)
+ {
+ _rejitQueueCounter.Dispose();
+ _rejitQueueCounter = null;
+
+ _funcTabLeafSizeCounter.Dispose();
+ _funcTabLeafSizeCounter = null;
+
+ _funcTabSizeCounter.Dispose();
+ _funcTabSizeCounter = null;
+
+ base.Dispose(disposing);
+ }
+ }
+}