This commit is contained in:
nub31
2025-09-09 17:44:57 +02:00
parent 5a54d26fd0
commit e02399e102
9 changed files with 143 additions and 126 deletions

View File

@@ -1,5 +1,4 @@
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Text;
using NubLang.Tokenization;
@@ -11,6 +10,7 @@ public class QBEGenerator
{
private readonly TypedSyntaxTree _syntaxTree;
private readonly TypedDefinitionTable _definitionTable;
private readonly string _sourceFileName;
private readonly QBEWriter _writer;
private readonly List<CStringLiteral> _cStringLiterals = [];
@@ -23,10 +23,11 @@ public class QBEGenerator
private int _stringLiteralIndex;
private bool _codeIsReachable = true;
public QBEGenerator(TypedSyntaxTree syntaxTree, TypedDefinitionTable definitionTable)
public QBEGenerator(TypedSyntaxTree syntaxTree, TypedDefinitionTable definitionTable, string sourceFileName)
{
_syntaxTree = syntaxTree;
_definitionTable = definitionTable;
_sourceFileName = sourceFileName;
_writer = new QBEWriter();
}
@@ -42,6 +43,8 @@ public class QBEGenerator
_stringLiteralIndex = 0;
_codeIsReachable = true;
_writer.WriteLine($"dbgfile \"{_sourceFileName}\"");
foreach (var structDef in _definitionTable.GetStructs())
{
EmitStructTypeDefinition(structDef);
@@ -260,39 +263,22 @@ public class QBEGenerator
}
}
private bool EmitTryCreateWithoutCopy(ExpressionNode source, [NotNullWhen(true)] out string? destination)
private string EmitCreateCopy(ExpressionNode source)
{
switch (source)
// Allowlist for types which are safe to not copy
if (source is ArrayInitializerNode or StructInitializerNode or ConvertToInterfaceNode or LiteralNode)
{
case ArrayInitializerNode:
case StructInitializerNode:
case LiteralNode { Kind: LiteralKind.String }:
{
destination = EmitExpression(source);
return true;
}
return EmitExpression(source);
}
destination = null;
return false;
}
private string EmitCreateCopyOrInitialize(ExpressionNode source)
{
// If the source is a value which is not used yet such as an array/struct/interface initializer or literal, we can skip copying
if (EmitTryCreateWithoutCopy(source, out var uncopiedValue))
{
return uncopiedValue;
}
var value = EmitExpression(source);
// Simple types are passed in registers and therefore always copied
if (source.Type.IsSimpleType(out _, out var complexType))
{
// Simple types are passed in registers and are therefore always copied
return value;
return EmitExpression(source);
}
// For the rest, we figure out the size of the type and shallow copy them
var value = EmitExpression(source);
var size = complexType switch
{
ArrayTypeNode arrayType => EmitArraySizeInBytes(arrayType, value),
@@ -474,6 +460,12 @@ public class QBEGenerator
private void EmitStatement(StatementNode statement)
{
var tokens = statement.Tokens.ToArray();
if (tokens.Length != 0)
{
_writer.WriteLine($"dbgloc {tokens[0].FileSpan.Span.Start.Line}");
}
switch (statement)
{
case AssignmentNode assignment:
@@ -589,6 +581,12 @@ public class QBEGenerator
private string EmitExpression(ExpressionNode expression)
{
var tokens = expression.Tokens.ToArray();
if (tokens.Length != 0)
{
_writer.WriteLine($"dbgloc {tokens[0].FileSpan.Span.Start.Line}");
}
return expression switch
{
ArrayInitializerNode arrayInitializer => EmitArrayInitializer(arrayInitializer),
@@ -616,7 +614,13 @@ public class QBEGenerator
private string EmitArrayIndexAccess(ArrayIndexAccessNode arrayIndexAccess)
{
return EmitLoad(arrayIndexAccess.Type, EmitAddressOfArrayIndexAccess(arrayIndexAccess));
var address = EmitAddressOfArrayIndexAccess(arrayIndexAccess);
if (arrayIndexAccess.Type is StructTypeNode)
{
return address;
}
return EmitLoad(arrayIndexAccess.Type, address);
}
private void EmitArrayBoundsCheck(string array, string index)
@@ -666,7 +670,13 @@ public class QBEGenerator
private string EmitDereference(DereferenceNode dereference)
{
return EmitLoad(dereference.Type, EmitExpression(dereference.Expression));
var address = EmitExpression(dereference.Expression);
if (dereference.Type is StructTypeNode)
{
return address;
}
return EmitLoad(dereference.Type, address);
}
private string EmitAddressOf(AddressOfNode addressOf)
@@ -901,10 +911,12 @@ public class QBEGenerator
private string EmitVariableIdent(VariableIdentNode variableIdent)
{
var address = EmitAddressOfVariableIdent(variableIdent);
if (variableIdent.Type is StructTypeNode)
{
return address;
}
return variableIdent.Type.IsSimpleType(out _, out _)
? EmitLoad(variableIdent.Type, address)
: address;
return EmitLoad(variableIdent.Type, address);
}
private string EmitFuncParameterIdent(FuncParameterIdentNode funcParameterIdent)
@@ -1075,13 +1087,11 @@ public class QBEGenerator
private string EmitStructFieldAccess(StructFieldAccessNode structFieldAccess)
{
var address = EmitAddressOfStructFieldAccess(structFieldAccess);
// Inline structs should not be loaded
if (structFieldAccess.Type is StructTypeNode)
{
return address;
}
return EmitLoad(structFieldAccess.Type, address);
}
@@ -1096,7 +1106,7 @@ public class QBEGenerator
foreach (var parameter in structFuncCall.Parameters)
{
var copy = EmitCreateCopyOrInitialize(parameter);
var copy = EmitCreateCopy(parameter);
parameterStrings.Add($"{FuncQBETypeName(parameter.Type)} {copy}");
}
@@ -1138,7 +1148,7 @@ public class QBEGenerator
foreach (var parameter in interfaceFuncCall.Parameters)
{
var copy = EmitCreateCopyOrInitialize(parameter);
var copy = EmitCreateCopy(parameter);
parameterStrings.Add($"{FuncQBETypeName(parameter.Type)} {copy}");
}
@@ -1248,7 +1258,7 @@ public class QBEGenerator
foreach (var parameter in funcCall.Parameters)
{
var copy = EmitCreateCopyOrInitialize(parameter);
var copy = EmitCreateCopy(parameter);
parameterStrings.Add($"{FuncQBETypeName(parameter.Type)} {copy}");
}