aboutsummaryrefslogtreecommitdiff
path: root/src/main/java
diff options
context:
space:
mode:
authorMichael Williamson <mike@zwobble.org>2023-06-19 19:11:44 +0100
committerMichael Williamson <mike@zwobble.org>2023-06-19 19:11:44 +0100
commit4be0a1caf255fa3c1dd86dfc210671b7ae395ebe (patch)
treef063e319fd94da91edc00f96764f1129e5a60c8d /src/main/java
parentcdd6065a224cdc623eda83106d6d167504de4f67 (diff)
Write directly to file when serializing LLVM IR
Diffstat (limited to 'src/main/java')
-rw-r--r--src/main/java/org/shedlang/compiler/backends/llvm/LlvmBackend.java18
-rw-r--r--src/main/java/org/shedlang/compiler/backends/llvm/ir/LlvmIrSerializer.java308
-rw-r--r--src/main/java/org/shedlang/compiler/util/Iterables.java16
3 files changed, 176 insertions, 166 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 c1ff0c95..f26de6dd 100644
--- a/src/main/java/org/shedlang/compiler/backends/llvm/LlvmBackend.java
+++ b/src/main/java/org/shedlang/compiler/backends/llvm/LlvmBackend.java
@@ -9,6 +9,8 @@ import org.shedlang.compiler.stackir.instructions.Instruction;
import org.shedlang.compiler.typechecker.TypeInfo;
import org.shedlang.compiler.types.NamespaceName;
+import java.io.BufferedWriter;
+import java.io.FileWriter;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
@@ -63,18 +65,14 @@ public class LlvmBackend implements Backend {
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
- );
+ var fileWriter = new FileWriter(llvmModulePath.toFile(), StandardCharsets.UTF_8);
+ try (var writer = new BufferedWriter(fileWriter)) {
+ LlvmIrSerializer.serializeModule(llvmModule, writer);
+ }
+
+ var objectPath = workingDirectory.resolve(name + ".o");
runLlvmCompiler(llvmModulePath, objectPath);
return objectPath;
diff --git a/src/main/java/org/shedlang/compiler/backends/llvm/ir/LlvmIrSerializer.java b/src/main/java/org/shedlang/compiler/backends/llvm/ir/LlvmIrSerializer.java
index 47032f9f..716deb8a 100644
--- a/src/main/java/org/shedlang/compiler/backends/llvm/ir/LlvmIrSerializer.java
+++ b/src/main/java/org/shedlang/compiler/backends/llvm/ir/LlvmIrSerializer.java
@@ -5,294 +5,296 @@ 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.types.*;
+import java.io.IOException;
+
import static org.shedlang.compiler.util.Iterables.forEachInterspersed;
public class LlvmIrSerializer {
private LlvmIrSerializer() {
}
- public static void serializeBasicBlock(LlvmBasicBlock basicBlock, StringBuilder builder) {
+ public static void serializeBasicBlock(LlvmBasicBlock basicBlock, Appendable writer) throws IOException {
if (basicBlock.label().isPresent()) {
- builder.append(basicBlock.label().get());
- builder.append(":\n");
+ writer.append(basicBlock.label().get());
+ writer.append(":\n");
}
for (var instruction : basicBlock.instructions()) {
- builder.append(" ");
- serializeInstruction(instruction, builder);
- builder.append("\n");
+ writer.append(" ");
+ serializeInstruction(instruction, writer);
+ writer.append("\n");
}
- builder.append(" ");
- serializeTerminatorInstruction(basicBlock.terminator(), builder);
- builder.append("\n");
+ writer.append(" ");
+ serializeTerminatorInstruction(basicBlock.terminator(), writer);
+ writer.append("\n");
}
- public static void serializeInstruction(LlvmInstruction instruction, StringBuilder builder) {
+ public static void serializeInstruction(LlvmInstruction instruction, Appendable writer) throws IOException {
switch (instruction) {
case LlvmAdd add -> {
- serializeVariable(add.target(), builder);
- builder.append(" = add ");
- serializeType(add.type(), builder);
- builder.append(" ");
- serializeOperand(add.left(), builder);
- builder.append(", ");
- serializeOperand(add.right(), builder);
+ serializeVariable(add.target(), writer);
+ writer.append(" = add ");
+ serializeType(add.type(), writer);
+ writer.append(" ");
+ serializeOperand(add.left(), writer);
+ writer.append(", ");
+ serializeOperand(add.right(), writer);
}
case LlvmCall call -> {
if (call.target().isPresent()) {
- serializeVariable(call.target().get(), builder);
- builder.append(" = ");
+ serializeVariable(call.target().get(), writer);
+ writer.append(" = ");
}
- builder.append("call ");
- serializeType(call.returnType(), builder);
- builder.append(" ");
- serializeOperand(call.functionPointer(), builder);
- builder.append("(");
+ writer.append("call ");
+ serializeType(call.returnType(), writer);
+ writer.append(" ");
+ serializeOperand(call.functionPointer(), writer);
+ writer.append("(");
forEachInterspersed(
call.args(),
- arg -> serializeTypedOperand(arg, builder),
- () -> builder.append(", ")
+ arg -> serializeTypedOperand(arg, writer),
+ () -> writer.append(", ")
);
- builder.append(")");
+ writer.append(")");
}
case LlvmGetElementPtr getElementPtr -> {
- serializeVariable(getElementPtr.target(), builder);
- builder.append(" = getelementptr ");
- serializeType(getElementPtr.pointerType().elementType(), builder);
- builder.append(", ptr ");
- serializeOperand(getElementPtr.pointer(), builder);
+ serializeVariable(getElementPtr.target(), writer);
+ writer.append(" = getelementptr ");
+ serializeType(getElementPtr.pointerType().elementType(), writer);
+ writer.append(", ptr ");
+ serializeOperand(getElementPtr.pointer(), writer);
for (var index : getElementPtr.indexes()) {
- builder.append(", ");
- serializeTypedOperand(index, builder);
+ writer.append(", ");
+ serializeTypedOperand(index, writer);
}
}
case LlvmIntToPtr intToPtr -> {
- serializeVariable(intToPtr.target(), builder);
- builder.append(" = inttoptr ");
- serializeType(intToPtr.sourceType(), builder);
- builder.append(" ");
- serializeOperand(intToPtr.value(), builder);
- builder.append(" to ptr");
+ serializeVariable(intToPtr.target(), writer);
+ writer.append(" = inttoptr ");
+ serializeType(intToPtr.sourceType(), writer);
+ writer.append(" ");
+ serializeOperand(intToPtr.value(), writer);
+ writer.append(" to ptr");
}
case LlvmLoad load -> {
- serializeVariable(load.target(), builder);
- builder.append(" = load ");
- serializeType(load.type(), builder);
- builder.append(", ptr ");
- serializeOperand(load.pointer(), builder);
+ serializeVariable(load.target(), writer);
+ writer.append(" = load ");
+ serializeType(load.type(), writer);
+ writer.append(", ptr ");
+ serializeOperand(load.pointer(), writer);
}
case LlvmPtrToInt ptrToInt -> {
- serializeVariable(ptrToInt.target(), builder);
- builder.append(" = ptrtoint ptr ");
- serializeOperand(ptrToInt.value(), builder);
- builder.append(" to ");
- serializeType(ptrToInt.targetType(), builder);
+ serializeVariable(ptrToInt.target(), writer);
+ writer.append(" = ptrtoint ptr ");
+ serializeOperand(ptrToInt.value(), writer);
+ writer.append(" to ");
+ serializeType(ptrToInt.targetType(), writer);
}
case LlvmStore store -> {
- builder.append("store ");
- serializeType(store.type(), builder);
- builder.append(" ");
- serializeOperand(store.value(), builder);
- builder.append(", ptr ");
- serializeOperand(store.pointer(), builder);
+ writer.append("store ");
+ serializeType(store.type(), writer);
+ writer.append(" ");
+ serializeOperand(store.value(), writer);
+ writer.append(", ptr ");
+ serializeOperand(store.pointer(), writer);
}
}
}
- public static void serializeModule(LlvmModule module, StringBuilder builder) {
+ public static void serializeModule(LlvmModule module, Appendable writer) throws IOException {
for (var topLevelEntity : module.body()) {
- serializeTopLevelEntity(topLevelEntity, builder);
+ serializeTopLevelEntity(topLevelEntity, writer);
}
}
- public static void serializeOperand(LlvmOperand operand, StringBuilder builder) {
+ public static void serializeOperand(LlvmOperand operand, Appendable writer) throws IOException {
switch (operand) {
case LlvmOperandArray array -> {
- builder.append("[");
+ writer.append("[");
forEachInterspersed(
array.elements(),
element -> {
- serializeType(array.type(), builder);
- builder.append(" ");
- serializeOperand(element, builder);
+ serializeType(array.type(), writer);
+ writer.append(" ");
+ serializeOperand(element, writer);
},
- () -> builder.append(", ")
+ () -> writer.append(", ")
);
- builder.append("]");
+ writer.append("]");
}
case LlvmOperandInt operandInt -> {
- builder.append(operandInt.value());
+ writer.append(Long.toString(operandInt.value()));
}
case LlvmOperandNull operandNull -> {
- builder.append("null");
+ writer.append("null");
}
case LlvmOperandStructure structure -> {
- builder.append("{");
+ writer.append("{");
forEachInterspersed(
structure.elements(),
- element -> serializeTypedOperand(element, builder),
- () -> builder.append(", ")
+ element -> serializeTypedOperand(element, writer),
+ () -> writer.append(", ")
);
- builder.append("}");
+ writer.append("}");
}
case LlvmOperandPtrToInt ptrToInt -> {
- builder.append("ptrtoint (ptr ");
- serializeOperand(ptrToInt.operand(), builder);
- builder.append(" to ");
- serializeType(ptrToInt.targetType(), builder);
- builder.append(")");
+ writer.append("ptrtoint (ptr ");
+ serializeOperand(ptrToInt.operand(), writer);
+ writer.append(" to ");
+ serializeType(ptrToInt.targetType(), writer);
+ writer.append(")");
}
case LlvmVariable variable -> {
- serializeVariable(variable, builder);
+ serializeVariable(variable, writer);
}
}
}
- public static void serializeParam(LlvmParam param, StringBuilder builder) {
- serializeType(param.type(), builder);
- builder.append(" %");
- builder.append(param.name());
+ public static void serializeParam(LlvmParam param, Appendable writer) throws IOException {
+ serializeType(param.type(), writer);
+ writer.append(" %");
+ writer.append(param.name());
}
public static void serializeTerminatorInstruction(
LlvmTerminatorInstruction instruction,
- StringBuilder builder
- ) {
+ Appendable writer
+ ) throws IOException {
switch (instruction) {
case LlvmBr br -> {
- builder.append("br i1 ");
- serializeOperand(br.condition(), builder);
- builder.append(", label %");
- builder.append(br.ifTrueLabel());
- builder.append(", label %");
- builder.append(br.ifFalseLabel());
+ writer.append("br i1 ");
+ serializeOperand(br.condition(), writer);
+ writer.append(", label %");
+ writer.append(br.ifTrueLabel());
+ writer.append(", label %");
+ writer.append(br.ifFalseLabel());
}
case LlvmBrUnconditional br -> {
- builder.append("br label %");
- builder.append(br.targetLabel());
+ writer.append("br label %");
+ writer.append(br.targetLabel());
}
case LlvmReturn returnValue -> {
- builder.append("ret ");
- serializeType(returnValue.type(), builder);
- builder.append(" ");
- serializeOperand(returnValue.value(), builder);
+ writer.append("ret ");
+ serializeType(returnValue.type(), writer);
+ writer.append(" ");
+ serializeOperand(returnValue.value(), writer);
}
case LlvmReturnVoid returnVoid -> {
- builder.append("ret void");
+ writer.append("ret void");
}
}
}
- public static void serializeTopLevelEntity(LlvmTopLevelEntity entity, StringBuilder builder) {
+ public static void serializeTopLevelEntity(LlvmTopLevelEntity entity, Appendable writer) throws IOException {
switch (entity) {
case LlvmFunctionDeclaration functionDeclaration -> {
- builder.append("declare ");
- serializeType(functionDeclaration.returnType(), builder);
- builder.append(" @");
- builder.append(functionDeclaration.name());
- builder.append("(");
+ writer.append("declare ");
+ serializeType(functionDeclaration.returnType(), writer);
+ writer.append(" @");
+ writer.append(functionDeclaration.name());
+ writer.append("(");
forEachInterspersed(
functionDeclaration.params(),
- param -> serializeParam(param, builder),
- () -> builder.append(", ")
+ param -> serializeParam(param, writer),
+ () -> writer.append(", ")
);
- builder.append(")\n");
+ writer.append(")\n");
}
case LlvmFunctionDefinition functionDefinition -> {
- builder.append("define ");
- serializeType(functionDefinition.returnType(), builder);
- builder.append(" @");
- builder.append(functionDefinition.name());
- builder.append("(");
+ writer.append("define ");
+ serializeType(functionDefinition.returnType(), writer);
+ writer.append(" @");
+ writer.append(functionDefinition.name());
+ writer.append("(");
forEachInterspersed(
functionDefinition.params(),
- param -> serializeParam(param, builder),
- () -> builder.append(", ")
+ param -> serializeParam(param, writer),
+ () -> writer.append(", ")
);
- builder.append(") {\n");
+ writer.append(") {\n");
for (var basicBlock : functionDefinition.body()) {
- serializeBasicBlock(basicBlock, builder);
+ serializeBasicBlock(basicBlock, writer);
}
- builder.append("}\n");
+ writer.append("}\n");
}
case LlvmGlobalDefinition globalDefinition -> {
- builder.append("@");
- builder.append(globalDefinition.name());
- builder.append(" = ");
+ writer.append("@");
+ writer.append(globalDefinition.name());
+ writer.append(" = ");
if (globalDefinition.isPrivate()) {
- builder.append("private ");
+ writer.append("private ");
}
if (globalDefinition.unnamedAddr()) {
- builder.append("unnamed_addr ");
+ writer.append("unnamed_addr ");
}
if (globalDefinition.value().isEmpty()) {
- builder.append("external ");
+ writer.append("external ");
}
- builder.append(globalDefinition.constant() ? "constant" : "global");
- builder.append(" ");
- serializeType(globalDefinition.type(), builder);
+ writer.append(globalDefinition.constant() ? "constant" : "global");
+ writer.append(" ");
+ serializeType(globalDefinition.type(), writer);
if (globalDefinition.value().isPresent()) {
- builder.append(" ");
- serializeOperand(globalDefinition.value().get(), builder);
+ writer.append(" ");
+ serializeOperand(globalDefinition.value().get(), writer);
}
- builder.append("\n");
+ writer.append("\n");
}
}
}
- public static void serializeType(LlvmType type, StringBuilder builder) {
+ public static void serializeType(LlvmType type, Appendable writer) throws IOException {
switch (type) {
case LlvmTypeScalar scalar -> {
- builder.append(scalar.name());
+ writer.append(scalar.name());
}
case LlvmTypeArray array -> {
- builder.append("[");
- builder.append(array.size().orElse(0));
- builder.append(" x ");
- serializeType(array.elementType(), builder);
- builder.append("]");
+ writer.append("[");
+ writer.append(Integer.toString(array.size().orElse(0)));
+ writer.append(" x ");
+ serializeType(array.elementType(), writer);
+ writer.append("]");
}
case LlvmTypeStructure structure -> {
- builder.append("{");
+ writer.append("{");
forEachInterspersed(
structure.elementTypes(),
- elementType -> serializeType(elementType, builder),
- () -> builder.append(", ")
+ elementType -> serializeType(elementType, writer),
+ () -> writer.append(", ")
);
- builder.append("}");
+ writer.append("}");
}
case LlvmTypePointer pointer -> {
- builder.append("ptr");
+ writer.append("ptr");
}
case LlvmTypeFunction function -> {
- serializeType(function.returnType(), builder);
- builder.append(" (");
+ serializeType(function.returnType(), writer);
+ writer.append(" (");
forEachInterspersed(
function.paramTypes(),
- paramType -> serializeType(paramType, builder),
- () -> builder.append(", ")
+ paramType -> serializeType(paramType, writer),
+ () -> writer.append(", ")
);
- builder.append(")");
+ writer.append(")");
}
}
}
- public static void serializeTypedOperand(LlvmTypedOperand typedOperand, StringBuilder builder) {
- serializeType(typedOperand.type(), builder);
- builder.append(" ");
- serializeOperand(typedOperand.operand(), builder);
+ public static void serializeTypedOperand(LlvmTypedOperand typedOperand, Appendable writer) throws IOException {
+ serializeType(typedOperand.type(), writer);
+ writer.append(" ");
+ serializeOperand(typedOperand.operand(), writer);
}
- public static void serializeVariable(LlvmVariable variable, StringBuilder builder) {
+ public static void serializeVariable(LlvmVariable variable, Appendable writer) throws IOException {
switch (variable) {
case LlvmVariableGlobal global -> {
- builder.append("@");
- builder.append(global.name());
+ writer.append("@");
+ writer.append(global.name());
}
case LlvmVariableLocal local -> {
- builder.append("%");
- builder.append(local.name());
+ writer.append("%");
+ writer.append(local.name());
}
}
}
diff --git a/src/main/java/org/shedlang/compiler/util/Iterables.java b/src/main/java/org/shedlang/compiler/util/Iterables.java
index 6fcb02e1..ff043c13 100644
--- a/src/main/java/org/shedlang/compiler/util/Iterables.java
+++ b/src/main/java/org/shedlang/compiler/util/Iterables.java
@@ -1,12 +1,22 @@
package org.shedlang.compiler.util;
-import java.util.function.Consumer;
-
public class Iterables {
private Iterables() {
}
- public static <T> void forEachInterspersed(Iterable<T> values, Consumer<T> onElement, Action between) {
+ public interface OnElement<T, E extends Exception> {
+ void accept(T value) throws E;
+ }
+
+ public interface Between<E extends Exception> {
+ void call() throws E;
+ }
+
+ public static <T, E extends Exception> void forEachInterspersed(
+ Iterable<T> values,
+ OnElement<T, E> onElement,
+ Between<E> between
+ ) throws E {
var first = true;
for (var value : values) {
if (!first) {