This commit is contained in:
nub31
2025-08-13 20:01:09 +02:00
parent bdcf0d3e7d
commit 46a2057e43
6 changed files with 41 additions and 35 deletions

View File

@@ -16,18 +16,18 @@ struct Human : Printable, Stringable
func str(): cstring func str(): cstring
{ {
return this^.name return this.name
} }
func print() func print()
{ {
puts(this^.str()) puts(this.str())
} }
} }
func main(args: []cstring): i64 func main(args: []cstring): i64
{ {
let human: Stringable = alloc Human { let human = alloc Human {
name = "oliver" name = "oliver"
} }

View File

@@ -117,9 +117,10 @@ var typedDefinitionTable = new TypedDefinitionTable(typedSyntaxTrees);
var objectFiles = new List<string>(); var objectFiles = new List<string>();
foreach (var syntaxTree in typedSyntaxTrees) for (var i = 0; i < typedSyntaxTrees.Count; i++)
{ {
var outFileName = HexString.CreateUnique(8); var syntaxTree = typedSyntaxTrees[i];
var outFileName = Path.GetFileNameWithoutExtension(options.Files[i].Path);
var generator = new QBEGenerator(syntaxTree, typedDefinitionTable); var generator = new QBEGenerator(syntaxTree, typedDefinitionTable);
var ssa = generator.Emit(); var ssa = generator.Emit();

View File

@@ -110,7 +110,7 @@ public partial class QBEGenerator
var value = EmitExpression(addressOf.Expression); var value = EmitExpression(addressOf.Expression);
if (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"); throw new UnreachableException("Tried to take address of non-pointer type. This should have been caught in the type checker");
} }
return new Val(value.Name, addressOf.Type, ValKind.Direct); return new Val(value.Name, addressOf.Type, ValKind.Direct);
@@ -333,11 +333,6 @@ public partial class QBEGenerator
_writer.Indented($"{destination} =l alloc8 {size}"); _writer.Indented($"{destination} =l alloc8 {size}");
} }
// if (structDef.InterfaceImplementations.Any())
// {
// _writer.Indented($"storel {destination}, {StructVtableName(structDef.Name)}");
// }
foreach (var field in structDef.Fields) foreach (var field in structDef.Fields)
{ {
if (!structInitializer.Initializers.TryGetValue(field.Name, out var valueExpression)) if (!structInitializer.Initializers.TryGetValue(field.Name, out var valueExpression))
@@ -345,7 +340,10 @@ public partial class QBEGenerator
valueExpression = field.Value.Value; valueExpression = field.Value.Value;
} }
Debug.Assert(valueExpression != null); if (valueExpression == null)
{
throw new UnreachableException("Value of field in uninitialized. This should have been caught in the type checker");
}
var offset = TmpName(); var offset = TmpName();
_writer.Indented($"{offset} =l add {destination}, {OffsetOf(structDef, field.Name)}"); _writer.Indented($"{offset} =l add {destination}, {OffsetOf(structDef, field.Name)}");
@@ -423,13 +421,12 @@ public partial class QBEGenerator
private Val EmitStructFuncAccess(StructFuncAccessNode structFuncAccess) private Val EmitStructFuncAccess(StructFuncAccessNode structFuncAccess)
{ {
var target = EmitExpression(structFuncAccess.Target); var target = EmitUnwrap(EmitExpression(structFuncAccess.Target));
Debug.Assert(target.Kind == ValKind.Pointer);
var structDef = _definitionTable.LookupStruct(structFuncAccess.StructType.Name); var structDef = _definitionTable.LookupStruct(structFuncAccess.StructType.Name);
var func = StructFuncName(structDef.Name, structFuncAccess.Func); var func = StructFuncName(structDef.Name, structFuncAccess.Func);
return new Val(func, structFuncAccess.Type, ValKind.Direct, target.Name); return new Val(func, structFuncAccess.Type, ValKind.Direct, target);
} }
private Val EmitInterfaceFuncAccess(InterfaceFuncAccessNode interfaceFuncAccess) private Val EmitInterfaceFuncAccess(InterfaceFuncAccessNode interfaceFuncAccess)
@@ -449,13 +446,16 @@ public partial class QBEGenerator
var func = TmpName(); var func = TmpName();
_writer.Indented($"{func} =l loadl {funcOffset}"); _writer.Indented($"{func} =l loadl {funcOffset}");
var dataPointer = TmpName();
_writer.Indented($"{dataPointer} =l add {target}, 8");
var data = TmpName(); var data = TmpName();
_writer.Indented($"{data} =l add {target}, 8"); _writer.Indented($"{data} =l loadl {dataPointer}");
return new Val(func, interfaceFuncAccess.Type, ValKind.Direct, data); return new Val(func, interfaceFuncAccess.Type, ValKind.Direct, data);
} }
private Val EmitInterfaceInitializer(InterfaceInitializerNode interfaceInitializer) private Val EmitInterfaceInitializer(InterfaceInitializerNode interfaceInitializer, string? destination = null)
{ {
var implementation = EmitUnwrap(EmitExpression(interfaceInitializer.Implementation)); var implementation = EmitUnwrap(EmitExpression(interfaceInitializer.Implementation));
@@ -470,27 +470,28 @@ public partial class QBEGenerator
vtableOffset += interfaceImplementation.Functions.Count * 8; vtableOffset += interfaceImplementation.Functions.Count * 8;
} }
var result = TmpName(); if (destination == null)
_writer.Indented($"{result} =l alloc8 16"); {
destination = TmpName();
_writer.Indented($"{destination} =l alloc8 {SizeOf(interfaceInitializer.InterfaceType)}");
}
var interfaceVtablePointer = TmpName(); var interfaceVtablePointer = TmpName();
_writer.Indented($"{interfaceVtablePointer} =l add {StructVtableName(interfaceInitializer.StructType.Name)}, {vtableOffset}"); _writer.Indented($"{interfaceVtablePointer} =l add {StructVtableName(interfaceInitializer.StructType.Name)}, {vtableOffset}");
_writer.Indented($"storel {interfaceVtablePointer}, {result}"); _writer.Indented($"storel {interfaceVtablePointer}, {destination}");
var objectPointer = TmpName(); var objectPointer = TmpName();
_writer.Indented($"{objectPointer} =l add {result}, 8"); _writer.Indented($"{objectPointer} =l add {destination}, 8");
_writer.Indented($"storel {implementation}, {objectPointer}"); _writer.Indented($"storel {implementation}, {objectPointer}");
return new Val(result, interfaceInitializer.InterfaceType, ValKind.Direct); return new Val(destination, interfaceInitializer.InterfaceType, ValKind.Direct);
} }
private Val EmitFuncCall(FuncCallNode funcCall) private Val EmitFuncCall(FuncCallNode funcCall)
{ {
var expression = EmitExpression(funcCall.Expression); var expression = EmitExpression(funcCall.Expression);
var funcPointer = EmitUnwrap(expression);
var parameterStrings = new List<string>(); var parameterStrings = new List<string>();
if (expression.ThisArg != null) if (expression.ThisArg != null)
{ {
parameterStrings.Add($"l {expression.ThisArg}"); parameterStrings.Add($"l {expression.ThisArg}");
@@ -502,6 +503,7 @@ public partial class QBEGenerator
parameterStrings.Add($"{FuncQBETypeName(parameter.Type)} {copy}"); parameterStrings.Add($"{FuncQBETypeName(parameter.Type)} {copy}");
} }
var funcPointer = EmitUnwrap(expression);
if (funcCall.Type is VoidTypeNode) if (funcCall.Type is VoidTypeNode)
{ {
_writer.Indented($"call {funcPointer}({string.Join(", ", parameterStrings)})"); _writer.Indented($"call {funcPointer}({string.Join(", ", parameterStrings)})");

View File

@@ -41,7 +41,11 @@ public partial class QBEGenerator
private void EmitAssignment(AssignmentNode assignment) private void EmitAssignment(AssignmentNode assignment)
{ {
var destination = EmitExpression(assignment.Target); var destination = EmitExpression(assignment.Target);
Debug.Assert(destination.Kind == ValKind.Pointer); if (destination.Kind != ValKind.Pointer)
{
throw new UnreachableException("Destination of assignment must be a pointer. This should be caught in the type checker");
}
EmitCopyIntoOrInitialize(assignment.Value, destination.Name); EmitCopyIntoOrInitialize(assignment.Value, destination.Name);
} }

View File

@@ -224,6 +224,11 @@ public partial class QBEGenerator
EmitStructInitializer(structInitializer, destinationPointer); EmitStructInitializer(structInitializer, destinationPointer);
return true; return true;
} }
case InterfaceInitializerNode interfaceInitializer:
{
EmitInterfaceInitializer(interfaceInitializer, destinationPointer);
return true;
}
case LiteralNode { Kind: LiteralKind.String } literal: case LiteralNode { Kind: LiteralKind.String } literal:
{ {
EmitStore(source.Type, EmitUnwrap(EmitLiteral(literal)), destinationPointer); EmitStore(source.Type, EmitUnwrap(EmitLiteral(literal)), destinationPointer);
@@ -250,9 +255,9 @@ public partial class QBEGenerator
} }
else else
{ {
if (complexType is StructTypeNode structType) if (complexType is StructTypeNode or InterfaceTypeNode)
{ {
EmitMemcpy(value, destinationPointer, SizeOf(structType).ToString()); EmitMemcpy(value, destinationPointer, SizeOf(complexType).ToString());
} }
else else
{ {
@@ -261,7 +266,6 @@ public partial class QBEGenerator
ArrayTypeNode arrayType => EmitArraySizeInBytes(arrayType, value), ArrayTypeNode arrayType => EmitArraySizeInBytes(arrayType, value),
CStringTypeNode => EmitCStringSizeInBytes(value), CStringTypeNode => EmitCStringSizeInBytes(value),
StringTypeNode => EmitStringSizeInBytes(value), StringTypeNode => EmitStringSizeInBytes(value),
InterfaceTypeNode => 16.ToString(),
_ => throw new ArgumentOutOfRangeException(nameof(source.Type)) _ => throw new ArgumentOutOfRangeException(nameof(source.Type))
}; };
@@ -311,7 +315,7 @@ public partial class QBEGenerator
ArrayTypeNode arrayType => EmitArraySizeInBytes(arrayType, value), ArrayTypeNode arrayType => EmitArraySizeInBytes(arrayType, value),
CStringTypeNode => EmitCStringSizeInBytes(value), CStringTypeNode => EmitCStringSizeInBytes(value),
StringTypeNode => EmitStringSizeInBytes(value), StringTypeNode => EmitStringSizeInBytes(value),
InterfaceTypeNode => 16.ToString(), InterfaceTypeNode interfaceType => SizeOf(interfaceType).ToString(),
StructTypeNode structType => SizeOf(structType).ToString(), StructTypeNode structType => SizeOf(structType).ToString(),
_ => throw new ArgumentOutOfRangeException(nameof(source.Type)) _ => throw new ArgumentOutOfRangeException(nameof(source.Type))
}; };
@@ -486,11 +490,6 @@ public partial class QBEGenerator
{ {
var offset = 0; var offset = 0;
// if (structType.InterfaceImplementations.Any())
// {
// offset = 8;
// }
foreach (var field in structType.Fields) foreach (var field in structType.Fields)
{ {
var fieldAlignment = AlignmentOf(field); var fieldAlignment = AlignmentOf(field);

View File

@@ -73,7 +73,7 @@ public sealed class Parser
if (thisArg != null) if (thisArg != null)
{ {
parameters.Add(new FuncParameterSyntax([], "this", new PointerTypeSyntax([], thisArg))); parameters.Add(new FuncParameterSyntax([], "this", thisArg));
} }
ExpectSymbol(Symbol.OpenParen); ExpectSymbol(Symbol.OpenParen);