From 8cfec90370f6d5bc9dcae22a38b2fb0ff8520e9a Mon Sep 17 00:00:00 2001 From: Michael Williamson Date: Sat, 8 Jul 2023 12:42:35 +0100 Subject: Support string-add in LLVM backend --- .../compiler/backends/llvm/LlvmCodeGen.java | 31 +++++++++++--------- .../compiler/backends/llvm/LlvmCodeGenStrings.java | 33 ++++++++++++++++++++++ .../compiler/backends/llvm/LlvmCodeGenTypes.java | 1 + .../backends/llvm/LlvmCodeGenStringAddTests.java | 28 ++++++++++++++++++ 4 files changed, 79 insertions(+), 14 deletions(-) create mode 100644 src/test/java/org/shedlang/compiler/backends/llvm/LlvmCodeGenStringAddTests.java (limited to 'src') diff --git a/src/main/java/org/shedlang/compiler/backends/llvm/LlvmCodeGen.java b/src/main/java/org/shedlang/compiler/backends/llvm/LlvmCodeGen.java index 875fb799..e2236dcc 100644 --- a/src/main/java/org/shedlang/compiler/backends/llvm/LlvmCodeGen.java +++ b/src/main/java/org/shedlang/compiler/backends/llvm/LlvmCodeGen.java @@ -149,8 +149,10 @@ public class LlvmCodeGen { case IntAddInstruction intAdd -> generateBinaryOperation( - (target, left, right) -> - new LlvmAdd(target, LlvmCodeGenTypes.INT_TYPE, left, right), + (target, left, right, operationContext) -> + operationContext.addInstruction( + new LlvmAdd(target, LlvmCodeGenTypes.INT_TYPE, left, right) + ), context ); @@ -162,8 +164,10 @@ public class LlvmCodeGen { case IntSubInstruction intSub -> generateBinaryOperation( - (target, left, right) -> - new LlvmSub(target, LlvmCodeGenTypes.INT_TYPE, left, right), + (target, left, right, operationContext) -> + operationContext.addInstruction( + new LlvmSub(target, LlvmCodeGenTypes.INT_TYPE, left, right) + ), context ); @@ -230,15 +234,20 @@ public class LlvmCodeGen { } case StringAddInstruction stringAdd -> - throw new UnsupportedOperationException("TODO"); + generateBinaryOperation( + (target, left, right, operationContext) -> + LlvmCodeGenStrings.add(target, left, right, operationContext), + context + ); }; } interface BinaryOperation { - LlvmInstruction generate( + LlvmCodeGenContext generate( LlvmVariable target, LlvmOperand left, - LlvmOperand right + LlvmOperand right, + LlvmCodeGenContext context ); } @@ -258,13 +267,7 @@ public class LlvmCodeGen { var target = targetResult.value(); context = targetResult.context(); - return context - .addInstruction(operation.generate( - target, - left, - right - )) - .push(target); + return operation.generate(target, left, right, context).push(target); } private static LlvmCodeGenContext generateBinaryComparison( diff --git a/src/main/java/org/shedlang/compiler/backends/llvm/LlvmCodeGenStrings.java b/src/main/java/org/shedlang/compiler/backends/llvm/LlvmCodeGenStrings.java index 8165e3c8..6c9c782d 100644 --- a/src/main/java/org/shedlang/compiler/backends/llvm/LlvmCodeGenStrings.java +++ b/src/main/java/org/shedlang/compiler/backends/llvm/LlvmCodeGenStrings.java @@ -1,6 +1,9 @@ package org.shedlang.compiler.backends.llvm; +import org.shedlang.compiler.backends.llvm.ir.ast.LlvmFunctionDeclaration; import org.shedlang.compiler.backends.llvm.ir.ast.LlvmGlobalDefinition; +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.operands.*; import org.shedlang.compiler.backends.llvm.ir.ast.types.LlvmType; import org.shedlang.compiler.backends.llvm.ir.ast.types.LlvmTypePointer; @@ -67,4 +70,34 @@ public class LlvmCodeGenStrings { LlvmCodeGenTypes.VALUE_TYPE ); } + + public static LlvmCodeGenContext add( + LlvmVariable target, + LlvmOperand left, + LlvmOperand right, + LlvmCodeGenContext context + ) { + var runtimeAddName = "shed__runtime__string_add"; + + if (!context.hasTopLevelEntity(runtimeAddName)) { + context = context.addTopLevelEntity(new LlvmFunctionDeclaration( + runtimeAddName, + LlvmCodeGenTypes.STRING_TYPE, + List.of( + new LlvmParam(LlvmCodeGenTypes.STRING_TYPE, "left"), + new LlvmParam(LlvmCodeGenTypes.STRING_TYPE, "right") + ) + )); + } + + return context.addInstruction(new LlvmCall( + target, + LlvmCodeGenTypes.STRING_TYPE, + new LlvmVariableGlobal(runtimeAddName), + List.of( + new LlvmTypedOperand(LlvmCodeGenTypes.STRING_TYPE, left), + new LlvmTypedOperand(LlvmCodeGenTypes.STRING_TYPE, right) + ) + )); + } } diff --git a/src/main/java/org/shedlang/compiler/backends/llvm/LlvmCodeGenTypes.java b/src/main/java/org/shedlang/compiler/backends/llvm/LlvmCodeGenTypes.java index a8367384..e2d37a8a 100644 --- a/src/main/java/org/shedlang/compiler/backends/llvm/LlvmCodeGenTypes.java +++ b/src/main/java/org/shedlang/compiler/backends/llvm/LlvmCodeGenTypes.java @@ -9,4 +9,5 @@ public class LlvmCodeGenTypes { public static final LlvmTypeScalar VALUE_TYPE = LlvmTypes.INT_64; public static final LlvmTypeScalar INT_TYPE = LlvmTypes.INT_64; + public static final LlvmTypeScalar STRING_TYPE = VALUE_TYPE; } diff --git a/src/test/java/org/shedlang/compiler/backends/llvm/LlvmCodeGenStringAddTests.java b/src/test/java/org/shedlang/compiler/backends/llvm/LlvmCodeGenStringAddTests.java new file mode 100644 index 00000000..29fa4370 --- /dev/null +++ b/src/test/java/org/shedlang/compiler/backends/llvm/LlvmCodeGenStringAddTests.java @@ -0,0 +1,28 @@ +package org.shedlang.compiler.backends.llvm; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.shedlang.compiler.backends.llvm.ir.ast.LlvmIr; +import org.shedlang.compiler.stackir.instructions.Instructions; +import org.shedlang.compiler.testing.snapshots.SnapshotResolver; +import org.shedlang.compiler.testing.snapshots.Snapshotter; + +import java.io.IOException; + +import static org.shedlang.compiler.backends.llvm.LlvmCodeGenTesting.serializeContext; + +@ExtendWith({SnapshotResolver.class}) +public class LlvmCodeGenStringAddTests { + @Test + public void stringAddIsCompiledToCallToRuntimeStringAdd(Snapshotter snapshotter) throws IOException { + var instruction = Instructions.stringAdd(); + var context = LlvmCodeGenContext.EMPTY + .push(LlvmIr.variableLocal("a")) + .push(LlvmIr.variableLocal("b")) + .push(LlvmIr.variableLocal("c")); + + var result = LlvmCodeGen.generateInstruction(instruction, context); + + snapshotter.assertSnapshot(serializeContext(result)); + } +} -- cgit v1.2.3