diff options
| author | Michael Williamson <mike@zwobble.org> | 2023-07-06 18:24:47 +0100 |
|---|---|---|
| committer | Michael Williamson <mike@zwobble.org> | 2023-07-06 18:24:47 +0100 |
| commit | df888d6cce6a31e55eac4e21ccd496ce6023dfeb (patch) | |
| tree | c8c62f9307aa737c8d2289449422e4e31314b916 /src | |
| parent | 163460c063814f659713ceed417e5f0be4a800d0 (diff) | |
Add int-equals instruction
Diffstat (limited to 'src')
20 files changed, 238 insertions, 3 deletions
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 135e9552..8b2520e7 100644 --- a/src/main/java/org/shedlang/compiler/backends/llvm/LlvmCodeGen.java +++ b/src/main/java/org/shedlang/compiler/backends/llvm/LlvmCodeGen.java @@ -5,7 +5,10 @@ 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.LlvmModule; import org.shedlang.compiler.backends.llvm.ir.ast.LlvmParam; +import org.shedlang.compiler.backends.llvm.ir.ast.instructions.LlvmConditionCode; +import org.shedlang.compiler.backends.llvm.ir.ast.instructions.LlvmIcmp; import org.shedlang.compiler.backends.llvm.ir.ast.instructions.LlvmReturn; +import org.shedlang.compiler.backends.llvm.ir.ast.instructions.LlvmZext; 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.types.LlvmTypes; @@ -153,6 +156,40 @@ public class LlvmCodeGen { yield context.push(fieldValue); } + case IntEqualsInstruction intEquals -> { + var rightResult = context.pop(); + var right = rightResult.value(); + context = rightResult.context(); + + var leftResult = context.pop(); + var left = leftResult.value(); + context = leftResult.context(); + + var targetI1Result = context.generateVariableLocal(LlvmCodeGenLocalVariableSpace.TEMPORARY); + var targetI1 = targetI1Result.value(); + context = targetI1Result.context(); + + var targetResult = context.generateVariableLocal(LlvmCodeGenLocalVariableSpace.TEMPORARY); + var target = targetResult.value(); + context = targetResult.context(); + + yield context + .addInstruction(new LlvmIcmp( + targetI1, + LlvmConditionCode.EQ, + LlvmCodeGenTypes.INT_TYPE, + left, + right + )) + .addInstruction(new LlvmZext( + target, + LlvmTypes.INT_1, + targetI1, + LlvmCodeGenTypes.VALUE_TYPE + )) + .push(target); + } + case LocalLoadInstruction localLoad -> context.push(context.shedLocal(localLoad.name())); 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 d8c18bed..a8367384 100644 --- a/src/main/java/org/shedlang/compiler/backends/llvm/LlvmCodeGenTypes.java +++ b/src/main/java/org/shedlang/compiler/backends/llvm/LlvmCodeGenTypes.java @@ -8,4 +8,5 @@ public class LlvmCodeGenTypes { } public static final LlvmTypeScalar VALUE_TYPE = LlvmTypes.INT_64; + public static final LlvmTypeScalar INT_TYPE = LlvmTypes.INT_64; } 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 716deb8a..cad69bc0 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 @@ -30,6 +30,15 @@ public class LlvmIrSerializer { writer.append("\n"); } + private static void serializeConditionCode( + LlvmConditionCode conditionCode, + Appendable writer + ) throws IOException { + writer.append(switch (conditionCode) { + case EQ -> "eq"; + }); + } + public static void serializeInstruction(LlvmInstruction instruction, Appendable writer) throws IOException { switch (instruction) { case LlvmAdd add -> { @@ -69,6 +78,17 @@ public class LlvmIrSerializer { serializeTypedOperand(index, writer); } } + case LlvmIcmp icmp -> { + serializeVariable(icmp.target(), writer); + writer.append(" = icmp "); + serializeConditionCode(icmp.conditionCode(), writer); + writer.append(" "); + serializeType(icmp.type(), writer); + writer.append(" "); + serializeOperand(icmp.left(), writer); + writer.append(", "); + serializeOperand(icmp.right(), writer); + } case LlvmIntToPtr intToPtr -> { serializeVariable(intToPtr.target(), writer); writer.append(" = inttoptr "); @@ -99,6 +119,15 @@ public class LlvmIrSerializer { writer.append(", ptr "); serializeOperand(store.pointer(), writer); } + case LlvmZext zext -> { + serializeVariable(zext.target(), writer); + writer.append(" = zext "); + serializeType(zext.sourceType(), writer); + writer.append(" "); + serializeOperand(zext.value(), writer); + writer.append(" to "); + serializeType(zext.targetType(), writer); + } } } diff --git a/src/main/java/org/shedlang/compiler/backends/llvm/ir/ast/instructions/LlvmConditionCode.java b/src/main/java/org/shedlang/compiler/backends/llvm/ir/ast/instructions/LlvmConditionCode.java new file mode 100644 index 00000000..4dcc331e --- /dev/null +++ b/src/main/java/org/shedlang/compiler/backends/llvm/ir/ast/instructions/LlvmConditionCode.java @@ -0,0 +1,5 @@ +package org.shedlang.compiler.backends.llvm.ir.ast.instructions; + +public enum LlvmConditionCode { + EQ, +} diff --git a/src/main/java/org/shedlang/compiler/backends/llvm/ir/ast/instructions/LlvmIcmp.java b/src/main/java/org/shedlang/compiler/backends/llvm/ir/ast/instructions/LlvmIcmp.java new file mode 100644 index 00000000..01e23385 --- /dev/null +++ b/src/main/java/org/shedlang/compiler/backends/llvm/ir/ast/instructions/LlvmIcmp.java @@ -0,0 +1,14 @@ +package org.shedlang.compiler.backends.llvm.ir.ast.instructions; + +import org.shedlang.compiler.backends.llvm.ir.ast.operands.LlvmOperand; +import org.shedlang.compiler.backends.llvm.ir.ast.operands.LlvmVariable; +import org.shedlang.compiler.backends.llvm.ir.ast.types.LlvmType; + +public record LlvmIcmp( + LlvmVariable target, + LlvmConditionCode conditionCode, + LlvmType type, + LlvmOperand left, + LlvmOperand right +) implements LlvmInstruction { +} diff --git a/src/main/java/org/shedlang/compiler/backends/llvm/ir/ast/instructions/LlvmInstruction.java b/src/main/java/org/shedlang/compiler/backends/llvm/ir/ast/instructions/LlvmInstruction.java index fda542d4..a9073029 100644 --- a/src/main/java/org/shedlang/compiler/backends/llvm/ir/ast/instructions/LlvmInstruction.java +++ b/src/main/java/org/shedlang/compiler/backends/llvm/ir/ast/instructions/LlvmInstruction.java @@ -1,4 +1,4 @@ package org.shedlang.compiler.backends.llvm.ir.ast.instructions; -public sealed interface LlvmInstruction permits LlvmAdd, LlvmCall, LlvmGetElementPtr, LlvmIntToPtr, LlvmLoad, LlvmPtrToInt, LlvmStore { +public sealed interface LlvmInstruction permits LlvmAdd, LlvmCall, LlvmGetElementPtr, LlvmIcmp, LlvmIntToPtr, LlvmLoad, LlvmPtrToInt, LlvmStore, LlvmZext { } diff --git a/src/main/java/org/shedlang/compiler/backends/llvm/ir/ast/instructions/LlvmZext.java b/src/main/java/org/shedlang/compiler/backends/llvm/ir/ast/instructions/LlvmZext.java new file mode 100644 index 00000000..7268b5e7 --- /dev/null +++ b/src/main/java/org/shedlang/compiler/backends/llvm/ir/ast/instructions/LlvmZext.java @@ -0,0 +1,13 @@ +package org.shedlang.compiler.backends.llvm.ir.ast.instructions; + +import org.shedlang.compiler.backends.llvm.ir.ast.operands.LlvmOperand; +import org.shedlang.compiler.backends.llvm.ir.ast.operands.LlvmVariable; +import org.shedlang.compiler.backends.llvm.ir.ast.types.LlvmType; + +public record LlvmZext( + LlvmVariable target, + LlvmType sourceType, + LlvmOperand value, + LlvmType targetType +) implements LlvmInstruction { +} diff --git a/src/main/java/org/shedlang/compiler/backends/wasm/WasmCodeGen.java b/src/main/java/org/shedlang/compiler/backends/wasm/WasmCodeGen.java index 212c81ff..77887f94 100644 --- a/src/main/java/org/shedlang/compiler/backends/wasm/WasmCodeGen.java +++ b/src/main/java/org/shedlang/compiler/backends/wasm/WasmCodeGen.java @@ -179,6 +179,9 @@ public class WasmCodeGen { ); } + case IntEqualsInstruction intEqualsInstruction -> + context.addInstruction(new WasmI32Eq()); + case LocalLoadInstruction localLoad -> context.addInstruction(new WasmLocalGet(context.shedLocal(localLoad.name()))); diff --git a/src/main/java/org/shedlang/compiler/backends/wasm/structure/ast/instructions/WasmI32Eq.java b/src/main/java/org/shedlang/compiler/backends/wasm/structure/ast/instructions/WasmI32Eq.java new file mode 100644 index 00000000..5f384d53 --- /dev/null +++ b/src/main/java/org/shedlang/compiler/backends/wasm/structure/ast/instructions/WasmI32Eq.java @@ -0,0 +1,4 @@ +package org.shedlang.compiler.backends.wasm.structure.ast.instructions; + +public record WasmI32Eq() implements WasmInstruction { +} diff --git a/src/main/java/org/shedlang/compiler/backends/wasm/structure/ast/instructions/WasmInstruction.java b/src/main/java/org/shedlang/compiler/backends/wasm/structure/ast/instructions/WasmInstruction.java index 0e802d51..2e4b166c 100644 --- a/src/main/java/org/shedlang/compiler/backends/wasm/structure/ast/instructions/WasmInstruction.java +++ b/src/main/java/org/shedlang/compiler/backends/wasm/structure/ast/instructions/WasmInstruction.java @@ -1,4 +1,4 @@ package org.shedlang.compiler.backends.wasm.structure.ast.instructions; -public sealed interface WasmInstruction permits WasmCall, WasmCallIndirect, WasmDrop, WasmGlobalGet, WasmGlobalSet, WasmI32Const, WasmI32Load, WasmI32Store, WasmI64Const, WasmIf, WasmLocalGet, WasmLocalSet, WasmMemoryAddressConst, WasmMemoryGrow, WasmReturn, WasmTableElementIndexConst { +public sealed interface WasmInstruction permits WasmCall, WasmCallIndirect, WasmDrop, WasmGlobalGet, WasmGlobalSet, WasmI32Const, WasmI32Eq, WasmI32Load, WasmI32Store, WasmI64Const, WasmIf, WasmLocalGet, WasmLocalSet, WasmMemoryAddressConst, WasmMemoryGrow, WasmReturn, WasmTableElementIndexConst { } diff --git a/src/main/java/org/shedlang/compiler/backends/wasm/structure/binary/WasmBinaryFormatInstructions.java b/src/main/java/org/shedlang/compiler/backends/wasm/structure/binary/WasmBinaryFormatInstructions.java index c9552a96..549c5004 100644 --- a/src/main/java/org/shedlang/compiler/backends/wasm/structure/binary/WasmBinaryFormatInstructions.java +++ b/src/main/java/org/shedlang/compiler/backends/wasm/structure/binary/WasmBinaryFormatInstructions.java @@ -104,6 +104,9 @@ public class WasmBinaryFormatInstructions { writer.writeByte(0x42); writer.writeSignedInt64(i64Const.value()); } + case WasmI32Eq i32Eq -> { + writer.writeByte(0x46); + } // == Relocatable Instructions == diff --git a/src/main/java/org/shedlang/compiler/stackir/InstructionSerializer.java b/src/main/java/org/shedlang/compiler/stackir/InstructionSerializer.java index ef832b90..ac58103c 100644 --- a/src/main/java/org/shedlang/compiler/stackir/InstructionSerializer.java +++ b/src/main/java/org/shedlang/compiler/stackir/InstructionSerializer.java @@ -81,6 +81,9 @@ public class InstructionSerializer { treeString(fieldLoad.namespaceName().toString()), treeString(fieldLoad.fieldName()) ); + + case IntEqualsInstruction intEquals -> + treeList(treeIdentifier("int-equals")); case LocalLoadInstruction localLoadInstruction -> treeList( diff --git a/src/main/java/org/shedlang/compiler/stackir/instructions/Instruction.java b/src/main/java/org/shedlang/compiler/stackir/instructions/Instruction.java index 6a21404c..f3c8a30a 100644 --- a/src/main/java/org/shedlang/compiler/stackir/instructions/Instruction.java +++ b/src/main/java/org/shedlang/compiler/stackir/instructions/Instruction.java @@ -3,7 +3,7 @@ package org.shedlang.compiler.stackir.instructions; import org.shedlang.compiler.sources.Source; public sealed interface Instruction - permits CallInstruction, DefineFunctionInstruction, DiscardInstruction, FieldLoadInstruction, LocalLoadInstruction, LocalStoreInstruction, NamespaceFieldStoreInstruction, NamespaceImportInstruction, PushBoolInstruction, PushIntInstruction, PushStringInstruction, PushUnitInstruction, ReturnInstruction { + permits CallInstruction, DefineFunctionInstruction, DiscardInstruction, FieldLoadInstruction, IntEqualsInstruction, LocalLoadInstruction, LocalStoreInstruction, NamespaceFieldStoreInstruction, NamespaceImportInstruction, PushBoolInstruction, PushIntInstruction, PushStringInstruction, PushUnitInstruction, ReturnInstruction { Source source(); } diff --git a/src/main/java/org/shedlang/compiler/stackir/instructions/IntEqualsInstruction.java b/src/main/java/org/shedlang/compiler/stackir/instructions/IntEqualsInstruction.java new file mode 100644 index 00000000..623db1c4 --- /dev/null +++ b/src/main/java/org/shedlang/compiler/stackir/instructions/IntEqualsInstruction.java @@ -0,0 +1,10 @@ +package org.shedlang.compiler.stackir.instructions; + +import org.shedlang.compiler.sources.Source; + +/** + * Pop two values from the stack, compare them as Ints, and push a Bool onto + * the stack: true if equal, false if not equal. + */ +public record IntEqualsInstruction(Source source) implements Instruction { +} diff --git a/src/test/java/org/shedlang/compiler/backends/llvm/LlvmCodeGenIntEqualsTests.java b/src/test/java/org/shedlang/compiler/backends/llvm/LlvmCodeGenIntEqualsTests.java new file mode 100644 index 00000000..be97752d --- /dev/null +++ b/src/test/java/org/shedlang/compiler/backends/llvm/LlvmCodeGenIntEqualsTests.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 LlvmCodeGenIntEqualsTests { + @Test + public void intEqualsIsCompiledToComparison(Snapshotter snapshotter) throws IOException { + var instruction = Instructions.intEquals(); + 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)); + } +} diff --git a/src/test/java/org/shedlang/compiler/backends/llvm/ir/LlvmIrSerializerInstructionTests.java b/src/test/java/org/shedlang/compiler/backends/llvm/ir/LlvmIrSerializerInstructionTests.java index ee2be2d4..86a5b0d7 100644 --- a/src/test/java/org/shedlang/compiler/backends/llvm/ir/LlvmIrSerializerInstructionTests.java +++ b/src/test/java/org/shedlang/compiler/backends/llvm/ir/LlvmIrSerializerInstructionTests.java @@ -2,6 +2,7 @@ package org.shedlang.compiler.backends.llvm.ir; import org.junit.jupiter.api.Test; import org.shedlang.compiler.backends.llvm.ir.ast.LlvmIr; +import org.shedlang.compiler.backends.llvm.ir.ast.instructions.LlvmConditionCode; import org.shedlang.compiler.backends.llvm.ir.ast.types.LlvmTypes; import java.io.IOException; @@ -115,6 +116,21 @@ public class LlvmIrSerializerInstructionTests { } @Test + public void icmpIsSerialized() throws IOException { + var instruction = LlvmIr.icmp( + LlvmIr.variableLocal("target"), + LlvmConditionCode.EQ, + LlvmTypes.INT_32, + LlvmIr.variableLocal("left"), + LlvmIr.variableLocal("right") + ); + + var result = serializeToString(instruction, LlvmIrSerializer::serializeInstruction); + + assertThat(result, equalTo("%target = icmp eq i32 %left, %right")); + } + + @Test public void intToPtrIsSerialized() throws IOException { var instruction = LlvmIr.intToPtr( LlvmIr.variableLocal("x"), @@ -165,4 +181,18 @@ public class LlvmIrSerializerInstructionTests { assertThat(result, equalTo("store i64 42, ptr %target")); } + + @Test + public void zextIsSerialized() throws IOException { + var instruction = LlvmIr.zext( + LlvmIr.variableLocal("target"), + LlvmTypes.INT_32, + LlvmIr.variableLocal("source"), + LlvmTypes.INT_64 + ); + + var result = serializeToString(instruction, LlvmIrSerializer::serializeInstruction); + + assertThat(result, equalTo("%target = zext i32 %source to i64")); + } } diff --git a/src/test/java/org/shedlang/compiler/backends/llvm/ir/ast/LlvmIr.java b/src/test/java/org/shedlang/compiler/backends/llvm/ir/ast/LlvmIr.java index a8023c35..59c16bb6 100644 --- a/src/test/java/org/shedlang/compiler/backends/llvm/ir/ast/LlvmIr.java +++ b/src/test/java/org/shedlang/compiler/backends/llvm/ir/ast/LlvmIr.java @@ -71,6 +71,16 @@ public class LlvmIr { return new LlvmGetElementPtr(target, pointerType, pointer, indexes); } + public static LlvmIcmp icmp( + LlvmVariable target, + LlvmConditionCode conditionCode, + LlvmType type, + LlvmOperand left, + LlvmOperand right + ) { + return new LlvmIcmp(target, conditionCode, type, left, right); + } + public static LlvmIntToPtr intToPtr( LlvmVariable target, LlvmTypeScalar sourceType, @@ -159,4 +169,13 @@ public class LlvmIr { public static LlvmVariableLocal variableLocal(String name) { return new LlvmVariableLocal(name); } + + public static LlvmZext zext( + LlvmVariable target, + LlvmType sourceType, + LlvmOperand value, + LlvmType targetType + ) { + return new LlvmZext(target, sourceType, value, targetType); + } } diff --git a/src/test/java/org/shedlang/compiler/backends/wasm/WasmCodeGenIntEqualsTests.java b/src/test/java/org/shedlang/compiler/backends/wasm/WasmCodeGenIntEqualsTests.java new file mode 100644 index 00000000..4e6eb0ff --- /dev/null +++ b/src/test/java/org/shedlang/compiler/backends/wasm/WasmCodeGenIntEqualsTests.java @@ -0,0 +1,24 @@ +package org.shedlang.compiler.backends.wasm; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +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.wasm.WasmCodeGenTesting.objdumpContext; + +@ExtendWith({SnapshotResolver.class}) +public class WasmCodeGenIntEqualsTests { + @Test + public void intEqualsIsCompiledToI32Eq(Snapshotter snapshotter) throws IOException, InterruptedException { + var instruction = Instructions.intEquals(); + var context = WasmCodeGenContext.EMPTY; + + var result = WasmCodeGen.generateInstruction(instruction, context); + + snapshotter.assertSnapshot(objdumpContext(result)); + } +} diff --git a/src/test/java/org/shedlang/compiler/stackir/InstructionSerializerTests.java b/src/test/java/org/shedlang/compiler/stackir/InstructionSerializerTests.java index 74e018f3..10588ec1 100644 --- a/src/test/java/org/shedlang/compiler/stackir/InstructionSerializerTests.java +++ b/src/test/java/org/shedlang/compiler/stackir/InstructionSerializerTests.java @@ -74,6 +74,14 @@ public class InstructionSerializerTests { assertThat(string, equalTo("(field-load \"Example/Lib\" \"x\")")); } + @Test + public void canSerializeIntEquals() { + var instruction = Instructions.intEquals(); + + var string = serialize(instruction); + + assertThat(string, equalTo("(int-equals)")); + } @Test public void canSerializeLocalLoad() { diff --git a/src/test/java/org/shedlang/compiler/stackir/instructions/Instructions.java b/src/test/java/org/shedlang/compiler/stackir/instructions/Instructions.java index adc0731b..a1630727 100644 --- a/src/test/java/org/shedlang/compiler/stackir/instructions/Instructions.java +++ b/src/test/java/org/shedlang/compiler/stackir/instructions/Instructions.java @@ -61,4 +61,8 @@ public class Instructions { public static Instruction return_() { return new ReturnInstruction(Sources.NULL); } + + public static Instruction intEquals() { + return new IntEqualsInstruction(Sources.NULL); + } } |
