From 896d1fe1eae1fdf58bb44759c8aabdbafde2f4b5 Mon Sep 17 00:00:00 2001 From: nub31 Date: Sun, 6 Jul 2025 22:46:40 +0200 Subject: [PATCH] ... --- .../NubLang/Generation/QBE/QBEGenerator.cs | 117 ++++++------------ src/compiler/NubLang/NubType.cs | 52 +++++++- 2 files changed, 83 insertions(+), 86 deletions(-) diff --git a/src/compiler/NubLang/Generation/QBE/QBEGenerator.cs b/src/compiler/NubLang/Generation/QBE/QBEGenerator.cs index 982b798..e16676d 100644 --- a/src/compiler/NubLang/Generation/QBE/QBEGenerator.cs +++ b/src/compiler/NubLang/Generation/QBE/QBEGenerator.cs @@ -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) diff --git a/src/compiler/NubLang/NubType.cs b/src/compiler/NubLang/NubType.cs index fb686ef..f926a51 100644 --- a/src/compiler/NubLang/NubType.cs +++ b/src/compiler/NubLang/NubType.cs @@ -37,8 +37,14 @@ public abstract class NubType : IEquatable 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;