This commit is contained in:
nub31
2025-09-20 01:48:30 +02:00
parent ca838e32b8
commit f5a292312f
2 changed files with 72 additions and 44 deletions

View File

@@ -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)

View File

@@ -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;
@@ -145,15 +157,3 @@ public class StringTypeNode : TypeNode
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);
}