This commit is contained in:
nub31
2025-07-06 22:46:40 +02:00
parent 5658e0e25d
commit 896d1fe1ea
2 changed files with 83 additions and 86 deletions

View File

@@ -141,79 +141,6 @@ public static class QBEGenerator
return $":{@namespace}_{name}";
}
private static int AlignTo(int offset, int alignment)
{
return (offset + alignment - 1) & ~(alignment - 1);
}
private static int SizeOf(NubType type)
{
if (type.IsSimpleType(out var simpleType, out var complexType))
{
return simpleType.StorageSize switch
{
StorageSize.I64 or StorageSize.U64 or StorageSize.F64 => 8,
StorageSize.I32 or StorageSize.U32 or StorageSize.F32 => 4,
StorageSize.I16 or StorageSize.U16 => 2,
StorageSize.I8 or StorageSize.U8 => 1,
_ => throw new ArgumentOutOfRangeException(nameof(simpleType.StorageSize))
};
}
// Only custom types such as structs/traits have known sizes for now. For objects other than custom types, we store pointers
if (complexType is not NubCustomType customType)
{
return 8;
}
switch (customType.Kind(_definitionTable))
{
case CustomTypeKind.Struct:
{
var structDef = _definitionTable.LookupStruct(customType.Namespace, customType.Name);
var size = 0;
var maxAlignment = 1;
foreach (var field in structDef.Fields)
{
var fieldAlignment = field.Type.Alignment(_definitionTable);
maxAlignment = Math.Max(maxAlignment, fieldAlignment);
size = AlignTo(size, fieldAlignment);
size += SizeOf(field.Type);
}
return AlignTo(size, maxAlignment);
}
case CustomTypeKind.Trait:
{
return 16;
}
default:
throw new ArgumentOutOfRangeException();
}
}
private static int OffsetOf(BoundStructNode structDefinition, string member)
{
var offset = 0;
foreach (var field in structDefinition.Fields)
{
if (field.Name == member)
{
return offset;
}
var fieldAlignment = field.Type.Alignment(_definitionTable);
offset = AlignTo(offset, fieldAlignment);
offset += SizeOf(field.Type);
}
throw new UnreachableException($"Member '{member}' not found in struct");
}
private static void EmitStore(NubType type, string value, string destination)
{
string store;
@@ -279,7 +206,7 @@ public static class QBEGenerator
{
var size = TmpName();
_writer.Indented($"{size} =l loadl {array}");
_writer.Indented($"{size} =l mul {size}, {SizeOf(type.ElementType)}");
_writer.Indented($"{size} =l mul {size}, {type.ElementType.Size(_definitionTable)}");
_writer.Indented($"{size} =l add {size}, 8");
return size;
}
@@ -345,7 +272,7 @@ public static class QBEGenerator
{
if (complexType is NubCustomType customType)
{
EmitMemcpy(value, destinationPointer, SizeOf(customType).ToString());
EmitMemcpy(value, destinationPointer, customType.Size(_definitionTable).ToString());
}
else
{
@@ -403,7 +330,7 @@ public static class QBEGenerator
NubArrayType arrayType => EmitArraySizeInBytes(arrayType, value),
NubCStringType => EmitCStringSizeInBytes(value),
NubStringType => EmitStringSizeInBytes(value),
NubCustomType customType => SizeOf(customType).ToString(),
NubCustomType customType => customType.Size(_definitionTable).ToString(),
_ => throw new ArgumentOutOfRangeException(nameof(source.Type))
};
@@ -575,10 +502,10 @@ public static class QBEGenerator
case BoundAssignmentNode assignment:
EmitAssignment(assignment);
break;
case BoundBreakNode @break:
case BoundBreakNode:
EmitBreak();
break;
case BoundContinueNode @continue:
case BoundContinueNode:
EmitContinue();
break;
case BoundIfNode ifStatement:
@@ -754,10 +681,12 @@ public static class QBEGenerator
var array = EmitUnwrap(EmitExpression(arrayIndexAccess.Target));
var index = EmitUnwrap(EmitExpression(arrayIndexAccess.Index));
EmitArrayBoundsCheck(array, index);
var elementType = ((NubArrayType)arrayIndexAccess.Target.Type).ElementType;
var pointer = TmpName();
_writer.Indented($"{pointer} =l mul {index}, {SizeOf(elementType)}");
_writer.Indented($"{pointer} =l mul {index}, {elementType.Size(_definitionTable)}");
_writer.Indented($"{pointer} =l add {pointer}, 8");
_writer.Indented($"{pointer} =l add {array}, {pointer}");
return new Val(pointer, arrayIndexAccess.Type, ValKind.Pointer);
@@ -790,7 +719,7 @@ public static class QBEGenerator
private static Val EmitArrayInitializer(BoundArrayInitializerNode arrayInitializer)
{
var capacity = EmitUnwrap(EmitExpression(arrayInitializer.Capacity));
var elementSize = SizeOf(arrayInitializer.ElementType);
var elementSize = arrayInitializer.ElementType.Size(_definitionTable);
var capacityInBytes = TmpName();
_writer.Indented($"{capacityInBytes} =l mul {capacity}, {elementSize}");
@@ -816,7 +745,11 @@ public static class QBEGenerator
private static Val EmitAddressOf(BoundAddressOfNode addressOf)
{
var value = EmitExpression(addressOf.Expression);
Debug.Assert(value.Kind == ValKind.Pointer);
if (value.Kind != ValKind.Pointer)
{
throw new UnreachableException("Tried to take address of non-pointer type. This should have been causht in the type checker");
}
return new Val(value.Name, addressOf.Type, ValKind.Direct);
}
@@ -1033,7 +966,7 @@ public static class QBEGenerator
if (destination == null)
{
destination = TmpName();
var size = SizeOf(structInitializer.StructType);
var size = structInitializer.StructType.Size(_definitionTable);
_writer.Indented($"{destination} =l alloc8 {size}");
}
@@ -1177,6 +1110,26 @@ public static class QBEGenerator
_ => throw new ArgumentOutOfRangeException()
};
}
private static int OffsetOf(BoundStructNode structDefinition, string member)
{
var offset = 0;
foreach (var field in structDefinition.Fields)
{
if (field.Name == member)
{
return offset;
}
var fieldAlignment = field.Type.Alignment(_definitionTable);
offset = NubType.AlignTo(offset, fieldAlignment);
offset += field.Type.Size(_definitionTable);
}
throw new UnreachableException($"Member '{member}' not found in struct");
}
}
internal class StringLiteral(string value, string name)

