From 0afd4545f5df5261001c19e8466ac5d468f1a877 Mon Sep 17 00:00:00 2001 From: nub31 Date: Sat, 20 Sep 2025 01:48:30 +0200 Subject: [PATCH] ... --- .../NubLang/Generation/QBE/QBEGenerator.cs | 92 ++++++++++++------- .../NubLang/TypeChecking/Node/TypeNode.cs | 24 ++--- 2 files changed, 72 insertions(+), 44 deletions(-) diff --git a/compiler/NubLang/Generation/QBE/QBEGenerator.cs b/compiler/NubLang/Generation/QBE/QBEGenerator.cs index be5e15b..0d97645 100644 --- a/compiler/NubLang/Generation/QBE/QBEGenerator.cs +++ b/compiler/NubLang/Generation/QBE/QBEGenerator.cs @@ -273,15 +273,6 @@ public class QBEGenerator _writer.Indented($"call $.memcpy(l {source}, l {destination}, l {length})"); } - private string EmitArraySizeInBytes(ArrayTypeNode type, string array) - { - var size = TmpName(); - _writer.Indented($"{size} =l call $.array_size(l {array})"); - _writer.Indented($"{size} =l mul {size}, {SizeOf(type.ElementType)}"); - _writer.Indented($"{size} =l add {size}, 8"); - return size; - } - private string EmitCStringSizeInBytes(string cstring) { var result = TmpName(); @@ -299,25 +290,31 @@ public class QBEGenerator } // todo(nub31): EmitRValue should take a destination parameter so we can skip copying rvalues - private void EmitCopyInto(ExpressionNode source, string destination) + private void EmitCopyInto(ExpressionNode source, string destinationAddress, bool tryMove = true) { + if (tryMove && source is RValueExpressionNode rValue) + { + EmitRValueInto(rValue, destinationAddress); + return; + } + if (source.Type.IsScalar) { - EmitStore(source.Type, EmitExpression(source), destination); + EmitStore(source.Type, EmitExpression(source), destinationAddress); return; } if (source.Type.IsValueType) { var value = EmitExpression(source); - _writer.Indented($"blit {value}, {destination}, {SizeOf(source.Type)}"); + _writer.Indented($"blit {value}, {destinationAddress}, {SizeOf(source.Type)}"); if (source.Type is StructTypeNode structType) { var copyFunc = structType.Functions.FirstOrDefault(x => x.Hook == "oncopy"); if (copyFunc != null) { - _writer.Indented($"call {StructFuncName(structType.Module, structType.Name, copyFunc.Name)}(l {destination})"); + _writer.Indented($"call {StructFuncName(structType.Module, structType.Name, copyFunc.Name)}(l {destinationAddress})"); } } @@ -326,16 +323,6 @@ public class QBEGenerator switch (source.Type) { - case ArrayTypeNode arrayType: - { - var value = EmitExpression(source); - var size = EmitArraySizeInBytes(arrayType, value); - var buffer = TmpName(); - _writer.Indented($"{buffer} =l alloc8 {size}"); - EmitMemcpy(value, buffer, size); - EmitStore(arrayType, buffer, destination); - return; - } case CStringTypeNode: { var value = EmitExpression(source); @@ -343,7 +330,7 @@ public class QBEGenerator var buffer = TmpName(); _writer.Indented($"{buffer} =l alloc8 {size}"); EmitMemcpy(value, buffer, size); - EmitStore(source.Type, buffer, destination); + EmitStore(source.Type, buffer, destinationAddress); return; } case StringTypeNode: @@ -353,7 +340,7 @@ public class QBEGenerator var buffer = TmpName(); _writer.Indented($"{buffer} =l alloc8 {size}"); EmitMemcpy(value, buffer, size); - EmitStore(source.Type, buffer, destination); + EmitStore(source.Type, buffer, destinationAddress); return; } case VoidTypeNode: @@ -707,6 +694,43 @@ public class QBEGenerator }; } + private void EmitRValueInto(RValueExpressionNode rValue, string destinationAddress) + { + if (rValue.Type.IsScalar) + { + EmitStore(rValue.Type, EmitRValue(rValue), destinationAddress); + return; + } + + switch (rValue) + { + case StructInitializerNode expr: + { + EmitStructInitializer(expr, destinationAddress); + return; + } + case StringLiteralNode expr: + { + // String literals are read only, so safe to use without copy + EmitStore(expr.Type, EmitStringLiteral(expr), destinationAddress); + return; + } + case CStringLiteralNode expr: + { + // String literals are read only, so safe to use without copy + EmitStore(expr.Type, EmitCStringLiteral(expr), destinationAddress); + return; + } + default: + { + // If no special case is provided, fall back to copying + Console.WriteLine($"No fast initialization for {rValue.GetType().Name}. Using copy fallback"); + EmitCopyInto(rValue, destinationAddress, false); + break; + } + } + } + private string EmitLValue(LValueExpressionNode lValue) { var address = EmitAddressOf(lValue); @@ -963,25 +987,29 @@ public class QBEGenerator private string EmitStructInitializer(StructInitializerNode structInitializer) { - var destination = TmpName(); + var destinationAddress = TmpName(); var size = SizeOf(structInitializer.StructType); - _writer.Indented($"{destination} =l alloc8 {size}"); - _writer.Indented($"call {StructCtorName(structInitializer.StructType.Module, structInitializer.StructType.Name)}(l {destination})"); + _writer.Indented($"{destinationAddress} =l alloc8 {size}"); + EmitStructInitializer(structInitializer, destinationAddress); + return destinationAddress; + } + + private void EmitStructInitializer(StructInitializerNode structInitializer, string destinationAddress) + { + _writer.Indented($"call {StructCtorName(structInitializer.StructType.Module, structInitializer.StructType.Name)}(l {destinationAddress})"); var createFunc = structInitializer.StructType.Functions.FirstOrDefault(x => x.Hook == "oncreate"); if (createFunc != null) { - _writer.Indented($"call {StructFuncName(structInitializer.StructType.Module, structInitializer.StructType.Name, createFunc.Name)}(l {destination})"); + _writer.Indented($"call {StructFuncName(structInitializer.StructType.Module, structInitializer.StructType.Name, createFunc.Name)}(l {destinationAddress})"); } foreach (var (field, value) in structInitializer.Initializers) { var offset = TmpName(); - _writer.Indented($"{offset} =l add {destination}, {OffsetOf(structInitializer.StructType, field)}"); + _writer.Indented($"{offset} =l add {destinationAddress}, {OffsetOf(structInitializer.StructType, field)}"); EmitCopyInto(value, offset); } - - return destination; } private string EmitUnaryExpression(UnaryExpressionNode unaryExpression) diff --git a/compiler/NubLang/TypeChecking/Node/TypeNode.cs b/compiler/NubLang/TypeChecking/Node/TypeNode.cs index 032ce7b..af43155 100644 --- a/compiler/NubLang/TypeChecking/Node/TypeNode.cs +++ b/compiler/NubLang/TypeChecking/Node/TypeNode.cs @@ -126,6 +126,18 @@ public class StructTypeFunc(string name, string? hook, FuncTypeNode type) public FuncTypeNode Type { get; } = type; } +public class ArrayTypeNode(TypeNode elementType) : TypeNode +{ + public override bool IsValueType => false; + public override bool IsScalar => true; + + public TypeNode ElementType { get; } = elementType; + + public override string ToString() => "[]" + ElementType; + public override bool Equals(TypeNode? other) => other is ArrayTypeNode array && ElementType.Equals(array.ElementType); + public override int GetHashCode() => HashCode.Combine(typeof(ArrayTypeNode), ElementType); +} + public class CStringTypeNode : TypeNode { public override bool IsValueType => false; @@ -144,16 +156,4 @@ public class StringTypeNode : TypeNode public override string ToString() => "string"; public override bool Equals(TypeNode? other) => other is StringTypeNode; public override int GetHashCode() => HashCode.Combine(typeof(StringTypeNode)); -} - -public class ArrayTypeNode(TypeNode elementType) : TypeNode -{ - public override bool IsValueType => false; - public override bool IsScalar => false; - - public TypeNode ElementType { get; } = elementType; - - public override string ToString() => "[]" + ElementType; - public override bool Equals(TypeNode? other) => other is ArrayTypeNode array && ElementType.Equals(array.ElementType); - public override int GetHashCode() => HashCode.Combine(typeof(ArrayTypeNode), ElementType); } \ No newline at end of file