This commit is contained in:
nub31
2025-09-10 16:32:59 +02:00
parent e02399e102
commit 32190b3bea
8 changed files with 168 additions and 182 deletions

View File

@@ -166,9 +166,63 @@ public class QBEGenerator
return into;
}
private void EmitMemset(string destination, int value, string length)
{
var count = TmpName();
_writer.Indented($"{count} =l copy 0");
var loopLabel = LabelName();
_writer.WriteLine(loopLabel);
var continueLabel = LabelName();
var doneLabel = LabelName();
var condition = TmpName();
_writer.Indented($"{condition} =w cultl {count}, {length}");
_writer.Indented($"jnz {condition}, {continueLabel}, {doneLabel}");
_writer.WriteLine(continueLabel);
var destinationAddress = TmpName();
_writer.Indented($"{destinationAddress} =l add {destination}, {count}");
_writer.Indented($"storeb {value}, {destinationAddress}");
_writer.Indented($"{count} =l add {count}, 1");
_writer.Indented($"jmp {loopLabel}");
_writer.WriteLine(doneLabel);
}
private void EmitMemcpy(string source, string destination, string length)
{
_writer.Indented($"call $nub_memcpy(l {source}, l {destination}, l {length})");
var count = TmpName();
_writer.Indented($"{count} =l copy 0");
var loopLabel = LabelName();
_writer.WriteLine(loopLabel);
var continueLabel = LabelName();
var doneLabel = LabelName();
var condition = TmpName();
_writer.Indented($"{condition} =w cultl {count}, {length}");
_writer.Indented($"jnz {condition}, {continueLabel}, {doneLabel}");
_writer.WriteLine(continueLabel);
var sourceAddress = TmpName();
_writer.Indented($"{sourceAddress} =l add {source}, {count}");
var destinationAddress = TmpName();
_writer.Indented($"{destinationAddress} =l add {destination}, {count}");
var value = TmpName();
_writer.Indented($"{value} =w loadub {sourceAddress}");
_writer.Indented($"storeb {value}, {destinationAddress}");
_writer.Indented($"{count} =l add {count}, 1");
_writer.Indented($"jmp {loopLabel}");
_writer.WriteLine(doneLabel);
}
private string EmitArraySizeInBytes(ArrayTypeNode type, string array)
@@ -182,10 +236,27 @@ public class QBEGenerator
private string EmitCStringSizeInBytes(string cstring)
{
var size = TmpName();
_writer.Indented($"{size} =l call $nub_cstring_length(l {cstring})");
_writer.Indented($"{size} =l add {size}, 1");
return size;
var count = TmpName();
_writer.Indented($"{count} =l copy 0");
var loopLabel = LabelName();
_writer.WriteLine(loopLabel);
var address = TmpName();
_writer.Indented($"{address} =l add {cstring}, {count}");
var value = TmpName();
_writer.Indented($"{value} =w loadub {address}");
var notZeroLabel = LabelName();
var zeroLabel = LabelName();
_writer.Indented($"jnz {value}, {notZeroLabel}, {zeroLabel}");
_writer.WriteLine(notZeroLabel);
_writer.Indented($"{count} =l add {count}, 1");
_writer.Indented($"jmp {loopLabel}");
_writer.WriteLine(zeroLabel);
return count;
}
private string EmitStringSizeInBytes(string nubstring)
@@ -196,74 +267,42 @@ public class QBEGenerator
return size;
}
private bool EmitTryMoveInto(ExpressionNode source, string destinationLValue)
private void EmitCopyInto(ExpressionNode source, string destination)
{
switch (source)
{
case ArrayInitializerNode arrayInitializer:
{
EmitStore(source.Type, EmitArrayInitializer(arrayInitializer), destinationLValue);
return true;
}
case StructInitializerNode structInitializer:
{
EmitStructInitializer(structInitializer, destinationLValue);
return true;
}
case ConvertToInterfaceNode convertToInterface:
{
EmitConvertToInterface(convertToInterface, destinationLValue);
return true;
}
case LiteralNode { Kind: LiteralKind.String } literal:
{
EmitStore(source.Type, EmitLiteral(literal), destinationLValue);
return true;
}
}
return false;
}
private void EmitCopyIntoOrInitialize(ExpressionNode source, string destinationLValue)
{
// If the source is a value which is not used yet such as an array/struct initializer or literal, we can skip copying
if (EmitTryMoveInto(source, destinationLValue))
// Simple types are passed in registers and can therefore just be stored
if (source.Type.IsSimpleType(out var simpleType, out var complexType))
{
var value = EmitExpression(source);
EmitStore(simpleType, value, destination);
return;
}
var value = EmitExpression(source);
if (source.Type.IsSimpleType(out var simpleType, out var complexType))
// Structs and interfaces has known sizes at compile time
if (complexType is StructTypeNode or InterfaceTypeNode)
{
EmitStore(simpleType, value, destinationLValue);
var value = EmitExpression(source);
_writer.Indented($"blit {value}, {destination}, {SizeOf(complexType)}");
}
// The rest of the complex types has unknown sizes
else
{
if (complexType is StructTypeNode or InterfaceTypeNode)
var value = EmitExpression(source);
var size = complexType switch
{
EmitMemcpy(value, destinationLValue, SizeOf(complexType).ToString());
}
else
{
var size = complexType switch
{
ArrayTypeNode arrayType => EmitArraySizeInBytes(arrayType, value),
CStringTypeNode => EmitCStringSizeInBytes(value),
StringTypeNode => EmitStringSizeInBytes(value),
_ => throw new ArgumentOutOfRangeException(nameof(source.Type))
};
ArrayTypeNode arrayType => EmitArraySizeInBytes(arrayType, value),
CStringTypeNode => EmitCStringSizeInBytes(value),
StringTypeNode => EmitStringSizeInBytes(value),
_ => throw new ArgumentOutOfRangeException(nameof(source.Type))
};
var buffer = TmpName();
_writer.Indented($"{buffer} =l alloc8 {size}");
EmitMemcpy(value, buffer, size);
EmitStore(complexType, buffer, destinationLValue);
}
var buffer = TmpName();
_writer.Indented($"{buffer} =l alloc8 {size}");
EmitMemcpy(value, buffer, size);
EmitStore(complexType, buffer, destination);
}
}
private string EmitCreateCopy(ExpressionNode source)
private string EmitCopy(ExpressionNode source)
{
// Allowlist for types which are safe to not copy
if (source is ArrayInitializerNode or StructInitializerNode or ConvertToInterfaceNode or LiteralNode)
@@ -279,19 +318,30 @@ public class QBEGenerator
// 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),
CStringTypeNode => EmitCStringSizeInBytes(value),
StringTypeNode => EmitStringSizeInBytes(value),
InterfaceTypeNode interfaceType => SizeOf(interfaceType).ToString(),
StructTypeNode structType => SizeOf(structType).ToString(),
_ => throw new ArgumentOutOfRangeException(nameof(source.Type))
};
var destination = TmpName();
_writer.Indented($"{destination} =l alloc8 {size}");
EmitMemcpy(value, destination, size);
// Structs and interfaces has known sizes at compile time
if (complexType is StructTypeNode or InterfaceTypeNode)
{
var size = SizeOf(complexType);
_writer.Indented($"{destination} =l alloc8 {size}");
_writer.Indented($"blit {value}, {destination}, {size}");
}
// The rest of the complex types has unknown sizes
else
{
var size = complexType switch
{
ArrayTypeNode arrayType => EmitArraySizeInBytes(arrayType, value),
CStringTypeNode => EmitCStringSizeInBytes(value),
StringTypeNode => EmitStringSizeInBytes(value),
_ => throw new ArgumentOutOfRangeException(nameof(source.Type))
};
_writer.Indented($"{destination} =l alloc8 {size}");
EmitMemcpy(value, destination, size);
}
return destination;
}
@@ -460,11 +510,11 @@ 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}");
}
// var tokens = statement.Tokens.ToArray();
// if (tokens.Length != 0)
// {
// _writer.WriteLine($"dbgloc {tokens[0].FileSpan.Span.Start.Line}");
// }
switch (statement)
{
@@ -499,7 +549,7 @@ public class QBEGenerator
private void EmitAssignment(AssignmentNode assignment)
{
EmitCopyIntoOrInitialize(assignment.Value, EmitAddressOfLValue(assignment.Target));
EmitCopyInto(assignment.Value, EmitAddressOfLValue(assignment.Target));
}
private void EmitBreak()
@@ -554,7 +604,7 @@ public class QBEGenerator
if (variableDeclaration.Assignment.HasValue)
{
EmitCopyIntoOrInitialize(variableDeclaration.Assignment.Value, name);
EmitCopyInto(variableDeclaration.Assignment.Value, name);
}
}
@@ -581,11 +631,11 @@ 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}");
}
// var tokens = expression.Tokens.ToArray();
// if (tokens.Length != 0)
// {
// _writer.WriteLine($"dbgloc {tokens[0].FileSpan.Span.Start.Line}");
// }
return expression switch
{
@@ -623,30 +673,6 @@ public class QBEGenerator
return EmitLoad(arrayIndexAccess.Type, address);
}
private void EmitArrayBoundsCheck(string array, string index)
{
var count = TmpName();
_writer.Indented($"{count} =l loadl {array}");
var isNegative = TmpName();
_writer.Indented($"{isNegative} =w csltl {index}, 0");
var isOob = TmpName();
_writer.Indented($"{isOob} =w csgel {index}, {count}");
var anyOob = TmpName();
_writer.Indented($"{anyOob} =w or {isNegative}, {isOob}");
var oobLabel = LabelName();
var notOobLabel = LabelName();
_writer.Indented($"jnz {anyOob}, {oobLabel}, {notOobLabel}");
_writer.Indented(oobLabel);
_writer.Indented($"call $nub_panic_array_oob()");
_writer.Indented(notOobLabel);
}
private string EmitArrayInitializer(ArrayInitializerNode arrayInitializer)
{
var capacity = EmitExpression(arrayInitializer.Capacity);
@@ -663,7 +689,7 @@ public class QBEGenerator
var dataPointer = TmpName();
_writer.Indented($"{dataPointer} =l add {arrayPointer}, 8");
_writer.Indented($"call $nub_memset(l {dataPointer}, w 0, l {capacityInBytes})");
EmitMemset(dataPointer, 0, capacityInBytes);
return arrayPointer;
}
@@ -700,8 +726,6 @@ public class QBEGenerator
var array = EmitExpression(arrayIndexAccess.Target);
var index = EmitExpression(arrayIndexAccess.Index);
EmitArrayBoundsCheck(array, index);
var elementType = ((ArrayTypeNode)arrayIndexAccess.Target.Type).ElementType;
var offset = TmpName();
@@ -1006,16 +1030,13 @@ public class QBEGenerator
throw new NotSupportedException($"Cannot create literal of kind '{literal.Kind}' for type {literal.Type}");
}
private string EmitStructInitializer(StructInitializerNode structInitializer, string? destination = null)
private string EmitStructInitializer(StructInitializerNode structInitializer)
{
var structDef = _definitionTable.LookupStruct(structInitializer.StructType.Name);
if (destination == null)
{
destination = TmpName();
var size = SizeOf(structInitializer.StructType);
_writer.Indented($"{destination} =l alloc8 {size}");
}
var destination = TmpName();
var size = SizeOf(structInitializer.StructType);
_writer.Indented($"{destination} =l alloc8 {size}");
foreach (var field in structDef.Fields)
{
@@ -1031,7 +1052,7 @@ public class QBEGenerator
var offset = TmpName();
_writer.Indented($"{offset} =l add {destination}, {OffsetOf(structDef, field.Name)}");
EmitCopyIntoOrInitialize(valueExpression, offset);
EmitCopyInto(valueExpression, offset);
}
return destination;
@@ -1106,7 +1127,7 @@ public class QBEGenerator
foreach (var parameter in structFuncCall.Parameters)
{
var copy = EmitCreateCopy(parameter);
var copy = EmitCopy(parameter);
parameterStrings.Add($"{FuncQBETypeName(parameter.Type)} {copy}");
}
@@ -1148,7 +1169,7 @@ public class QBEGenerator
foreach (var parameter in interfaceFuncCall.Parameters)
{
var copy = EmitCreateCopy(parameter);
var copy = EmitCopy(parameter);
parameterStrings.Add($"{FuncQBETypeName(parameter.Type)} {copy}");
}
@@ -1165,7 +1186,7 @@ public class QBEGenerator
}
}
private string EmitConvertToInterface(ConvertToInterfaceNode convertToInterface, string? destination = null)
private string EmitConvertToInterface(ConvertToInterfaceNode convertToInterface)
{
var implementation = EmitExpression(convertToInterface.Implementation);
@@ -1180,11 +1201,8 @@ public class QBEGenerator
vtableOffset += interfaceImplementation.Functions.Count * 8;
}
if (destination == null)
{
destination = TmpName();
_writer.Indented($"{destination} =l alloc8 {SizeOf(convertToInterface.InterfaceType)}");
}
var destination = TmpName();
_writer.Indented($"{destination} =l alloc8 {SizeOf(convertToInterface.InterfaceType)}");
var interfaceVtablePointer = TmpName();
_writer.Indented($"{interfaceVtablePointer} =l add {StructVtableName(convertToInterface.StructType.Name)}, {vtableOffset}");
@@ -1258,7 +1276,7 @@ public class QBEGenerator
foreach (var parameter in funcCall.Parameters)
{
var copy = EmitCreateCopy(parameter);
var copy = EmitCopy(parameter);
parameterStrings.Add($"{FuncQBETypeName(parameter.Type)} {copy}");
}