...
This commit is contained in:
@@ -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)
|
||||||
|
|||||||
@@ -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;
|
||||||
@@ -145,15 +157,3 @@ public class StringTypeNode : TypeNode
|
|||||||
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);
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user