aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMichael Williamson <mike@zwobble.org>2023-06-16 22:50:45 +0100
committerMichael Williamson <mike@zwobble.org>2023-06-16 22:50:45 +0100
commitdbb847a2e9524e1a6479c13ea2379dfa453bb32b (patch)
tree1d589b67275a9a4948dc6c1bfb0e455b93972056 /src
parentfa21920d943f199609712461cb700418d6d4ead0 (diff)
Generate top level entity for minimal function
Diffstat (limited to 'src')
-rw-r--r--src/main/java/org/shedlang/compiler/backends/llvm/LlvmCompiler.java38
-rw-r--r--src/main/java/org/shedlang/compiler/backends/llvm/LlvmCompilerContext.java32
-rw-r--r--src/main/java/org/shedlang/compiler/backends/llvm/LlvmCompilerTopLevelEntitySpace.java1
-rw-r--r--src/main/java/org/shedlang/compiler/backends/llvm/ir/ast/LlvmTopLevelEntity.java1
-rw-r--r--src/test/java/org/shedlang/compiler/backends/llvm/LlvmCompilerDefineFunctionTests.java63
-rw-r--r--src/test/java/org/shedlang/compiler/backends/llvm/ir/ast/LlvmIrMatchers.java32
6 files changed, 162 insertions, 5 deletions
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 7fc14092..2ad82eef 100644
--- a/src/main/java/org/shedlang/compiler/backends/llvm/LlvmCompiler.java
+++ b/src/main/java/org/shedlang/compiler/backends/llvm/LlvmCompiler.java
@@ -1,5 +1,9 @@
package org.shedlang.compiler.backends.llvm;
+import org.shedlang.compiler.backends.llvm.ir.ast.LlvmBasicBlock;
+import org.shedlang.compiler.backends.llvm.ir.ast.LlvmFunctionDefinition;
+import org.shedlang.compiler.backends.llvm.ir.ast.LlvmParam;
+import org.shedlang.compiler.backends.llvm.ir.ast.instructions.LlvmReturn;
import org.shedlang.compiler.backends.llvm.ir.ast.operands.LlvmOperand;
import org.shedlang.compiler.backends.llvm.ir.ast.operands.LlvmOperandInt;
import org.shedlang.compiler.stackir.instructions.*;
@@ -49,8 +53,38 @@ public class LlvmCompiler {
args
);
}
- case DefineFunctionInstruction defineFunctionInstruction -> {
- throw new UnsupportedOperationException("TODO");
+ case DefineFunctionInstruction defineFunction -> {
+ var topLevelEntityName = context.generateTopLevelEntityName(
+ LlvmCompilerTopLevelEntitySpace.FUNCTION,
+ defineFunction.name()
+ );
+
+ var functionContext = context.enterFunction();
+ for (var bodyInstruction : defineFunction.body()) {
+ functionContext = compileInstruction(bodyInstruction, functionContext);
+ }
+ // TODO: rejoin function context with context
+ // TODO: assert stack has exactly one element
+ var returnValue = functionContext.stack().get(0);
+
+ yield context.addTopLevelEntity(new LlvmFunctionDefinition(
+ topLevelEntityName,
+ LlvmCompilerTypes.VALUE_TYPE,
+ List.of(
+ new LlvmParam(
+ LlvmCompilerClosures.typeClosureEnvironmentPointer(),
+ // TODO: allocate name properly
+ "shed__env__0"
+ )
+ ),
+ List.of(
+ new LlvmBasicBlock(
+ Optional.empty(),
+ List.of(),
+ new LlvmReturn(LlvmCompilerTypes.VALUE_TYPE, returnValue)
+ )
+ )
+ ));
}
case DiscardInstruction discardInstruction ->
context.pop().context();
diff --git a/src/main/java/org/shedlang/compiler/backends/llvm/LlvmCompilerContext.java b/src/main/java/org/shedlang/compiler/backends/llvm/LlvmCompilerContext.java
index e1925e24..d558f483 100644
--- a/src/main/java/org/shedlang/compiler/backends/llvm/LlvmCompilerContext.java
+++ b/src/main/java/org/shedlang/compiler/backends/llvm/LlvmCompilerContext.java
@@ -93,21 +93,36 @@ public record LlvmCompilerContext(
builder.unnamedAddr()
);
+ return addTopLevelEntity(globalDefinition).toResult(globalDefinition);
+ }
+
+ public LlvmCompilerContext addTopLevelEntity(LlvmTopLevelEntity topLevelEntity) {
return new LlvmCompilerContext(
typeInfo,
stack,
locals,
instructions,
- topLevelEntitiesByName.plus(globalDefinition.name(), globalDefinition),
+ topLevelEntitiesByName.plus(topLevelEntity.name(), topLevelEntity),
localVariableNames
- ).toResult(globalDefinition);
+ );
+ }
+
+ public String generateTopLevelEntityName(LlvmCompilerTopLevelEntitySpace space, String name) {
+ return generateTopLevelEntityName(space, Optional.of(name));
}
private String generateTopLevelEntityName(LlvmCompilerTopLevelEntitySpace space) {
+ return generateTopLevelEntityName(space, Optional.empty());
+ }
+
+ private String generateTopLevelEntityName(
+ LlvmCompilerTopLevelEntitySpace space,
+ Optional<String> name
+ ) {
return NameAllocator.generateName(
topLevelEntitiesByName::containsKey,
"shed__" + space,
- Optional.empty()
+ name
);
}
@@ -146,4 +161,15 @@ public record LlvmCompilerContext(
public <T> LlvmCompilerResult<T> toResult(T value) {
return new LlvmCompilerResult<>(value, this);
}
+
+ public LlvmCompilerContext enterFunction() {
+ return new LlvmCompilerContext(
+ typeInfo,
+ Empty.stack(),
+ Empty.map(),
+ Empty.vector(),
+ topLevelEntitiesByName,
+ NameAllocator.empty()
+ );
+ }
}
diff --git a/src/main/java/org/shedlang/compiler/backends/llvm/LlvmCompilerTopLevelEntitySpace.java b/src/main/java/org/shedlang/compiler/backends/llvm/LlvmCompilerTopLevelEntitySpace.java
index 7ca7a06b..87b0a60b 100644
--- a/src/main/java/org/shedlang/compiler/backends/llvm/LlvmCompilerTopLevelEntitySpace.java
+++ b/src/main/java/org/shedlang/compiler/backends/llvm/LlvmCompilerTopLevelEntitySpace.java
@@ -1,6 +1,7 @@
package org.shedlang.compiler.backends.llvm;
public enum LlvmCompilerTopLevelEntitySpace {
+ FUNCTION("fun"),
STRING("string");
private final String name;
diff --git a/src/main/java/org/shedlang/compiler/backends/llvm/ir/ast/LlvmTopLevelEntity.java b/src/main/java/org/shedlang/compiler/backends/llvm/ir/ast/LlvmTopLevelEntity.java
index 86b3efc3..b1cabfa0 100644
--- a/src/main/java/org/shedlang/compiler/backends/llvm/ir/ast/LlvmTopLevelEntity.java
+++ b/src/main/java/org/shedlang/compiler/backends/llvm/ir/ast/LlvmTopLevelEntity.java
@@ -1,4 +1,5 @@
package org.shedlang.compiler.backends.llvm.ir.ast;
public sealed interface LlvmTopLevelEntity permits LlvmFunctionDefinition, LlvmGlobalDefinition {
+ String name();
}
diff --git a/src/test/java/org/shedlang/compiler/backends/llvm/LlvmCompilerDefineFunctionTests.java b/src/test/java/org/shedlang/compiler/backends/llvm/LlvmCompilerDefineFunctionTests.java
new file mode 100644
index 00000000..1575c2ad
--- /dev/null
+++ b/src/test/java/org/shedlang/compiler/backends/llvm/LlvmCompilerDefineFunctionTests.java
@@ -0,0 +1,63 @@
+package org.shedlang.compiler.backends.llvm;
+
+import org.junit.jupiter.api.Test;
+import org.shedlang.compiler.backends.llvm.ir.ast.LlvmFunctionDefinition;
+import org.shedlang.compiler.backends.llvm.ir.ast.operands.LlvmOperand;
+import org.shedlang.compiler.sources.Sources;
+import org.shedlang.compiler.stackir.instructions.DefineFunctionInstruction;
+import org.shedlang.compiler.stackir.instructions.Instructions;
+import org.zwobble.precisely.Matcher;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import static org.shedlang.compiler.backends.llvm.ir.ast.LlvmIrMatchers.*;
+import static org.zwobble.precisely.AssertThat.assertThat;
+import static org.zwobble.precisely.Matchers.*;
+
+public class LlvmCompilerDefineFunctionTests {
+ @Test
+ public void canDefineMinimalFunction() {
+ var instruction = new DefineFunctionInstruction(
+ "f",
+ List.of(),
+ List.of(),
+ Set.of(),
+ List.of(
+ Instructions.pushUnit()
+ ),
+ Sources.NULL
+ );
+ var context = LlvmCompilerContext.EMPTY;
+
+ var result = LlvmCompiler.compileInstruction(instruction, context);
+
+ assertThat(result.topLevelEntities(), isSequence(
+ instanceOf(
+ LlvmFunctionDefinition.class,
+ has("name", x -> x.name(), equalTo("shed__fun__f__0")),
+ has("returnType", x -> x.returnType(), equalTo(LlvmCompilerTypes.VALUE_TYPE)),
+ has("params", x -> x.params(), isSequence(
+ isLlvmParam(LlvmCompilerClosures.typeClosureEnvironmentPointer(), "shed__env__0")
+ )),
+ has("body", x -> x.body(), isSequence(
+ isLlvmBasicBlock(
+ isSequence(),
+ isLlvmReturn(LlvmCompilerTypes.VALUE_TYPE, isLlvmOperandInt(0))
+ )
+ ))
+ )
+ ));
+ assertThat(result.instructions(), isSequence());
+ assertThat(result.stack(), isSequence());
+ assertThat(result.locals().entrySet(), isSequence());
+ }
+
+ private static Matcher<Map.Entry<String, LlvmOperand>> isLocal(String name, Matcher<LlvmOperand> operand) {
+ return allOf(
+ has("name", x -> x.getKey(), equalTo(name)),
+ has("operand", x -> x.getValue(), operand)
+ );
+ }
+}
diff --git a/src/test/java/org/shedlang/compiler/backends/llvm/ir/ast/LlvmIrMatchers.java b/src/test/java/org/shedlang/compiler/backends/llvm/ir/ast/LlvmIrMatchers.java
index 21755f6e..f80746e1 100644
--- a/src/test/java/org/shedlang/compiler/backends/llvm/ir/ast/LlvmIrMatchers.java
+++ b/src/test/java/org/shedlang/compiler/backends/llvm/ir/ast/LlvmIrMatchers.java
@@ -1,5 +1,8 @@
package org.shedlang.compiler.backends.llvm.ir.ast;
+import org.shedlang.compiler.backends.llvm.ir.ast.instructions.LlvmInstruction;
+import org.shedlang.compiler.backends.llvm.ir.ast.instructions.LlvmReturn;
+import org.shedlang.compiler.backends.llvm.ir.ast.instructions.LlvmTerminatorInstruction;
import org.shedlang.compiler.backends.llvm.ir.ast.operands.*;
import org.shedlang.compiler.backends.llvm.ir.ast.types.LlvmType;
import org.zwobble.precisely.Matcher;
@@ -10,6 +13,17 @@ public class LlvmIrMatchers {
private LlvmIrMatchers() {
}
+ public static Matcher<LlvmBasicBlock> isLlvmBasicBlock(
+ Matcher<Iterable<? extends LlvmInstruction>> instructions,
+ Matcher<LlvmTerminatorInstruction> terminator
+ ) {
+ return allOf(
+ has("label", x -> x.label(), isOptionalEmpty()),
+ has("instructions", x -> x.instructions(), instructions),
+ has("terminator", x -> x.terminator(), terminator)
+ );
+ }
+
public static Matcher<LlvmOperand> isLlvmOperandInt(long value) {
return instanceOf(
LlvmOperandInt.class,
@@ -30,6 +44,24 @@ public class LlvmIrMatchers {
);
}
+ public static Matcher<LlvmParam> isLlvmParam(LlvmType type, String name) {
+ return allOf(
+ has("type", x -> x.type(), equalTo(type)),
+ has("name", x -> x.name(), equalTo(name))
+ );
+ }
+
+ public static Matcher<LlvmTerminatorInstruction> isLlvmReturn(
+ LlvmType type,
+ Matcher<LlvmOperand> value
+ ) {
+ return instanceOf(
+ LlvmReturn.class,
+ has("type", x -> x.type(), equalTo(type)),
+ has("value", x -> x.value(), value)
+ );
+ }
+
public static Matcher<LlvmTypedOperand> isLlvmTypedOperand(LlvmType type, Matcher<LlvmOperand> operand) {
return allOf(
has("type", x -> x.type(), equalTo(type)),