From 7f63180b00e35e12a8e7207a83ad1dd3cf3c27dc Mon Sep 17 00:00:00 2001 From: nub31 Date: Thu, 3 Jul 2025 21:40:08 +0200 Subject: [PATCH] debugging --- src/compiler/CLI/Program.cs | 4 +- .../Generation/QBE/QBEDebugEmitter.cs | 85 +++++++++++++++++++ src/compiler/Generation/QBE/QBEGenerator.cs | 71 +++++++++++++--- 3 files changed, 148 insertions(+), 12 deletions(-) create mode 100644 src/compiler/Generation/QBE/QBEDebugEmitter.cs diff --git a/src/compiler/CLI/Program.cs b/src/compiler/CLI/Program.cs index 552eb12..456a89f 100644 --- a/src/compiler/CLI/Program.cs +++ b/src/compiler/CLI/Program.cs @@ -119,8 +119,8 @@ var objectFiles = new List(); foreach (var file in options.Files) { var outFileName = $"{HexString.CreateUnique(8)}_{Path.GetFileNameWithoutExtension(file)}"; - - var ssa = QBEGenerator.Emit(boundSyntaxTrees[file], boundDefinitionTable); + + var ssa = QBEGenerator.Emit(boundSyntaxTrees[file], boundDefinitionTable, file); File.WriteAllText(Path.Join(INT_DEBUG_DIR, $"{outFileName}.ssa"), ssa); var asm = await QBE.Invoke(ssa); diff --git a/src/compiler/Generation/QBE/QBEDebugEmitter.cs b/src/compiler/Generation/QBE/QBEDebugEmitter.cs new file mode 100644 index 0000000..e36387b --- /dev/null +++ b/src/compiler/Generation/QBE/QBEDebugEmitter.cs @@ -0,0 +1,85 @@ +using System.Text; +using Syntax; +using Syntax.Tokenization; +using Syntax.Typing.BoundNode; + +namespace Generation.QBE; + +public class QBEDebugEmitter +{ + private readonly StringBuilder _builder; + private int _currentLine = -1; + private readonly Dictionary _fileMap = new(); + private int _nextFileId = 0; + + public QBEDebugEmitter(StringBuilder builder) + { + _builder = builder; + } + + public int RegisterFile(string fileName) + { + if (_fileMap.TryGetValue(fileName, out var existingId)) + { + return existingId; + } + + var fileId = _nextFileId++; + _fileMap[fileName] = fileId; + + _builder.AppendLine($"# Debug file {fileId}: {fileName}"); + + return fileId; + } + + public void EmitDebugLocation(SourceSpan span) + { + if (span.IsEmpty) + return; + + var line = span.Start.Line; + + if (_currentLine != line) + { + _builder.AppendLine($" dbgloc {line}"); + _currentLine = line; + } + } + + public void EmitDebugLocation(Token token) + { + EmitDebugLocation(token.Span); + } + + public void EmitDebugLocation(BoundNode node) + { + var firstToken = node.Tokens.FirstOrDefault(); + if (firstToken != null) + { + EmitDebugLocation(firstToken); + } + } + + public void EmitDebugLocation(IEnumerable tokens) + { + var firstToken = tokens.FirstOrDefault(); + if (firstToken != null) + { + EmitDebugLocation(firstToken); + } + } + + public void ForceEmitDebugLocation(SourceSpan span) + { + if (!span.IsEmpty) + { + _builder.AppendLine($" dbgloc {span.Start.Line}"); + _currentLine = span.Start.Line; + } + } + + public void ResetLineTracker() + { + _currentLine = -1; + } +} \ No newline at end of file diff --git a/src/compiler/Generation/QBE/QBEGenerator.cs b/src/compiler/Generation/QBE/QBEGenerator.cs index 7fc4095..f900c46 100644 --- a/src/compiler/Generation/QBE/QBEGenerator.cs +++ b/src/compiler/Generation/QBE/QBEGenerator.cs @@ -15,6 +15,8 @@ public static class QBEGenerator private static BoundSyntaxTree _syntaxTree = null!; private static BoundDefinitionTable _definitionTable = null!; + private static QBEDebugEmitter _debugEmitter = null!; + private static StringBuilder _builder = new(); private static List _cStringLiterals = []; private static List _stringLiterals = []; @@ -30,12 +32,14 @@ public static class QBEGenerator private static int _stringLiteralIndex; private static bool _codeIsReachable = true; - public static string Emit(BoundSyntaxTree syntaxTree, BoundDefinitionTable definitionTable) + public static string Emit(BoundSyntaxTree syntaxTree, BoundDefinitionTable definitionTable, string file) { _syntaxTree = syntaxTree; _definitionTable = definitionTable; _builder = new StringBuilder(); + _debugEmitter = new QBEDebugEmitter(_builder); + _cStringLiterals = []; _stringLiterals = []; _breakLabels = []; @@ -50,6 +54,9 @@ public static class QBEGenerator _stringLiteralIndex = 0; _codeIsReachable = true; + _builder.AppendLine($"dbgfile \"{file}\""); + _builder.AppendLine(); + foreach (var structDef in _definitionTable.GetStructs()) { EmitStructDefinition(structDef); @@ -58,13 +65,13 @@ public static class QBEGenerator foreach (var funcDef in _syntaxTree.Definitions.OfType()) { - EmitFuncDefinition(FuncName(funcDef), funcDef.Parameters, funcDef.ReturnType, funcDef.Body, funcDef.Exported); + EmitFuncDefinition(funcDef, FuncName(funcDef), funcDef.Parameters, funcDef.ReturnType, funcDef.Body, funcDef.Exported); _builder.AppendLine(); } while (_anonymousFunctions.TryDequeue(out var anon)) { - EmitFuncDefinition(anon.Name, anon.Func.Parameters, anon.Func.ReturnType, anon.Func.Body, false); + EmitFuncDefinition(anon.Func, anon.Name, anon.Func.Parameters, anon.Func.ReturnType, anon.Func.Body, false); _builder.AppendLine(); } @@ -456,8 +463,10 @@ public static class QBEGenerator throw new UnreachableException($"Member '{member}' not found in struct"); } - private static void EmitFuncDefinition(string name, List parameters, NubType returnType, BoundBlockNode body, bool exported) + private static void EmitFuncDefinition(BoundNode debugNode, string name, List parameters, NubType returnType, BoundBlockNode body, bool exported) { + _debugEmitter.ResetLineTracker(); + _variables.Clear(); _variableScopes.Clear(); @@ -518,6 +527,8 @@ public static class QBEGenerator _builder.AppendLine($"({string.Join(", ", parameterStrings)}) {{"); _builder.AppendLine("@start"); + + _debugEmitter.EmitDebugLocation(debugNode); List parameterVars = []; @@ -598,11 +609,11 @@ public static class QBEGenerator case BoundAssignmentNode assignment: EmitAssignment(assignment); break; - case BoundBreakNode: - EmitBreak(); + case BoundBreakNode @break: + EmitBreak(@break); break; - case BoundContinueNode: - EmitContinue(); + case BoundContinueNode @continue: + EmitContinue(@continue); break; case BoundIfNode ifStatement: EmitIf(ifStatement); @@ -626,6 +637,8 @@ public static class QBEGenerator private static void EmitAssignment(BoundAssignmentNode assignment) { + _debugEmitter.EmitDebugLocation(assignment); + var destination = EmitExpression(assignment.Expression); Debug.Assert(destination.Kind == ValKind.Pointer); EmitCopyIntoOrInitialize(assignment.Value, destination.Name); @@ -633,6 +646,8 @@ public static class QBEGenerator private static void EmitBlock(BoundBlockNode block, List? variables = null) { + _debugEmitter.EmitDebugLocation(block); + _variableScopes.Push(_variables.Count); if (variables != null) { @@ -656,20 +671,26 @@ public static class QBEGenerator _codeIsReachable = true; } - private static void EmitBreak() + private static void EmitBreak(BoundBreakNode @break) { + _debugEmitter.EmitDebugLocation(@break); + _builder.AppendLine($" jmp {_breakLabels.Peek()}"); _codeIsReachable = false; } - private static void EmitContinue() + private static void EmitContinue(BoundContinueNode @continue) { + _debugEmitter.EmitDebugLocation(@continue); + _builder.AppendLine($" jmp {_continueLabels.Peek()}"); _codeIsReachable = false; } private static void EmitIf(BoundIfNode ifStatement) { + _debugEmitter.EmitDebugLocation(ifStatement); + var trueLabel = LabelName(); var falseLabel = LabelName(); var endLabel = LabelName(); @@ -694,6 +715,8 @@ public static class QBEGenerator private static void EmitReturn(BoundReturnNode @return) { + _debugEmitter.EmitDebugLocation(@return); + if (@return.Value.HasValue) { var result = EmitUnwrap(EmitExpression(@return.Value.Value)); @@ -707,6 +730,8 @@ public static class QBEGenerator private static void EmitVariableDeclaration(BoundVariableDeclarationNode variableDeclaration) { + _debugEmitter.EmitDebugLocation(variableDeclaration); + var variable = VarName(); _builder.AppendLine($" {variable} =l alloc8 {SizeOf(variableDeclaration.Type)}"); @@ -720,6 +745,8 @@ public static class QBEGenerator private static void EmitWhile(BoundWhileNode whileStatement) { + _debugEmitter.EmitDebugLocation(whileStatement); + var conditionLabel = LabelName(); var iterationLabel = LabelName(); var endLabel = LabelName(); @@ -761,6 +788,8 @@ public static class QBEGenerator private static Val EmitAnonymousFunc(BoundAnonymousFuncNode anonymousFunc) { + _debugEmitter.EmitDebugLocation(anonymousFunc); + var name = $"$anon_func{++_anonymousFuncIndex}"; _anonymousFunctions.Enqueue((anonymousFunc, name)); return new Val(name, anonymousFunc.Type, ValKind.Direct); @@ -768,6 +797,8 @@ public static class QBEGenerator private static Val EmitArrayIndexAccess(BoundArrayIndexAccessNode arrayIndexAccess) { + _debugEmitter.EmitDebugLocation(arrayIndexAccess); + var array = EmitUnwrap(EmitExpression(arrayIndexAccess.Array)); var index = EmitUnwrap(EmitExpression(arrayIndexAccess.Index)); @@ -806,6 +837,8 @@ public static class QBEGenerator private static Val EmitArrayInitializer(BoundArrayInitializerNode arrayInitializer) { + _debugEmitter.EmitDebugLocation(arrayInitializer); + var capacity = EmitUnwrap(EmitExpression(arrayInitializer.Capacity)); var elementSize = SizeOf(arrayInitializer.ElementType); @@ -827,6 +860,8 @@ public static class QBEGenerator private static Val EmitDereference(BoundDereferenceNode dereference) { + _debugEmitter.EmitDebugLocation(dereference); + var pointerType = (NubPointerType)dereference.Expression.Type; var pointer = EmitExpression(dereference.Expression); @@ -842,6 +877,8 @@ public static class QBEGenerator private static Val EmitAddressOf(BoundAddressOfNode addressOf) { + _debugEmitter.EmitDebugLocation(addressOf); + var value = EmitExpression(addressOf.Expression); Debug.Assert(value.Kind == ValKind.Pointer); return new Val(value.Name, addressOf.Type, ValKind.Direct); @@ -849,6 +886,8 @@ public static class QBEGenerator private static Val EmitBinaryExpression(BoundBinaryExpressionNode binaryExpression) { + _debugEmitter.EmitDebugLocation(binaryExpression); + var left = EmitUnwrap(EmitExpression(binaryExpression.Left)); var right = EmitUnwrap(EmitExpression(binaryExpression.Right)); @@ -966,6 +1005,8 @@ public static class QBEGenerator private static Val EmitIdentifier(BoundIdentifierNode identifier) { + _debugEmitter.EmitDebugLocation(identifier); + if (_definitionTable.LookupFunc(identifier.Namespace.Or(_syntaxTree.Namespace), identifier.Name).TryGetValue(out var func)) { return new Val(FuncName(func), identifier.Type, ValKind.Direct); @@ -981,6 +1022,8 @@ public static class QBEGenerator private static Val EmitLiteral(BoundLiteralNode literal) { + _debugEmitter.EmitDebugLocation(literal); + switch (literal.Kind) { case LiteralKind.Integer: @@ -1063,6 +1106,8 @@ public static class QBEGenerator private static Val EmitStructInitializer(BoundStructInitializerNode structInitializer, string? destination = null) { + _debugEmitter.EmitDebugLocation(structInitializer); + var structDefinition = _definitionTable.LookupStruct(structInitializer.StructType.Namespace, structInitializer.StructType.Name).GetValue(); if (destination == null) @@ -1091,6 +1136,8 @@ public static class QBEGenerator private static Val EmitUnaryExpression(BoundUnaryExpressionNode unaryExpression) { + _debugEmitter.EmitDebugLocation(unaryExpression); + var operand = EmitUnwrap(EmitExpression(unaryExpression.Operand)); var outputName = VarName(); @@ -1138,6 +1185,8 @@ public static class QBEGenerator private static Val EmitMemberAccess(BoundMemberAccessNode memberAccess) { + _debugEmitter.EmitDebugLocation(memberAccess); + var item = EmitUnwrap(EmitExpression(memberAccess.Expression)); var output = VarName(); @@ -1188,6 +1237,8 @@ public static class QBEGenerator private static Val EmitFuncCall(BoundFuncCallNode funcCall) { + _debugEmitter.EmitDebugLocation(funcCall); + var funcType = (NubFuncType)funcCall.Expression.Type; var parameterStrings = new List();