From e0bbb7478e308295560f3fa33c92180bb89e56da Mon Sep 17 00:00:00 2001 From: nub31 Date: Fri, 16 May 2025 19:32:24 +0200 Subject: [PATCH] ... --- build.sh | 2 +- example/program.nub | 19 +- src/compiler/Nub.Lang/Backend/Generator.cs | 414 +++++++++++++++++---- src/compiler/Nub.Lang/Nub.Lang.csproj | 1 + 4 files changed, 353 insertions(+), 83 deletions(-) diff --git a/build.sh b/build.sh index 4ab9e35..88e5648 100755 --- a/build.sh +++ b/build.sh @@ -5,7 +5,7 @@ mkdir -p out echo "setup..." -dotnet publish -c Release src/compiler/Nub.Lang > /dev/null +dotnet publish -c Release src/compiler/Nub.Lang echo "compiling..." diff --git a/example/program.nub b/example/program.nub index fd27633..883fac5 100644 --- a/example/program.nub +++ b/example/program.nub @@ -1,14 +1,19 @@ import c; -struct Human { - age: i8; -} - global func main(argc: i64, argv: i64) { printf("args: %d, starts at %p\n", argc, argv); - printf("10 + 300 = %d\n", addbyte(10, 300)); + + a = 128; + b = 32768; + c = 2147483648; + d = 9223372036850000000; + + x = test(a, b, c, d); + + printf("%d\n", x); } -func addbyte(a: i32, sb: i8): i32 { - return a + sb; +func test(a: i8, b: i16, c: i32, d: i64): i64 { + printf("a: %d, b: %d, c: %d, d: %d\n", a, b, c, d); + return 12; } \ No newline at end of file diff --git a/src/compiler/Nub.Lang/Backend/Generator.cs b/src/compiler/Nub.Lang/Backend/Generator.cs index 91184b3..325d0ce 100644 --- a/src/compiler/Nub.Lang/Backend/Generator.cs +++ b/src/compiler/Nub.Lang/Backend/Generator.cs @@ -53,8 +53,9 @@ public class Generator case PrimitiveTypeKind.I64: case PrimitiveTypeKind.U64: case PrimitiveTypeKind.String: - case PrimitiveTypeKind.Any: return "l"; + case PrimitiveTypeKind.Any: + throw new NotSupportedException("Cannot convert 'any' type to QBE type"); case PrimitiveTypeKind.I32: case PrimitiveTypeKind.U32: case PrimitiveTypeKind.I16: @@ -93,8 +94,9 @@ public class Generator case PrimitiveTypeKind.I64: case PrimitiveTypeKind.U64: case PrimitiveTypeKind.String: - case PrimitiveTypeKind.Any: return "l"; + case PrimitiveTypeKind.Any: + throw new NotSupportedException("Cannot convert any to QBE type"); case PrimitiveTypeKind.I32: case PrimitiveTypeKind.U32: return "w"; @@ -135,8 +137,9 @@ public class Generator case PrimitiveTypeKind.I64: case PrimitiveTypeKind.U64: case PrimitiveTypeKind.String: - case PrimitiveTypeKind.Any: return "l"; + case PrimitiveTypeKind.Any: + throw new NotSupportedException("Cannot convert any to QBE type"); case PrimitiveTypeKind.I32: case PrimitiveTypeKind.U32: return "w"; @@ -215,15 +218,6 @@ public class Generator { _variables.Clear(); - foreach (var parameter in node.Parameters) - { - _variables.Add(parameter.Name, new Variable - { - Identifier = $"%{parameter.Name}", - Type = parameter.Type - }); - } - if (node.Global) { _builder.Append("export "); @@ -260,21 +254,33 @@ public class Generator foreach (var parameter in node.Parameters) { + var parameterName = parameter.Name; + switch (FQT(parameter.Type)) { case "sb": - _builder.AppendLine($" %{parameter.Name} =w extsb %{parameter.Name}"); + parameterName = GenName("c"); + _builder.AppendLine($" %{parameterName} =w extsb %{parameter.Name}"); break; case "ub": - _builder.AppendLine($" %{parameter.Name} =w extub %{parameter.Name}"); + parameterName = GenName("c"); + _builder.AppendLine($" %{parameterName} =w extub %{parameter.Name}"); break; case "sh": - _builder.AppendLine($" %{parameter.Name} =w extsh %{parameter.Name}"); + parameterName = GenName("c"); + _builder.AppendLine($" %{parameterName} =w extsh %{parameter.Name}"); break; case "uh": - _builder.AppendLine($" %{parameter.Name} =w extuh %{parameter.Name}"); + parameterName = GenName("c"); + _builder.AppendLine($" %{parameterName} =w extuh %{parameter.Name}"); break; } + + _variables.Add(parameter.Name, new Variable + { + Identifier = $"%{parameterName}", + Type = parameter.Type + }); } GenerateBlock(node.Body); @@ -292,16 +298,6 @@ public class Generator _builder.AppendLine($"type :{structDefinition.Name} = {{ {string.Join(", ", fields)} }}"); } - private void GenerateBlock(BlockNode block) - { - foreach (var statement in block.Statements.Where(_ => _codeIsReachable)) - { - GenerateStatement(statement); - } - - _codeIsReachable = true; - } - private void GenerateStatement(StatementNode statement) { switch (statement) @@ -332,6 +328,67 @@ public class Generator } } + private string GenerateFuncCall(FuncCall funcCall) + { + var parameterDefinitions = _definitions + .OfType() + .FirstOrDefault(d => d.Name == funcCall.Name) + ?.Parameters; + + parameterDefinitions ??= _definitions + .OfType() + .FirstOrDefault(d => d.Name == funcCall.Name) + ?.Parameters; + + if (parameterDefinitions == null) + { + throw new Exception($"Unknown function {funcCall}"); + } + + var parameterStrings = new List(); + + for (var i = 0; i < funcCall.Parameters.Count; i++) + { + if (i < parameterDefinitions.Count && parameterDefinitions[i].Variadic) + { + parameterStrings.Add("..."); + } + + NubType expectedType; + if (i < parameterDefinitions.Count) + { + expectedType = parameterDefinitions[i].Type; + } + else if (parameterDefinitions[^1].Variadic) + { + expectedType = parameterDefinitions[^1].Type; + } + else + { + throw new Exception($"Parameters for func {funcCall} does not not match"); + } + + var parameter = funcCall.Parameters[i]; + var parameterOutput = GenerateExpression(parameter); + var result = GenerateTypeConversion(parameterOutput, parameter.Type, expectedType); + + var qbeParameterType = SQT(expectedType.Equals(NubPrimitiveType.Any) ? parameter.Type : expectedType); + parameterStrings.Add($"{qbeParameterType} {result}"); + } + + return $"call ${funcCall.Name}({string.Join(", ", parameterStrings)})"; + } + + private void GenerateBlock(BlockNode block) + { + foreach (var statement in block.Statements.Where(_ => _codeIsReachable)) + { + GenerateStatement(statement); + } + + _codeIsReachable = true; + } + private void GenerateBreak() { _builder.AppendLine($" jmp @{_breakLabels.Peek()}"); @@ -346,39 +403,7 @@ public class Generator private void GenerateStatementFuncCall(FuncCallStatementNode funcCall) { - var parameterDefinition = _definitions - .OfType() - .FirstOrDefault(d => d.Name == funcCall.FuncCall.Name) - ?.Parameters; - - parameterDefinition ??= _definitions - .OfType() - .FirstOrDefault(d => d.Name == funcCall.FuncCall.Name) - ?.Parameters; - - if (parameterDefinition == null) - { - throw new Exception($"Unknown function {funcCall.FuncCall}"); - } - - var results = new List<(string, NubType)>(); - foreach (var parameter in funcCall.FuncCall.Parameters) - { - results.Add((GenerateExpression(parameter), parameter.Type)); - } - - var parameterStrings = new List(); - for (var i = 0; i < results.Count; i++) - { - if (parameterDefinition.Count > i && parameterDefinition[i].Variadic) - { - parameterStrings.Add("..."); - } - - parameterStrings.Add($"{SQT(results[i].Item2)} {results[i].Item1}"); - } - - _builder.AppendLine($" call ${funcCall.FuncCall.Name}({string.Join(", ", parameterStrings)})"); + _builder.AppendLine($" {GenerateFuncCall(funcCall.FuncCall)}"); } private void GenerateIf(IfNode ifStatement) @@ -748,7 +773,7 @@ public class Generator return $"$str{_strings.Count}"; } - if (literal.LiteralType.Equals(NubPrimitiveType.I64) || literal.LiteralType.Equals(NubPrimitiveType.I32)) + if (literal.LiteralType.Equals(NubPrimitiveType.I64)) { return literal.Literal; } @@ -761,15 +786,263 @@ public class Generator throw new NotSupportedException($"Literal {literal.LiteralType} is not supported"); } - private string GenerateCast(string input, NubType inputType, string output, NubType outputType) + private string GenerateTypeConversion(string input, NubType inputType, NubType outputType) { + if (inputType.Equals(outputType)) + { + return input; + } + if (outputType is not NubPrimitiveType primitiveOutputType || inputType is not NubPrimitiveType primitiveInputType) { throw new NotSupportedException("Casting is only supported for primitive types"); } - // var instruction = - return "" + if (primitiveOutputType.Kind == PrimitiveTypeKind.Any) return input; + if (primitiveOutputType.Kind == PrimitiveTypeKind.Bool) + { + throw new NotSupportedException("Cannot cast any type to a bool"); + } + + var outputLabel = GenName("c"); + + switch (primitiveInputType.Kind) + { + case PrimitiveTypeKind.I64: + switch (primitiveOutputType.Kind) + { + case PrimitiveTypeKind.I64: + case PrimitiveTypeKind.U64: + case PrimitiveTypeKind.I32: + case PrimitiveTypeKind.U32: + case PrimitiveTypeKind.I16: + case PrimitiveTypeKind.U16: + case PrimitiveTypeKind.I8: + case PrimitiveTypeKind.U8: + return input; + case PrimitiveTypeKind.F64: + _builder.AppendLine($" %{outputLabel} =d sltof {input}"); + return $"%{outputLabel}"; + case PrimitiveTypeKind.F32: + _builder.AppendLine($" %{outputLabel} =s sltof {input}"); + return $"%{outputLabel}"; + case PrimitiveTypeKind.String: + default: + throw new ArgumentOutOfRangeException(); + } + case PrimitiveTypeKind.I32: + switch (primitiveOutputType.Kind) + { + case PrimitiveTypeKind.I64: + case PrimitiveTypeKind.U64: + _builder.AppendLine($" %{outputLabel} =l extsw {input}"); + return $"%{outputLabel}"; + case PrimitiveTypeKind.I32: + case PrimitiveTypeKind.U32: + case PrimitiveTypeKind.I16: + case PrimitiveTypeKind.U16: + case PrimitiveTypeKind.I8: + case PrimitiveTypeKind.U8: + return input; + case PrimitiveTypeKind.F64: + var extLabel = GenName("ext"); + _builder.AppendLine($" %{extLabel} =l extsw {input}"); + _builder.AppendLine($" %{outputLabel} =d sltof {extLabel}"); + return $"%{outputLabel}"; + case PrimitiveTypeKind.F32: + _builder.AppendLine($" %{outputLabel} =s swtof {input}"); + return $"%{outputLabel}"; + case PrimitiveTypeKind.String: + default: + throw new ArgumentOutOfRangeException(); + } + case PrimitiveTypeKind.I16: + switch (primitiveOutputType.Kind) + { + case PrimitiveTypeKind.I64: + case PrimitiveTypeKind.U64: + _builder.AppendLine($" %{outputLabel} =l extsh {input}"); + return $"%{outputLabel}"; + case PrimitiveTypeKind.I32: + case PrimitiveTypeKind.U32: + _builder.AppendLine($" %{outputLabel} =w extsh {input}"); + return $"%{outputLabel}"; + case PrimitiveTypeKind.I16: + case PrimitiveTypeKind.U16: + case PrimitiveTypeKind.I8: + case PrimitiveTypeKind.U8: + return input; + case PrimitiveTypeKind.F64: + { + var extLabel = GenName("ext"); + _builder.AppendLine($" %{extLabel} =l extsh {input}"); + _builder.AppendLine($" %{outputLabel} =d sltof {extLabel}"); + return $"%{outputLabel}"; + } + case PrimitiveTypeKind.F32: + { + var extLabel = GenName("ext"); + _builder.AppendLine($" %{extLabel} =w extsh {input}"); + _builder.AppendLine($" %{outputLabel} =s swtof {extLabel}"); + return $"%{outputLabel}"; + } + case PrimitiveTypeKind.String: + default: + throw new ArgumentOutOfRangeException(); + } + case PrimitiveTypeKind.I8: + switch (primitiveOutputType.Kind) + { + case PrimitiveTypeKind.I64: + case PrimitiveTypeKind.U64: + _builder.AppendLine($" %{outputLabel} =l extsb {input}"); + return $"%{outputLabel}"; + case PrimitiveTypeKind.I32: + case PrimitiveTypeKind.U32: + case PrimitiveTypeKind.I16: + case PrimitiveTypeKind.U16: + _builder.AppendLine($" %{outputLabel} =w extsb {input}"); + return $"%{outputLabel}"; + case PrimitiveTypeKind.I8: + case PrimitiveTypeKind.U8: + return input; + case PrimitiveTypeKind.F64: + { + var extLabel = GenName("ext"); + _builder.AppendLine($" %{extLabel} =l extsb {input}"); + _builder.AppendLine($" %{outputLabel} =d sltof {extLabel}"); + return $"%{outputLabel}"; + } + case PrimitiveTypeKind.F32: + { + var extLabel = GenName("ext"); + _builder.AppendLine($" %{extLabel} =w extsb {input}"); + _builder.AppendLine($" %{outputLabel} =s swtof {extLabel}"); + return $"%{outputLabel}"; + } + case PrimitiveTypeKind.String: + default: + throw new ArgumentOutOfRangeException(); + } + case PrimitiveTypeKind.U64: + switch (primitiveOutputType.Kind) + { + case PrimitiveTypeKind.I64: + case PrimitiveTypeKind.U64: + case PrimitiveTypeKind.I32: + case PrimitiveTypeKind.U32: + case PrimitiveTypeKind.I16: + case PrimitiveTypeKind.U16: + case PrimitiveTypeKind.I8: + case PrimitiveTypeKind.U8: + return input; + case PrimitiveTypeKind.F64: + _builder.AppendLine($" %{outputLabel} =d ultof {input}"); + return $"%{outputLabel}"; + case PrimitiveTypeKind.F32: + _builder.AppendLine($" %{outputLabel} =s ultof {input}"); + return $"%{outputLabel}"; + case PrimitiveTypeKind.String: + default: + throw new ArgumentOutOfRangeException(); + } + case PrimitiveTypeKind.U32: + switch (primitiveOutputType.Kind) + { + case PrimitiveTypeKind.I64: + case PrimitiveTypeKind.U64: + _builder.AppendLine($" %{outputLabel} =l extuw {input}"); + return $"%{outputLabel}"; + case PrimitiveTypeKind.I32: + case PrimitiveTypeKind.U32: + case PrimitiveTypeKind.I16: + case PrimitiveTypeKind.U16: + case PrimitiveTypeKind.I8: + case PrimitiveTypeKind.U8: + return input; + case PrimitiveTypeKind.F64: + var extLabel = GenName("ext"); + _builder.AppendLine($" %{extLabel} =l extuw {input}"); + _builder.AppendLine($" %{outputLabel} =d ultof {extLabel}"); + return $"%{outputLabel}"; + case PrimitiveTypeKind.F32: + _builder.AppendLine($" %{outputLabel} =s uwtof {input}"); + return $"%{outputLabel}"; + case PrimitiveTypeKind.String: + default: + throw new ArgumentOutOfRangeException(); + } + case PrimitiveTypeKind.U16: + switch (primitiveOutputType.Kind) + { + case PrimitiveTypeKind.I64: + case PrimitiveTypeKind.U64: + _builder.AppendLine($" %{outputLabel} =l extuh {input}"); + return $"%{outputLabel}"; + case PrimitiveTypeKind.I32: + case PrimitiveTypeKind.U32: + _builder.AppendLine($" %{outputLabel} =w extuh {input}"); + return $"%{outputLabel}"; + case PrimitiveTypeKind.I16: + case PrimitiveTypeKind.U16: + case PrimitiveTypeKind.I8: + case PrimitiveTypeKind.U8: + return input; + case PrimitiveTypeKind.F64: + { + var extLabel = GenName("ext"); + _builder.AppendLine($" %{extLabel} =l extuh {input}"); + _builder.AppendLine($" %{outputLabel} =d ultof {extLabel}"); + return $"%{outputLabel}"; + } + case PrimitiveTypeKind.F32: + { + var extLabel = GenName("ext"); + _builder.AppendLine($" %{extLabel} =w extuh {input}"); + _builder.AppendLine($" %{outputLabel} =s uwtof {extLabel}"); + return $"%{outputLabel}"; + } + case PrimitiveTypeKind.String: + default: + throw new ArgumentOutOfRangeException(); + } + case PrimitiveTypeKind.U8: + switch (primitiveOutputType.Kind) + { + case PrimitiveTypeKind.I64: + case PrimitiveTypeKind.U64: + _builder.AppendLine($" %{outputLabel} =l extub {input}"); + return $"%{outputLabel}"; + case PrimitiveTypeKind.I32: + case PrimitiveTypeKind.U32: + case PrimitiveTypeKind.I16: + case PrimitiveTypeKind.U16: + _builder.AppendLine($" %{outputLabel} =w extub {input}"); + return $"%{outputLabel}"; + case PrimitiveTypeKind.I8: + case PrimitiveTypeKind.U8: + return input; + case PrimitiveTypeKind.F64: + { + var extLabel = GenName("ext"); + _builder.AppendLine($" %{extLabel} =l extub {input}"); + _builder.AppendLine($" %{outputLabel} =d ultof {extLabel}"); + return $"%{outputLabel}"; + } + case PrimitiveTypeKind.F32: + { + var extLabel = GenName("ext"); + _builder.AppendLine($" %{extLabel} =w extub {input}"); + _builder.AppendLine($" %{outputLabel} =s uwtof {extLabel}"); + return $"%{outputLabel}"; + } + case PrimitiveTypeKind.String: + default: + throw new ArgumentOutOfRangeException(); + } + default: + throw new NotSupportedException($"Casting from {primitiveInputType.Kind} to {primitiveOutputType.Kind} is not supported"); + } } private string GenerateStructInitializer(StructInitializerNode structInitializer) @@ -816,18 +1089,9 @@ public class Generator private string GenerateExpressionFuncCall(FuncCallExpressionNode funcCall) { - var results = new List<(string, NubType)>(); - foreach (var parameter in funcCall.FuncCall.Parameters) - { - results.Add((GenerateExpression(parameter), parameter.Type)); - } - - var parameters = results.Select(p => $"{SQT(p.Item2)} {p.Item1}"); - - var output = GenName(); - _builder.AppendLine($" %{output} ={SQT(funcCall.Type)} call ${funcCall.FuncCall.Name}({string.Join(", ", parameters)})"); - - return $"%{output}"; + var outputLabel = GenName(); + _builder.AppendLine($" %{outputLabel} ={SQT(funcCall.Type)} {GenerateFuncCall(funcCall.FuncCall)}"); + return $"%{outputLabel}"; } private string GenName(string prefix = "v") diff --git a/src/compiler/Nub.Lang/Nub.Lang.csproj b/src/compiler/Nub.Lang/Nub.Lang.csproj index 865633d..ee51912 100644 --- a/src/compiler/Nub.Lang/Nub.Lang.csproj +++ b/src/compiler/Nub.Lang/Nub.Lang.csproj @@ -6,6 +6,7 @@ net9.0 enable enable + true