diff options
| author | Michael Williamson <mike@zwobble.org> | 2023-06-17 10:49:53 +0100 |
|---|---|---|
| committer | Michael Williamson <mike@zwobble.org> | 2023-06-17 10:49:53 +0100 |
| commit | 43fd7ec22f5f86ab79a5aa70c8dd460d84ad4726 (patch) | |
| tree | 2aeb384c88372b8b6f37307b7471b85031134e92 /src/main/java | |
| parent | c70a0a1ecbd562f8e13c6c96b28bcd15d3cd2b62 (diff) | |
Hack together compilation of LLVM modules to object files
Diffstat (limited to 'src/main/java')
5 files changed, 113 insertions, 21 deletions
diff --git a/src/main/java/org/shedlang/compiler/ShedCompiler.java b/src/main/java/org/shedlang/compiler/ShedCompiler.java index 6f252776..ebf97bdc 100644 --- a/src/main/java/org/shedlang/compiler/ShedCompiler.java +++ b/src/main/java/org/shedlang/compiler/ShedCompiler.java @@ -36,6 +36,18 @@ public class ShedCompiler { var namespaces = new LinkedHashMap<NamespaceName, List<Instruction>>(); + var typeCheckerContext = TypeCheckerContext.EMPTY + .enter(P.map( + Map.entry("Io", Types.effectType(Effects.IO)), + Map.entry("Unit", Types.metaType(Types.UNIT)), + + Map.entry("print", new FunctionType( + List.of(Types.STRING), + List.of(), + Types.UNIT + )) + )); + for (var sourceFilePath : sourceFilePaths) { var namespaceNameParts = StreamSupport.stream(sourceRoot.relativize(sourceFilePath).spliterator(), false) .map(element -> { @@ -51,25 +63,14 @@ public class ShedCompiler { var tokens = tokenise(source); var untypedNode = Parser.parseNamespace(tokens, namespaceName); + var typeCheckNamespaceResult = TypeChecker.typeCheckNamespace(untypedNode, typeCheckerContext); + typeCheckerContext = typeCheckNamespaceResult.context(); - var context = TypeCheckerContext.EMPTY - .enter(P.map( - Map.entry("Io", Types.effectType(Effects.IO)), - Map.entry("Unit", Types.metaType(Types.UNIT)), - - Map.entry("print", new FunctionType( - List.of(Types.STRING), - List.of(), - Types.UNIT - )) - )); - var typedNode = TypeChecker.typeCheckNamespace(untypedNode, context); - - var instructions = StackCompiler.compileNamespace(typedNode.value()); + var instructions = StackCompiler.compileNamespace(typeCheckNamespaceResult.value()); namespaces.put(namespaceName, instructions); } - backend.compile(config, namespaces); + backend.compile(config, namespaces, typeCheckerContext.toTypeInfo()); } private List<Path> collectSourceFilePaths(Path sourceRoot) throws IOException { diff --git a/src/main/java/org/shedlang/compiler/backends/Backend.java b/src/main/java/org/shedlang/compiler/backends/Backend.java index ef0e31ca..aaf73bf9 100644 --- a/src/main/java/org/shedlang/compiler/backends/Backend.java +++ b/src/main/java/org/shedlang/compiler/backends/Backend.java @@ -2,11 +2,17 @@ package org.shedlang.compiler.backends; import org.shedlang.compiler.config.ProjectConfig; import org.shedlang.compiler.stackir.instructions.Instruction; +import org.shedlang.compiler.typechecker.TypeInfo; import org.shedlang.compiler.types.NamespaceName; +import java.io.IOException; import java.util.List; import java.util.Map; public interface Backend { - void compile(ProjectConfig config, Map<NamespaceName, List<Instruction>> namespaces); + void compile( + ProjectConfig config, + Map<NamespaceName, List<Instruction>> namespaces, + TypeInfo typeInfo + ) throws IOException; } diff --git a/src/main/java/org/shedlang/compiler/backends/GenerateInstructionsBackend.java b/src/main/java/org/shedlang/compiler/backends/GenerateInstructionsBackend.java index bd7d5451..ed980e77 100644 --- a/src/main/java/org/shedlang/compiler/backends/GenerateInstructionsBackend.java +++ b/src/main/java/org/shedlang/compiler/backends/GenerateInstructionsBackend.java @@ -3,13 +3,18 @@ package org.shedlang.compiler.backends; import org.shedlang.compiler.config.ProjectConfig; import org.shedlang.compiler.stackir.InstructionSerializer; import org.shedlang.compiler.stackir.instructions.Instruction; +import org.shedlang.compiler.typechecker.TypeInfo; import org.shedlang.compiler.types.NamespaceName; import java.util.List; import java.util.Map; public class GenerateInstructionsBackend implements Backend { - public void compile(ProjectConfig config, Map<NamespaceName, List<Instruction>> namespaces) { + public void compile( + ProjectConfig config, + Map<NamespaceName, List<Instruction>> namespaces, + TypeInfo typeInfo + ) { System.out.println("main: " + config.main()); for (var namespaceEntry : namespaces.entrySet()) { 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 4abc46e5..2ee2b710 100644 --- a/src/main/java/org/shedlang/compiler/backends/llvm/LlvmBackend.java +++ b/src/main/java/org/shedlang/compiler/backends/llvm/LlvmBackend.java @@ -1,16 +1,74 @@ package org.shedlang.compiler.backends.llvm; import org.shedlang.compiler.backends.Backend; +import org.shedlang.compiler.backends.llvm.ir.LlvmIrSerializer; import org.shedlang.compiler.config.ProjectConfig; import org.shedlang.compiler.stackir.instructions.Instruction; +import org.shedlang.compiler.typechecker.TypeInfo; import org.shedlang.compiler.types.NamespaceName; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; import java.util.List; import java.util.Map; public class LlvmBackend implements Backend { @Override - public void compile(ProjectConfig config, Map<NamespaceName, List<Instruction>> namespaces) { - throw new UnsupportedOperationException("TODO"); + public void compile( + ProjectConfig config, + Map<NamespaceName, List<Instruction>> namespaces, + TypeInfo typeInfo + ) throws IOException { + for (var namespace : namespaces.entrySet()) { + var llvmModule = LlvmCompiler.compileNamespace( + namespace.getKey(), + namespace.getValue(), + typeInfo + ); + + // TODO: write directly to file + var builder = new StringBuilder(); + LlvmIrSerializer.serializeModule(llvmModule, builder); + var temporaryDirectory = Files.createTempDirectory("shed-"); + try { + // TODO: proper name + var llvmModulePath = temporaryDirectory.resolve("module.ll"); + var objectPath = temporaryDirectory.resolve("module.o"); + Files.writeString( + llvmModulePath, + builder.toString(), + StandardCharsets.UTF_8 + ); + run(List.of( + "llc", llvmModulePath.toString(), + "-filetype", "obj", + "-relocation-model", "pic", + "-o", objectPath.toString() + )); + } finally { + // TODO: delete + } + } + } + + private static void run(List<String> args) throws IOException { + var process = new ProcessBuilder(args) + .inheritIO() + .start(); + + while (true) { + try { + var exitCode = process.waitFor(); + if (exitCode != 0) { + // TODO: better error code + throw new RuntimeException("exit code: " + exitCode); + } else { + return; + } + } catch (InterruptedException exception) { + + } + } } } 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 694f3ff9..2ae8b649 100644 --- a/src/main/java/org/shedlang/compiler/backends/llvm/LlvmCompiler.java +++ b/src/main/java/org/shedlang/compiler/backends/llvm/LlvmCompiler.java @@ -1,6 +1,7 @@ package org.shedlang.compiler.backends.llvm; import org.shedlang.compiler.backends.llvm.ir.ast.LlvmFunctionDefinition; +import org.shedlang.compiler.backends.llvm.ir.ast.LlvmModule; import org.shedlang.compiler.backends.llvm.ir.ast.LlvmParam; import org.shedlang.compiler.backends.llvm.ir.ast.instructions.LlvmCall; import org.shedlang.compiler.backends.llvm.ir.ast.instructions.LlvmGetElementPtr; @@ -9,6 +10,7 @@ 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.LlvmTypes; import org.shedlang.compiler.stackir.instructions.*; +import org.shedlang.compiler.typechecker.TypeInfo; import org.shedlang.compiler.types.NamespaceName; import java.util.*; @@ -16,8 +18,28 @@ import java.util.*; import static org.shedlang.compiler.util.Lists.reversed; public class LlvmCompiler { - public static void compileNamespace(NamespaceName namespaceName, List<Instruction> instructions) { - + public static LlvmModule compileNamespace( + NamespaceName namespaceName, + List<Instruction> instructions, + TypeInfo typeInfo + ) { + var context = LlvmCompilerContext.fromTypeInfo(typeInfo); + for (var instruction : instructions) { + context = compileInstruction(instruction, context); + } + + var basicBlocks = context.basicBlocks(); + var namespaceInitFunction = new LlvmFunctionDefinition( + "shed__namespaceInit__" + String.join("_", namespaceName.parts()), + LlvmTypes.VOID, + List.of(), + basicBlocks + ); + + var topLevelEntities = context.addTopLevelEntity(namespaceInitFunction) + .topLevelEntities().stream().toList(); + + return new LlvmModule(topLevelEntities); } public static LlvmCompilerContext compileInstruction(Instruction instruction, LlvmCompilerContext context) { |
