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})"); _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) private string EmitCStringSizeInBytes(string cstring)
{ {
var result = TmpName(); var result = TmpName();
@@ -299,25 +290,31 @@ public class QBEGenerator
} }
// todo(nub31): EmitRValue should take a destination parameter so we can skip copying rvalues // 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) if (source.Type.IsScalar)
{ {
EmitStore(source.Type, EmitExpression(source), destination); EmitStore(source.Type, EmitExpression(source), destinationAddress);
return; return;
} }
if (source.Type.IsValueType) if (source.Type.IsValueType)
{ {
var value = EmitExpression(source); 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) if (source.Type is StructTypeNode structType)
{ {
var copyFunc = structType.Functions.FirstOrDefault(x => x.Hook == "oncopy"); var copyFunc = structType.Functions.FirstOrDefault(x => x.Hook == "oncopy");
if (copyFunc != null) 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) 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: case CStringTypeNode:
{ {
var value = EmitExpression(source); var value = EmitExpression(source);
@@ -343,7 +330,7 @@ public class QBEGenerator
var buffer = TmpName(); var buffer = TmpName();
_writer.Indented($"{buffer} =l alloc8 {size}"); _writer.Indented($"{buffer} =l alloc8 {size}");
EmitMemcpy(value, buffer, size); EmitMemcpy(value, buffer, size);
EmitStore(source.Type, buffer, destination); EmitStore(source.Type, buffer, destinationAddress);
return; return;
} }
case StringTypeNode: case StringTypeNode:
@@ -353,7 +340,7 @@ public class QBEGenerator
var buffer = TmpName(); var buffer = TmpName();
_writer.Indented($"{buffer} =l alloc8 {size}"); _writer.Indented($"{buffer} =l alloc8 {size}");
EmitMemcpy(value, buffer, size); EmitMemcpy(value, buffer, size);
EmitStore(source.Type, buffer, destination); EmitStore(source.Type, buffer, destinationAddress);
return; return;
} }
case VoidTypeNode: 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) private string EmitLValue(LValueExpressionNode lValue)
{ {
var address = EmitAddressOf(lValue); var address = EmitAddressOf(lValue);
@@ -963,25 +987,29 @@ public class QBEGenerator
private string EmitStructInitializer(StructInitializerNode structInitializer) private string EmitStructInitializer(StructInitializerNode structInitializer)
{ {
var destination = TmpName(); var destinationAddress = TmpName();
var size = SizeOf(structInitializer.StructType); var size = SizeOf(structInitializer.StructType);
_writer.Indented($"{destination} =l alloc8 {size}"); _writer.Indented($"{destinationAddress} =l alloc8 {size}");
_writer.Indented($"call {StructCtorName(structInitializer.StructType.Module, structInitializer.StructType.Name)}(l {destination})"); 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"); var createFunc = structInitializer.StructType.Functions.FirstOrDefault(x => x.Hook == "oncreate");
if (createFunc != null) 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) foreach (var (field, value) in structInitializer.Initializers)
{ {
var offset = TmpName(); 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); EmitCopyInto(value, offset);
} }
return destination;
} }
private string EmitUnaryExpression(UnaryExpressionNode unaryExpression) 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 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 class CStringTypeNode : TypeNode
{ {
public override bool IsValueType => false; public override bool IsValueType => false;
@@ -144,16 +156,4 @@ public class StringTypeNode : TypeNode
public override string ToString() => "string"; public override string ToString() => "string";
public override bool Equals(TypeNode? other) => other is StringTypeNode; public override bool Equals(TypeNode? other) => other is StringTypeNode;
public override int GetHashCode() => HashCode.Combine(typeof(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);
} }