diff options
| author | Michael Williamson <mike@zwobble.org> | 2023-06-18 00:09:38 +0100 |
|---|---|---|
| committer | Michael Williamson <mike@zwobble.org> | 2023-06-18 00:09:38 +0100 |
| commit | 0272455c8bb06d5c63220172b2888510aeb7f40b (patch) | |
| tree | 2ffd2ae9e64bd590152a7fc65e554664750ea591 /src/main/java | |
| parent | 7aebd6993b58a0fcb5ee716e835812cfd817c347 (diff) | |
Hack together working HelloWorld compilation
Diffstat (limited to 'src/main/java')
5 files changed, 188 insertions, 24 deletions
diff --git a/src/main/java/org/shedlang/compiler/backends/llvm/LlvmBackend.java b/src/main/java/org/shedlang/compiler/backends/llvm/LlvmBackend.java index 2c854299..c2cf941d 100644 --- a/src/main/java/org/shedlang/compiler/backends/llvm/LlvmBackend.java +++ b/src/main/java/org/shedlang/compiler/backends/llvm/LlvmBackend.java @@ -2,6 +2,7 @@ package org.shedlang.compiler.backends.llvm; import org.shedlang.compiler.backends.Backend; import org.shedlang.compiler.backends.llvm.ir.LlvmIrSerializer; +import org.shedlang.compiler.backends.llvm.ir.ast.LlvmModule; import org.shedlang.compiler.config.ProjectConfig; import org.shedlang.compiler.stackir.instructions.Instruction; import org.shedlang.compiler.typechecker.TypeInfo; @@ -10,6 +11,8 @@ import org.shedlang.compiler.types.NamespaceName; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -20,6 +23,7 @@ public class LlvmBackend implements Backend { Map<NamespaceName, List<Instruction>> namespaces, TypeInfo typeInfo ) throws IOException { + var objectFilePaths = new ArrayList<Path>(); for (var namespace : namespaces.entrySet()) { var namespaceName = namespace.getKey(); var llvmModule = LlvmCompiler.compileNamespace( @@ -28,25 +32,59 @@ public class LlvmBackend implements Backend { typeInfo ); - // TODO: write directly to file - var builder = new StringBuilder(); - LlvmIrSerializer.serializeModule(llvmModule, builder); - - var llvmModulePath = config.targetDir().resolve(String.join("_", namespaceName.parts()) + ".ll"); - var objectPath = config.targetDir().resolve(String.join("_", namespaceName.parts()) + ".o"); - Files.createDirectories(llvmModulePath.getParent()); - Files.writeString( - llvmModulePath, - builder.toString(), - StandardCharsets.UTF_8 - ); - run(List.of( - "llc-16", llvmModulePath.toString(), - "-filetype", "obj", - "-relocation-model", "pic", - "-o", objectPath.toString() - )); + var objectPath = compileLlvmModule(llvmModule, config.targetDir().resolve("namespaces"), String.join("_", namespaceName.parts())); + objectFilePaths.add(objectPath); + } + + var mainModule = LlvmCompiler.compileMain(config.main(), typeInfo); + var objectPath = compileLlvmModule(mainModule, config.targetDir(), "main"); + objectFilePaths.add(objectPath); + + var gccArgs = new ArrayList<String>(); + gccArgs.add("gcc"); + + gccArgs.add("-o"); + gccArgs.add(config.targetDir().resolve("main").toString()); + + for (var objectFilePath : objectFilePaths) { + gccArgs.add(objectFilePath.toString()); } + + // TODO: don't assume we're in the project root + gccArgs.add("runtime/build/libshed.a"); + + run(gccArgs); + } + + private static Path compileLlvmModule( + LlvmModule llvmModule, + Path workingDirectory, + String name + ) throws IOException { + // TODO: write directly to file + var builder = new StringBuilder(); + LlvmIrSerializer.serializeModule(llvmModule, builder); + + var llvmModulePath = workingDirectory.resolve(name + ".ll"); + var objectPath = workingDirectory.resolve(name + ".o"); + Files.createDirectories(llvmModulePath.getParent()); + Files.writeString( + llvmModulePath, + builder.toString(), + StandardCharsets.UTF_8 + ); + runLlvmCompiler(llvmModulePath, objectPath); + + return objectPath; + } + + private static void runLlvmCompiler(Path llvmModulePath, Path objectPath) throws IOException { + run(List.of( + "llc-16", llvmModulePath.toString(), + "-filetype", "obj", + "-relocation-model", "pic", + "-o", objectPath.toString() + )); } private static void run(List<String> args) throws IOException { diff --git a/src/main/java/org/shedlang/compiler/backends/llvm/LlvmCompiler.java b/src/main/java/org/shedlang/compiler/backends/llvm/LlvmCompiler.java index f5d677f4..b3100c65 100644 --- a/src/main/java/org/shedlang/compiler/backends/llvm/LlvmCompiler.java +++ b/src/main/java/org/shedlang/compiler/backends/llvm/LlvmCompiler.java @@ -2,8 +2,13 @@ package org.shedlang.compiler.backends.llvm; import org.shedlang.compiler.ast.typed.FreeVariables; import org.shedlang.compiler.backends.llvm.ir.ast.*; -import org.shedlang.compiler.backends.llvm.ir.ast.instructions.*; -import org.shedlang.compiler.backends.llvm.ir.ast.operands.*; +import org.shedlang.compiler.backends.llvm.ir.ast.instructions.LlvmCall; +import org.shedlang.compiler.backends.llvm.ir.ast.instructions.LlvmReturn; +import org.shedlang.compiler.backends.llvm.ir.ast.instructions.LlvmReturnVoid; +import org.shedlang.compiler.backends.llvm.ir.ast.operands.LlvmOperand; +import org.shedlang.compiler.backends.llvm.ir.ast.operands.LlvmOperandInt; +import org.shedlang.compiler.backends.llvm.ir.ast.operands.LlvmOperandPtrToInt; +import org.shedlang.compiler.backends.llvm.ir.ast.operands.LlvmVariableGlobal; import org.shedlang.compiler.backends.llvm.ir.ast.types.LlvmTypes; import org.shedlang.compiler.stackir.instructions.*; import org.shedlang.compiler.typechecker.TypeInfo; @@ -14,6 +19,60 @@ import java.util.*; import static org.shedlang.compiler.util.Lists.reversed; public class LlvmCompiler { + public static LlvmModule compileMain(NamespaceName main, TypeInfo typeInfo) { + var context = LlvmCompilerContext.fromTypeInfo(typeInfo); + + // TODO: remove duplication of definition/declaration + context = context.addTopLevelEntity(new LlvmFunctionDeclaration( + "shed__namespaceInit__" + String.join("_", main.parts()), + LlvmCompilerTypes.VALUE_TYPE, + List.of() + )); + + var mainContext = context.enterFunction(); + + var namespaceResult = mainContext.generateVariableLocal( + LlvmCompilerLocalVariableSpace.NAMESPACE, + String.join("_", main.parts()) + ); + var namespace = namespaceResult.value(); + mainContext = namespaceResult.context(); + + mainContext = mainContext.addInstruction(new LlvmCall( + namespace, + LlvmCompilerTypes.VALUE_TYPE, + new LlvmVariableGlobal("shed__namespaceInit__" + String.join("_", main.parts())), + List.of() + )); + + var fieldResult = LlvmCompilerNamespaces.fieldLoad( + main, + namespace, + // TODO: check there is a main function + "main", + mainContext + ); + var field = fieldResult.value(); + mainContext = fieldResult.context(); + + mainContext = LlvmCompilerClosures.call(field, mainContext, List.of()); + + mainContext = mainContext.addTerminatorInstruction(new LlvmReturnVoid()); + + var mainBasicBlocksResult = context.exitFunction(mainContext); + var mainBasicBlocks = mainBasicBlocksResult.value(); + context = mainBasicBlocksResult.context(); + + context = context.addTopLevelEntity(new LlvmFunctionDefinition( + "main", + LlvmTypes.VOID, + List.of(), + mainBasicBlocks + )); + + return new LlvmModule(context.topLevelEntities().stream().toList()); + } + public static LlvmModule compileNamespace( NamespaceName namespaceName, List<Instruction> instructions, @@ -24,11 +83,18 @@ public class LlvmCompiler { context = compileInstruction(instruction, context); } - context = context.addTerminatorInstruction(new LlvmReturnVoid()); + context = context.addTerminatorInstruction(new LlvmReturn( + LlvmCompilerTypes.VALUE_TYPE, + new LlvmOperandPtrToInt( + LlvmCompilerNamespaces.typeNamespacePointer(typeInfo.namespaceTypeInfo(namespaceName)), + LlvmCompilerNamespaces.operandNamespaceValue(namespaceName), + LlvmCompilerTypes.VALUE_TYPE + ) + )); var basicBlocks = context.basicBlocks(); var namespaceInitFunction = new LlvmFunctionDefinition( "shed__namespaceInit__" + String.join("_", namespaceName.parts()), - LlvmTypes.VOID, + LlvmCompilerTypes.VALUE_TYPE, List.of(), basicBlocks ); diff --git a/src/main/java/org/shedlang/compiler/backends/llvm/LlvmCompilerLocalVariableSpace.java b/src/main/java/org/shedlang/compiler/backends/llvm/LlvmCompilerLocalVariableSpace.java index fd7736e3..70cd13bc 100644 --- a/src/main/java/org/shedlang/compiler/backends/llvm/LlvmCompilerLocalVariableSpace.java +++ b/src/main/java/org/shedlang/compiler/backends/llvm/LlvmCompilerLocalVariableSpace.java @@ -8,7 +8,10 @@ public enum LlvmCompilerLocalVariableSpace { CLOSURE_ENVIRONMENT_POINTER("closureEnvironmentPointer"), CLOSURE_FREE_VARIABLE_POINTER("closureFreeVariablePointer"), CLOSURE_FREE_VARIABLE("closureFreeVariable"), + FIELD("field"), FIELD_POINTER("fieldPointer"), + NAMESPACE("namespace"), + NAMESPACE_STRUCT_POINTER("namespaceStructPointer"), SIZE_PTR("sizePtr"), SIZE("size"), TEMPORARY("tmp"); diff --git a/src/main/java/org/shedlang/compiler/backends/llvm/LlvmCompilerNamespaces.java b/src/main/java/org/shedlang/compiler/backends/llvm/LlvmCompilerNamespaces.java index 5c0bbca5..8b4c7622 100644 --- a/src/main/java/org/shedlang/compiler/backends/llvm/LlvmCompilerNamespaces.java +++ b/src/main/java/org/shedlang/compiler/backends/llvm/LlvmCompilerNamespaces.java @@ -2,6 +2,8 @@ package org.shedlang.compiler.backends.llvm; import org.shedlang.compiler.backends.llvm.ir.ast.LlvmGlobalDefinition; import org.shedlang.compiler.backends.llvm.ir.ast.instructions.LlvmGetElementPtr; +import org.shedlang.compiler.backends.llvm.ir.ast.instructions.LlvmIntToPtr; +import org.shedlang.compiler.backends.llvm.ir.ast.instructions.LlvmLoad; import org.shedlang.compiler.backends.llvm.ir.ast.instructions.LlvmStore; import org.shedlang.compiler.backends.llvm.ir.ast.operands.*; import org.shedlang.compiler.backends.llvm.ir.ast.types.LlvmType; @@ -88,4 +90,54 @@ public class LlvmCompilerNamespaces { fieldPointer )); } + + public static LlvmCompilerResult<LlvmVariableLocal> fieldLoad( + NamespaceName namespaceName, + LlvmOperand namespace, + String fieldName, + LlvmCompilerContext context + ) { + var namespaceTypeInfo = context.typeInfo().namespaceTypeInfo(namespaceName); + + var namespaceStructPointerResult = context.generateVariableLocal( + LlvmCompilerLocalVariableSpace.NAMESPACE_STRUCT_POINTER, + String.join("_", namespaceName.parts()) + ); + var namespaceStructPointer = namespaceStructPointerResult.value(); + context = namespaceStructPointerResult.context(); + + context = context.addInstruction(new LlvmIntToPtr( + namespaceStructPointer, + LlvmCompilerTypes.VALUE_TYPE, + namespace + )); + + var fieldPointerResult = context.generateVariableLocal( + LlvmCompilerLocalVariableSpace.FIELD_POINTER, + fieldName + ); + var fieldPointer = fieldPointerResult.value(); + context = fieldPointerResult.context(); + + var fieldResult = context.generateVariableLocal( + LlvmCompilerLocalVariableSpace.FIELD, + fieldName + ); + var field = fieldResult.value(); + context = fieldResult.context(); + + return context.addInstruction(new LlvmGetElementPtr( + fieldPointer, + typeNamespacePointer(namespaceTypeInfo), + namespaceStructPointer, + List.of( + LlvmTypedOperand.arrayIndex(0), + LlvmTypedOperand.structureIndex(namespaceTypeInfo.fieldIndex(fieldName)) + ) + )).addInstruction(new LlvmLoad( + field, + LlvmCompilerTypes.VALUE_TYPE, + fieldPointer + )).toResult(field); + } } diff --git a/src/main/java/org/shedlang/compiler/typechecker/TypeInfo.java b/src/main/java/org/shedlang/compiler/typechecker/TypeInfo.java index 5cb5a5b0..f7c381d9 100644 --- a/src/main/java/org/shedlang/compiler/typechecker/TypeInfo.java +++ b/src/main/java/org/shedlang/compiler/typechecker/TypeInfo.java @@ -17,7 +17,12 @@ public class TypeInfo { } public NamespaceTypeInfo namespaceTypeInfo(NamespaceName namespaceName) { - // TODO: handle missing key - return namespaceTypeInfo.get(namespaceName); + // TODO: throw better error + var typeInfo = namespaceTypeInfo.get(namespaceName); + if (typeInfo == null) { + throw new RuntimeException("No type info for: " + namespaceName); + } else { + return typeInfo; + } } } |
