...
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
Reference in New Issue
Block a user