This commit is contained in:
nub31
2025-06-07 19:05:11 +02:00
parent 8ea26cea2e
commit 75c4473a5b
15 changed files with 1275 additions and 208 deletions

View File

@@ -21,7 +21,6 @@ public class Generator
private Stack<string> _continueLabels = [];
private int _variableIndex;
private int _labelIndex;
private int _funcIndex;
private bool _codeIsReachable = true;
private Dictionary<IFuncSignature, string> _funcNames = [];
@@ -35,7 +34,6 @@ public class Generator
_breakLabels = [];
_continueLabels = [];
_variableIndex = 0;
_funcIndex = 0;
_labelIndex = 0;
_codeIsReachable = true;
@@ -45,12 +43,14 @@ public class Generator
_builder.AppendLine();
}
var localFuncIndex = 0;
foreach (var funcSignature in _sourceFiles.SelectMany(f => f.Definitions).OfType<IFuncSignature>())
{
switch (funcSignature)
{
case ExternFuncDefinitionNode externFuncDefinitionNode:
_funcNames[funcSignature] = "$" + externFuncDefinitionNode.Name;
_funcNames[funcSignature] = "$" + externFuncDefinitionNode.CallName;
break;
case LocalFuncDefinitionNode localFuncDefinitionNode:
if (localFuncDefinitionNode.Exported)
@@ -59,8 +59,7 @@ public class Generator
}
else
{
var funcName = GenFuncName();
_funcNames[funcSignature] = funcName;
_funcNames[funcSignature] = $"$func{++localFuncIndex}";
}
break;
@@ -88,7 +87,6 @@ public class Generator
private enum TypeContext
{
Struct,
FuncDef,
FuncCall,
}
@@ -97,30 +95,6 @@ public class Generator
{
return context switch
{
TypeContext.Struct => type switch
{
NubArrayType => "l", // TODO: Arrays in structs are pointers for now
NubPointerType => "l",
NubPrimitiveType primitiveType => primitiveType.Kind switch
{
PrimitiveTypeKind.I64 => "l",
PrimitiveTypeKind.I32 => "w",
PrimitiveTypeKind.I16 => "h",
PrimitiveTypeKind.I8 => "b",
PrimitiveTypeKind.U64 => "l",
PrimitiveTypeKind.U32 => "w",
PrimitiveTypeKind.U16 => "h",
PrimitiveTypeKind.U8 => "b",
PrimitiveTypeKind.F64 => "d",
PrimitiveTypeKind.F32 => "s",
PrimitiveTypeKind.Bool => "w",
PrimitiveTypeKind.String => "l", // TODO: Strings in structs are pointers for now
PrimitiveTypeKind.Any => throw new NotSupportedException("any type cannot be used in structs"),
_ => throw new ArgumentOutOfRangeException()
},
NubStructType => throw new NotImplementedException(),
_ => throw new ArgumentOutOfRangeException(nameof(type))
},
TypeContext.FuncDef => type switch
{
NubArrayType => "l",
@@ -143,6 +117,7 @@ public class Generator
_ => throw new ArgumentOutOfRangeException()
},
NubStructType structType => $":{structType.Namespace}_{structType.Name}",
NubFixedArrayType => "l",
_ => throw new ArgumentOutOfRangeException(nameof(type))
},
TypeContext.FuncCall => type switch
@@ -167,6 +142,7 @@ public class Generator
_ => throw new ArgumentOutOfRangeException()
},
NubStructType structType => $":{structType.Namespace}_{structType.Name}",
NubFixedArrayType => "l",
_ => throw new ArgumentOutOfRangeException(nameof(type))
},
_ => throw new ArgumentOutOfRangeException(nameof(context), context, null)
@@ -197,6 +173,7 @@ public class Generator
_ => throw new ArgumentOutOfRangeException()
},
NubStructType => "l",
NubFixedArrayType => "l",
_ => throw new ArgumentOutOfRangeException(nameof(type))
}}";
}
@@ -225,6 +202,7 @@ public class Generator
_ => throw new ArgumentOutOfRangeException()
},
NubStructType => "l",
NubFixedArrayType => "l",
_ => throw new ArgumentOutOfRangeException(nameof(type))
}}";
}
@@ -253,11 +231,12 @@ public class Generator
_ => throw new ArgumentOutOfRangeException()
},
NubStructType => "l",
NubFixedArrayType => "l",
_ => throw new ArgumentOutOfRangeException(nameof(type))
}}";
}
private int QbeTypeSize(NubType type)
private int SizeOf(NubType type)
{
switch (type)
{
@@ -291,16 +270,20 @@ public class Generator
case NubStructType nubStructType:
{
var definition = LookupStructDefinition(nubStructType.Namespace, nubStructType.Name);
return definition.Fields.Sum(f => QbeTypeSize(f.Type));
return definition.Fields.Sum(f => SizeOf(f.Type));
}
case NubPointerType:
case NubArrayType:
{
return 8;
}
case NubFixedArrayType nubFixedArrayType:
{
return SizeOf(nubFixedArrayType.ElementType) * nubFixedArrayType.Capacity;
}
default:
{
throw new NotImplementedException();
throw new UnreachableException();
}
}
}
@@ -313,6 +296,7 @@ public class Generator
NubPointerType => false,
NubPrimitiveType => false,
NubStructType => true,
NubFixedArrayType => true,
_ => throw new ArgumentOutOfRangeException(nameof(type))
};
}
@@ -368,7 +352,7 @@ public class Generator
}
var pointerName = GenVarName();
_builder.AppendLine($" {pointerName} {QBEAssign(parameter.Type)} alloc8 {QbeTypeSize(parameter.Type)}");
_builder.AppendLine($" {pointerName} {QBEAssign(parameter.Type)} alloc8 {SizeOf(parameter.Type)}");
_builder.AppendLine($" storel %{parameterName}, {pointerName}");
_variables[parameter.Name] = new Variable
@@ -403,8 +387,42 @@ public class Generator
private void GenerateStructDefinition(StructDefinitionNode structDefinition)
{
var fields = structDefinition.Fields.Select(f => QBEType(f.Type, TypeContext.Struct));
_builder.AppendLine($"type :{structDefinition.Name} = {{ {string.Join(", ", fields)} }}");
_builder.Append($"type :{structDefinition.Namespace}_{structDefinition.Name} = {{ ");
foreach (var structDefinitionField in structDefinition.Fields)
{
var fieldDefinition = GenerateFieldType(structDefinitionField.Type);
_builder.Append(fieldDefinition + ", ");
}
_builder.AppendLine("}");
}
private string GenerateFieldType(NubType type)
{
return type switch
{
NubArrayType => "l",
NubPointerType => "l",
NubPrimitiveType primitiveType => primitiveType.Kind switch
{
PrimitiveTypeKind.I64 => "l",
PrimitiveTypeKind.I32 => "w",
PrimitiveTypeKind.I16 => "h",
PrimitiveTypeKind.I8 => "b",
PrimitiveTypeKind.U64 => "l",
PrimitiveTypeKind.U32 => "w",
PrimitiveTypeKind.U16 => "h",
PrimitiveTypeKind.U8 => "b",
PrimitiveTypeKind.F64 => "d",
PrimitiveTypeKind.F32 => "s",
PrimitiveTypeKind.Bool => "w",
PrimitiveTypeKind.String => "l",
PrimitiveTypeKind.Any => throw new NotSupportedException("any type cannot be used in structs"),
_ => throw new ArgumentOutOfRangeException()
},
NubStructType structType => $":{structType.Namespace}_{structType.Name}",
NubFixedArrayType fixedArrayType => $"b {SizeOf(fixedArrayType)}",
_ => throw new ArgumentOutOfRangeException(nameof(type))
};
}
private void GenerateStatement(StatementNode statement)
@@ -451,31 +469,59 @@ public class Generator
private void GenerateArrayIndexAssignment(ArrayIndexAssignmentNode arrayIndexAssignment)
{
var arrayType = (NubArrayType)arrayIndexAssignment.ArrayIndexAccess.Array.Type;
var array = GenerateExpression(arrayIndexAssignment.ArrayIndexAccess.Array);
var index = GenerateExpression(arrayIndexAssignment.ArrayIndexAccess.Index);
GenerateArrayBoundsCheck(array, index);
var value = GenerateExpression(arrayIndexAssignment.Value);
var startName = GenVarName();
_builder.AppendLine($" {startName} =l add {array}, 8");
var adjustedIndex = GenVarName();
_builder.AppendLine($" {adjustedIndex} =l mul {index}, {QbeTypeSize(arrayType.BaseType)}");
var offsetName = GenVarName();
_builder.AppendLine($" {offsetName} =l add {startName}, {adjustedIndex}");
if (IsLargeType(arrayType.BaseType))
switch (arrayIndexAssignment.ArrayIndexAccess.Array.Type)
{
_builder.AppendLine($" blit {value}, {offsetName}, {QbeTypeSize(arrayType.BaseType)}");
}
else
{
_builder.AppendLine($" {QBEStore(arrayType.BaseType)} {value}, {offsetName}");
case NubArrayType arrayType:
{
var startName = GenVarName();
_builder.AppendLine($" {startName} =l add {array}, 8");
var adjustedIndex = GenVarName();
_builder.AppendLine($" {adjustedIndex} =l mul {index}, {SizeOf(arrayType.ElementType)}");
var offsetName = GenVarName();
_builder.AppendLine($" {offsetName} =l add {startName}, {adjustedIndex}");
if (IsLargeType(arrayType.ElementType))
{
_builder.AppendLine($" blit {value}, {offsetName}, {SizeOf(arrayType.ElementType)}");
}
else
{
_builder.AppendLine($" {QBEStore(arrayType.ElementType)} {value}, {offsetName}");
}
break;
}
case NubFixedArrayType fixedArrayType:
{
var startName = GenVarName();
_builder.AppendLine($" {startName} =l add {array}, 8");
var adjustedIndex = GenVarName();
_builder.AppendLine($" {adjustedIndex} =l mul {index}, {SizeOf(fixedArrayType.ElementType)}");
var offsetName = GenVarName();
_builder.AppendLine($" {offsetName} =l add {startName}, {adjustedIndex}");
if (IsLargeType(fixedArrayType.ElementType))
{
_builder.AppendLine($" blit {value}, {offsetName}, {SizeOf(fixedArrayType.ElementType)}");
}
else
{
_builder.AppendLine($" {QBEStore(fixedArrayType.ElementType)} {value}, {offsetName}");
}
break;
}
default:
{
throw new UnreachableException();
}
}
}
@@ -508,7 +554,7 @@ public class Generator
if (IsLargeType(dereferenceAssignment.Value.Type))
{
_builder.AppendLine($" blit {value}, {location}, {QbeTypeSize(dereferenceAssignment.Value.Type)}");
_builder.AppendLine($" blit {value}, {location}, {SizeOf(dereferenceAssignment.Value.Type)}");
}
else
{
@@ -555,7 +601,14 @@ public class Generator
var value = GenerateExpression(memberAssignment.Value);
throw new NotImplementedException();
if (IsLargeType(memberAssignment.Value.Type))
{
_builder.AppendLine($" blit {value}, {offsetName}, {SizeOf(memberAssignment.Value.Type)}");
}
else
{
_builder.AppendLine($" {QBEStore(memberAssignment.Value.Type)} {value}, {offsetName}");
}
}
private void GenerateReturn(ReturnNode @return)
@@ -579,30 +632,31 @@ public class Generator
private void GenerateVariableDeclaration(VariableDeclarationNode variableDeclaration)
{
var pointerName = GenVarName();
var type = variableDeclaration.ExplicitType.Value ?? variableDeclaration.Value.Value?.Type!;
_builder.AppendLine($" {pointerName} {QBEAssign(type)} alloc8 {QbeTypeSize(type)}");
string pointerName;
if (variableDeclaration.Value.HasValue)
{
var result = GenerateExpression(variableDeclaration.Value.Value);
if (IsLargeType(type))
{
_builder.AppendLine($" blit {result}, {pointerName}, {QbeTypeSize(type)}");
pointerName = result;
}
else
{
pointerName = GenVarName();
_builder.AppendLine($" {pointerName} {QBEAssign(type)} alloc8 {SizeOf(type)}");
_builder.AppendLine($" {QBEStore(type)} {result}, {pointerName}");
}
}
else
{
pointerName = GenVarName();
_builder.AppendLine($" {pointerName} {QBEAssign(type)} alloc8 {SizeOf(type)}");
if (IsLargeType(type))
{
_builder.AppendLine($" blit 0, {pointerName}, {QbeTypeSize(type)}");
_builder.AppendLine($" call $nub_memset(l {pointerName}, ub 0, l {SizeOf(type)})");
}
else
{
@@ -648,6 +702,7 @@ public class Generator
BinaryExpressionNode binaryExpression => GenerateBinaryExpression(binaryExpression),
CastNode cast => GenerateCast(cast),
DereferenceNode dereference => GenerateDereference(dereference),
FixedArrayInitializerNode fixedArrayInitializer => GenerateFixedArrayInitializer(fixedArrayInitializer),
FuncCallNode funcCallExpression => GenerateFuncCall(funcCallExpression),
IdentifierNode identifier => GenerateIdentifier(identifier),
LiteralNode literal => GenerateLiteral(literal),
@@ -660,29 +715,56 @@ public class Generator
private string GenerateArrayIndex(ArrayIndexAccessNode arrayIndexAccess)
{
var arrayType = ((NubArrayType)arrayIndexAccess.Array.Type).BaseType;
var array = GenerateExpression(arrayIndexAccess.Array);
var index = GenerateExpression(arrayIndexAccess.Index);
GenerateArrayBoundsCheck(array, index);
var firstItemPointerName = GenVarName();
_builder.AppendLine($" {firstItemPointerName} =l add {array}, 8");
var offsetPointerName = GenVarName();
_builder.AppendLine($" {offsetPointerName} =l mul {index}, {QbeTypeSize(arrayType)}");
var resultPointerName = GenVarName();
_builder.AppendLine($" {resultPointerName} =l add {firstItemPointerName}, {offsetPointerName}");
switch (arrayIndexAccess.Array.Type)
{
case NubArrayType arrayType:
{
var firstItemPointerName = GenVarName();
_builder.AppendLine($" {firstItemPointerName} =l add {array}, 8");
var offsetPointerName = GenVarName();
_builder.AppendLine($" {offsetPointerName} =l mul {index}, {SizeOf(arrayType.ElementType)}");
var resultPointerName = GenVarName();
_builder.AppendLine($" {resultPointerName} =l add {firstItemPointerName}, {offsetPointerName}");
if (IsLargeType(arrayType))
{
return resultPointerName;
}
else
{
var outputName = GenVarName();
_builder.AppendLine($" {outputName} {QBEAssign(arrayType)} {QBELoad(arrayType)} {resultPointerName}");
return outputName;
if (IsLargeType(arrayType.ElementType))
{
return resultPointerName;
}
else
{
var outputName = GenVarName();
_builder.AppendLine($" {outputName} {QBEAssign(arrayType.ElementType)} {QBELoad(arrayType.ElementType)} {resultPointerName}");
return outputName;
}
}
case NubFixedArrayType fixedArrayType:
{
var firstItemPointerName = GenVarName();
_builder.AppendLine($" {firstItemPointerName} =l add {array}, 8");
var offsetPointerName = GenVarName();
_builder.AppendLine($" {offsetPointerName} =l mul {index}, {SizeOf(fixedArrayType.ElementType)}");
var resultPointerName = GenVarName();
_builder.AppendLine($" {resultPointerName} =l add {firstItemPointerName}, {offsetPointerName}");
if (IsLargeType(fixedArrayType.ElementType))
{
return resultPointerName;
}
else
{
var outputName = GenVarName();
_builder.AppendLine($" {outputName} {QBEAssign(fixedArrayType.ElementType)} {QBELoad(fixedArrayType.ElementType)} {resultPointerName}");
return outputName;
}
}
default:
{
throw new UnreachableException();
}
}
}
@@ -714,7 +796,7 @@ public class Generator
{
var capacity = GenerateExpression(arrayInitializer.Capacity);
var capacityInBytes = GenVarName();
_builder.AppendLine($" {capacityInBytes} =l mul {capacity}, {QbeTypeSize(arrayInitializer.ElementType)}");
_builder.AppendLine($" {capacityInBytes} =l mul {capacity}, {SizeOf(arrayInitializer.ElementType)}");
var totalArraySize = GenVarName();
_builder.AppendLine($" {totalArraySize} =l add {capacityInBytes}, 8");
var outputName = GenVarName();
@@ -1483,7 +1565,7 @@ public class Generator
var structDefinition = LookupStructDefinition(structInitializer.StructType.Namespace, structInitializer.StructType.Name);
var structVar = GenVarName();
var size = structDefinition.Fields.Sum(x => QbeTypeSize(x.Type));
var size = structDefinition.Fields.Sum(x => SizeOf(x.Type));
_builder.AppendLine($" {structVar} =l alloc8 {size}");
foreach (var field in structDefinition.Fields)
@@ -1498,7 +1580,7 @@ public class Generator
if (IsLargeType(field.Type))
{
_builder.AppendLine($" blit {var}, {offsetName}, {QbeTypeSize(field.Type)}");
_builder.AppendLine($" blit {var}, {offsetName}, {SizeOf(field.Type)}");
}
else
{
@@ -1513,7 +1595,7 @@ public class Generator
if (IsLargeType(field.Type))
{
_builder.AppendLine($" blit {var}, {offsetName}, {QbeTypeSize(field.Type)}");
_builder.AppendLine($" blit {var}, {offsetName}, {SizeOf(field.Type)}");
}
else
{
@@ -1620,6 +1702,20 @@ public class Generator
}
}
private string GenerateFixedArrayInitializer(FixedArrayInitializerNode fixedArrayInitializer)
{
var capacityInBytes = SizeOf(fixedArrayInitializer.Type);
var outputName = GenVarName();
_builder.AppendLine($" {outputName} =l alloc8 {capacityInBytes + 8}");
_builder.AppendLine($" storel {fixedArrayInitializer.Capacity}, {outputName}");
var dataPtr = GenVarName();
_builder.AppendLine($" {dataPtr} =l add {outputName}, 8");
_builder.AppendLine($" call $nub_memset(l {dataPtr}, w 0, l {capacityInBytes})");
return outputName;
}
private string GenerateFuncCall(FuncCallNode funcCall)
{
var funcDefinition = LookupFuncSignature(funcCall.Namespace, funcCall.Name, funcCall.Parameters.Select(p => p.Type).ToList());
@@ -1664,11 +1760,6 @@ public class Generator
return $"%v{++_variableIndex}";
}
private string GenFuncName()
{
return $"$f{++_funcIndex}";
}
private string GenLabelName()
{
return $"@l{++_labelIndex}";
@@ -1694,7 +1785,7 @@ public class Generator
private int LookupMemberOffset(StructDefinitionNode structDefinition, string member)
{
return structDefinition.Fields.TakeWhile(f => f.Name != member).Sum(f => QbeTypeSize(f.Type));
return structDefinition.Fields.TakeWhile(f => f.Name != member).Sum(f => SizeOf(f.Type));
}
private class Variable