View File

@@ -37,8 +37,14 @@ public abstract class NubType : IEquatable<NubType>
throw new ArgumentException($"Type {this} is not a simple type, not a compex type");
}
public abstract int Size(BoundDefinitionTable definitionTable);
public abstract int Alignment(BoundDefinitionTable definitionTable);
public static int AlignTo(int offset, int alignment)
{
return (offset + alignment - 1) & ~(alignment - 1);
}
public override bool Equals(object? obj) => obj is NubType other && Equals(other);
public abstract bool Equals(NubType? other);
@@ -68,7 +74,7 @@ public abstract class NubSimpleType : NubType
{
public abstract StorageSize StorageSize { get; }
public override int Alignment(BoundDefinitionTable definitionTable)
public override int Size(BoundDefinitionTable definitionTable)
{
return StorageSize switch
{
@@ -79,6 +85,11 @@ public abstract class NubSimpleType : NubType
_ => throw new ArgumentOutOfRangeException(nameof(StorageSize))
};
}
public override int Alignment(BoundDefinitionTable definitionTable)
{
return Size(definitionTable);
}
}
#region Simple types
@@ -196,7 +207,8 @@ public abstract class NubComplexType : NubType;
public class NubCStringType : NubComplexType
{
public override int Alignment(BoundDefinitionTable definitionTable) => 8;
public override int Size(BoundDefinitionTable definitionTable) => 8;
public override int Alignment(BoundDefinitionTable definitionTable) => Size(definitionTable);
public override string ToString() => "cstring";
public override bool Equals(NubType? other) => other is NubCStringType;
@@ -205,7 +217,8 @@ public class NubCStringType : NubComplexType
public class NubStringType : NubComplexType
{
public override int Alignment(BoundDefinitionTable definitionTable) => 8;
public override int Size(BoundDefinitionTable definitionTable) => 8;
public override int Alignment(BoundDefinitionTable definitionTable) => Size(definitionTable);
public override string ToString() => "string";
public override bool Equals(NubType? other) => other is NubStringType;
@@ -232,6 +245,36 @@ public class NubCustomType(string @namespace, string name) : NubComplexType
throw new ArgumentException($"Definition table does not have any type information for {this}");
}
public override int Size(BoundDefinitionTable definitionTable)
{
switch (Kind(definitionTable))
{
case CustomTypeKind.Struct:
{
var structDef = definitionTable.LookupStruct(Namespace, Name);
var size = 0;
var maxAlignment = 1;
foreach (var field in structDef.Fields)
{
var fieldAlignment = field.Type.Alignment(definitionTable);
maxAlignment = Math.Max(maxAlignment, fieldAlignment);
size = AlignTo(size, fieldAlignment);
size += field.Type.Size(definitionTable);
}
return AlignTo(size, maxAlignment);
}
case CustomTypeKind.Trait:
{
return 16;
}
default:
throw new ArgumentOutOfRangeException();
}
}
public override int Alignment(BoundDefinitionTable definitionTable)
{
switch (Kind(definitionTable))
@@ -260,7 +303,8 @@ public class NubArrayType(NubType elementType) : NubComplexType
{
public NubType ElementType { get; } = elementType;
public override int Alignment(BoundDefinitionTable definitionTable) => 8;
public override int Size(BoundDefinitionTable definitionTable) => 8;
public override int Alignment(BoundDefinitionTable definitionTable) => Size(definitionTable);
public override string ToString() => "[]" + ElementType;