aboutsummaryrefslogtreecommitdiff
path: root/src/main/java
diff options
context:
space:
mode:
authorMichael Williamson <mike@zwobble.org>2023-06-18 00:09:38 +0100
committerMichael Williamson <mike@zwobble.org>2023-06-18 00:09:38 +0100
commit0272455c8bb06d5c63220172b2888510aeb7f40b (patch)
tree2ffd2ae9e64bd590152a7fc65e554664750ea591 /src/main/java
parent7aebd6993b58a0fcb5ee716e835812cfd817c347 (diff)
Hack together working HelloWorld compilation
Diffstat (limited to 'src/main/java')
-rw-r--r--src/main/java/org/shedlang/compiler/backends/llvm/LlvmBackend.java74
-rw-r--r--src/main/java/org/shedlang/compiler/backends/llvm/LlvmCompiler.java74
-rw-r--r--src/main/java/org/shedlang/compiler/backends/llvm/LlvmCompilerLocalVariableSpace.java3
-rw-r--r--src/main/java/org/shedlang/compiler/backends/llvm/LlvmCompilerNamespaces.java52
-rw-r--r--src/main/java/org/shedlang/compiler/typechecker/TypeInfo.java9
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;
+ }
}
}