From 36622755a943f0d7cf990963d6ac7749e42d5ce8 Mon Sep 17 00:00:00 2001 From: nub31 Date: Mon, 3 Nov 2025 19:54:41 +0100 Subject: [PATCH] ... --- compiler/NubLang/Generation/LlvmGenerator.cs | 92 ++++++++++++++++---- examples/playgroud/main.nub | 4 +- 2 files changed, 78 insertions(+), 18 deletions(-) diff --git a/compiler/NubLang/Generation/LlvmGenerator.cs b/compiler/NubLang/Generation/LlvmGenerator.cs index bfc971a..42d78bf 100644 --- a/compiler/NubLang/Generation/LlvmGenerator.cs +++ b/compiler/NubLang/Generation/LlvmGenerator.cs @@ -22,16 +22,26 @@ public class LlvmGenerator var writer = new IndentedTextWriter(); _module = topLevelNodes.OfType().First().NameToken.Value; - writer.WriteLine($"; Module {_module}"); - writer.WriteLine(); - writer.WriteLine("declare void @llvm.memcpy.p0.p0.i64(ptr, ptr, i64, i1)"); - writer.WriteLine(); + writer.WriteLine($$""" + ; Module {{_module}} + + target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128" + target triple = "x86_64-pc-linux-gnu" + + %nub.slice = type { i64, ptr } + %nub.string = type { i64, ptr } + + declare void @llvm.memcpy.p0.p0.i64(ptr, ptr, i64, i1) + + """); var declaredExternFunctions = new HashSet(); + writer.WriteLine("; == Function declarations =="); foreach (var module in repository.GetAll()) { + writer.WriteLine($"; ==== {module.Name} ===="); foreach (var prototype in module.FunctionPrototypes) { // note(nub31): If we are in the current module and the function has a body, we skip it to prevent duplicate definition @@ -45,22 +55,31 @@ public class LlvmGenerator continue; } - var parameters = prototype.Parameters.Select(x => $"{MapType(x.Type)} %{x.NameToken.Value}"); - var funcName = FuncName(module.Name, prototype.NameToken.Value, prototype.ExternSymbolToken?.Value); - writer.WriteLine($"declare {MapType(prototype.ReturnType)} @{funcName}({string.Join(", ", parameters)})"); - writer.WriteLine(); + writer.WriteLine($"declare {CreateFunctionPrototype(prototype, module.Name)}"); } } + writer.WriteLine(); + + writer.WriteLine("; == Struct declarations =="); + foreach (var module in repository.GetAll()) + { + writer.WriteLine($"; ==== {module.Name} ===="); + foreach (var structType in module.StructTypes) + { + var fieldTypes = structType.Fields.Select(x => MapType(x.Type)); + writer.WriteLine($"%{StructName(structType.Module, structType.Name)} = type {{ {string.Join(", ", fieldTypes)} }}"); + } + } + + writer.WriteLine(); + foreach (var structNode in topLevelNodes.OfType()) { - var types = structNode.Fields.Select(x => MapType(x.Type)); - writer.WriteLine($"%{StructName(structNode)} = type {{ {string.Join(", ", types)} }}"); - writer.WriteLine(); - _tmpIndex = 0; _labelIndex = 0; + writer.WriteLine("; == Struct constructors =="); writer.WriteLine($"define void @{StructName(structNode)}.new(ptr %self) {{"); using (writer.Indent()) { @@ -83,6 +102,7 @@ public class LlvmGenerator writer.WriteLine(); } + writer.WriteLine("; == Function definitions =="); foreach (var funcNode in topLevelNodes.OfType()) { if (funcNode.Body == null) continue; @@ -90,8 +110,7 @@ public class LlvmGenerator _tmpIndex = 0; _labelIndex = 0; - var parameters = funcNode.Prototype.Parameters.Select(x => $"{MapType(x.Type)} %{x.NameToken.Value}"); - writer.WriteLine($"define {MapType(funcNode.Prototype.ReturnType)} @{FuncName(_module, funcNode.Prototype.NameToken.Value, funcNode.Prototype.ExternSymbolToken?.Value)}({string.Join(", ", parameters)}) {{"); + writer.WriteLine($"define {CreateFunctionPrototype(funcNode.Prototype, _module)} {{"); using (writer.Indent()) { @@ -108,6 +127,7 @@ public class LlvmGenerator writer.WriteLine(); } + writer.WriteLine("; == String literals =="); foreach (var stringLiteral in _stringLiterals) { writer.WriteLine($"{stringLiteral.Name} = private unnamed_addr constant [{stringLiteral.Size} x i8] c\"{stringLiteral.Text}\\00\", align 1"); @@ -116,6 +136,46 @@ public class LlvmGenerator return writer.ToString(); } + private string CreateFunctionPrototype(FuncPrototypeNode prototypeNode, string module) + { + var parameterStrings = new List(); + + foreach (var parameter in prototypeNode.Parameters) + { + var llvmType = MapType(parameter.Type); + var name = parameter.NameToken.Value; + + if (parameter.Type is NubStructType) + { + var alignment = parameter.Type.GetAlignment(); + parameterStrings.Add($"{llvmType}* byval({llvmType}) align {alignment} %{name}"); + } + else + { + parameterStrings.Add($"{llvmType} %{name}"); + } + } + + var funcName = FuncName(module, prototypeNode.NameToken.Value, prototypeNode.ExternSymbolToken?.Value); + var returnType = MapType(prototypeNode.ReturnType); + + if (prototypeNode.ReturnType is NubStructType) + { + var alignment = prototypeNode.ReturnType.GetAlignment(); + var parameters = ""; + if (parameterStrings.Count != 0) + { + parameters = ", " + string.Join(", ", parameterStrings); + } + + return $"ccc void @{funcName}({returnType}* sret({returnType}) align {alignment}{parameters})"; + } + else + { + return $"ccc {returnType} @{funcName}({string.Join(", ", parameterStrings)})"; + } + } + private void EmitStatement(IndentedTextWriter writer, StatementNode statementNode) { switch (statementNode) @@ -860,11 +920,11 @@ public class LlvmGenerator if (funcCallNode.Type is NubVoidType) { - writer.WriteLine($"call {MapType(funcCallNode.Type)} {functionPtr}({string.Join(", ", parameterStrings)})"); + writer.WriteLine($"call ccc {MapType(funcCallNode.Type)} {functionPtr}({string.Join(", ", parameterStrings)})"); } else { - writer.WriteLine($"{result} = call {MapType(funcCallNode.Type)} {functionPtr}({string.Join(", ", parameterStrings)})"); + writer.WriteLine($"{result} = call ccc {MapType(funcCallNode.Type)} {functionPtr}({string.Join(", ", parameterStrings)})"); } return new Tmp(result, funcCallNode.Type, false); diff --git a/examples/playgroud/main.nub b/examples/playgroud/main.nub index 64b27eb..da133f4 100644 --- a/examples/playgroud/main.nub +++ b/examples/playgroud/main.nub @@ -15,7 +15,7 @@ extern "main" func main(argc: i64, argv: [?]^i8) puts(x) } -func test(arr: [?]i64) +func test(test: Test): Test { - + return test } \ No newline at end of file