From 51c202c469f884d1c67987282ed952cc303f43d7 Mon Sep 17 00:00:00 2001 From: Michael Williamson Date: Wed, 19 Jul 2023 22:10:39 +0100 Subject: Add Patio code gen for call --- .../org/shedlang/compiler/patio/PatioCodeGen.java | 79 +++++++++++++++++++--- .../compiler/patio/PatioCodeGenClosures.java | 47 +++++++++++++ .../compiler/patio/PatioCodeGenContext.java | 68 ++++++++++++++++++- .../compiler/patio/PatioCodeGenLocalSpace.java | 18 +++++ .../compiler/patio/PatioCodeGenResult.java | 4 ++ .../org/shedlang/compiler/patio/PatioLocal.java | 4 ++ 6 files changed, 209 insertions(+), 11 deletions(-) create mode 100644 src/main/java/org/shedlang/compiler/patio/PatioCodeGenClosures.java create mode 100644 src/main/java/org/shedlang/compiler/patio/PatioCodeGenLocalSpace.java create mode 100644 src/main/java/org/shedlang/compiler/patio/PatioCodeGenResult.java create mode 100644 src/main/java/org/shedlang/compiler/patio/PatioLocal.java (limited to 'src/main/java') diff --git a/src/main/java/org/shedlang/compiler/patio/PatioCodeGen.java b/src/main/java/org/shedlang/compiler/patio/PatioCodeGen.java index c0d52b54..6d07971f 100644 --- a/src/main/java/org/shedlang/compiler/patio/PatioCodeGen.java +++ b/src/main/java/org/shedlang/compiler/patio/PatioCodeGen.java @@ -1,35 +1,94 @@ package org.shedlang.compiler.patio; -import org.pcollections.PVector; import org.shedlang.compiler.patio.instructions.*; import org.shedlang.compiler.stackir.instructions.*; -import org.shedlang.compiler.util.P; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Map; + +import static org.shedlang.compiler.util.Lists.reversed; public class PatioCodeGen { private PatioCodeGen() {} - public static PVector generateInstruction(Instruction stackIrInstruction) { + public static PatioCodeGenContext generateInstruction( + Instruction stackIrInstruction, + PatioCodeGenContext context + ) { return switch (stackIrInstruction) { + case CallInstruction call -> { + var namedArgsByName = new ArrayList>(); + for (var argName : reversed(call.namedArgNames())) { + var argResult = context.allocateLocal( + PatioCodeGenLocalSpace.CALL_ARG_NAMED, + argName + ); + var arg = argResult.value(); + context = argResult.context(); + + context = context.addInstruction( + new PatioLocalStore(arg.name(), stackIrInstruction.source()) + ); + + namedArgsByName.add(Map.entry(argName, arg)); + } + + var positionalArgs = new ArrayList(); + for (var i = 0; i < call.positionalArgCount(); i++) { + var argResult = context.allocateLocal( + PatioCodeGenLocalSpace.CALL_ARG_POSITIONAL, + Integer.toString(call.positionalArgCount() - i - 1) + ); + var arg = argResult.value(); + context = argResult.context(); + + context = context.addInstruction( + new PatioLocalStore(arg.name(), stackIrInstruction.source()) + ); + + positionalArgs.add(arg); + } + Collections.reverse(positionalArgs); + + var receiverResult = context.allocateLocal(PatioCodeGenLocalSpace.RECEIVER); + var receiver = receiverResult.value(); + context = receiverResult.context(); + + context = context.addInstruction(new PatioLocalStore( + receiver.name(), + stackIrInstruction.source() + )); + + yield PatioCodeGenClosures.call( + receiver, + positionalArgs, + namedArgsByName, + stackIrInstruction.source(), + context + ); + } + case DiscardInstruction discard -> - P.vector(new PatioDiscard(discard.source())); + context.addInstruction(new PatioDiscard(discard.source())); case LocalLoadInstruction localLoad -> - P.vector(new PatioLocalLoad(localLoad.name(), localLoad.source())); + context.addInstruction(new PatioLocalLoad(localLoad.name(), localLoad.source())); case LocalStoreInstruction localStore -> - P.vector(new PatioLocalStore(localStore.name(), localStore.source())); + context.addInstruction(new PatioLocalStore(localStore.name(), localStore.source())); case PushBoolInstruction pushBool -> - P.vector(new PatioPushInt(pushBool.value() ? 1 : 0, pushBool.source())); + context.addInstruction(new PatioPushInt(pushBool.value() ? 1 : 0, pushBool.source())); case PushIntInstruction pushInt -> - P.vector(new PatioPushInt(pushInt.value().intValueExact(), pushInt.source())); + context.addInstruction(new PatioPushInt(pushInt.value().intValueExact(), pushInt.source())); case PushUnitInstruction pushUnit -> - P.vector(new PatioPushInt(0, pushUnit.source())); + context.addInstruction(new PatioPushInt(0, pushUnit.source())); case ReturnInstruction return_ -> - P.vector(new PatioReturn(return_.source())); + context.addInstruction(new PatioReturn(return_.source())); default -> throw new IllegalStateException("Unexpected value: " + stackIrInstruction); diff --git a/src/main/java/org/shedlang/compiler/patio/PatioCodeGenClosures.java b/src/main/java/org/shedlang/compiler/patio/PatioCodeGenClosures.java new file mode 100644 index 00000000..0cd31616 --- /dev/null +++ b/src/main/java/org/shedlang/compiler/patio/PatioCodeGenClosures.java @@ -0,0 +1,47 @@ +package org.shedlang.compiler.patio; + +import org.shedlang.compiler.patio.instructions.PatioCallPointer; +import org.shedlang.compiler.patio.instructions.PatioLocalLoad; +import org.shedlang.compiler.patio.instructions.PatioMemoryLoad; +import org.shedlang.compiler.sources.Source; + +import java.util.List; +import java.util.Map; + +import static org.shedlang.compiler.util.Iterables.sortedBy; + +class PatioCodeGenClosures { + private PatioCodeGenClosures() {} + + private static final int FUNCTION_POINTER_OFFSET = 0; + + static PatioCodeGenContext call( + PatioLocal closure, + List positionalArgs, + List> namedArgsByName, + Source source, + PatioCodeGenContext context + ) { + // TODO: WASM expects the receiver to be pushed last, but we push it first. + // Do we change our instruction set to match WASM? Or have a call + // mechanism less reliant on stack order? + context = context + .addInstruction(new PatioLocalLoad(closure.name(), source)) + .addInstruction(new PatioMemoryLoad(FUNCTION_POINTER_OFFSET, source)); + + context = context.addInstruction(new PatioLocalLoad(closure.name(), source)); + + for (var positionalArg : positionalArgs) { + context = context.addInstruction(new PatioLocalLoad(positionalArg.name(), source)); + } + + for (var namedArg : sortedBy(namedArgsByName, x -> x.getKey())) { + context = context.addInstruction(new PatioLocalLoad(namedArg.getValue().name(), source)); + } + + var argCount = positionalArgs.size() + namedArgsByName.size(); + + return context + .addInstruction(new PatioCallPointer(argCount, source)); + } +} diff --git a/src/main/java/org/shedlang/compiler/patio/PatioCodeGenContext.java b/src/main/java/org/shedlang/compiler/patio/PatioCodeGenContext.java index 675925e3..7ac7b263 100644 --- a/src/main/java/org/shedlang/compiler/patio/PatioCodeGenContext.java +++ b/src/main/java/org/shedlang/compiler/patio/PatioCodeGenContext.java @@ -1,4 +1,70 @@ package org.shedlang.compiler.patio; -public class PatioCodeGenContext { +import org.pcollections.PVector; +import org.shedlang.compiler.backends.llvm.NameAllocator; +import org.shedlang.compiler.patio.instructions.PatioInstruction; +import org.shedlang.compiler.util.P; + +import java.util.Optional; + +public record PatioCodeGenContext( + FunctionContext functionContext +) { + public record FunctionContext( + PVector instructions, + NameAllocator localNames + ) { + public static final FunctionContext EMPTY = new FunctionContext( + P.vector(), + NameAllocator.empty() + ); + + public FunctionContext addInstruction(PatioInstruction instruction) { + return new FunctionContext( + this.instructions.plus(instruction), + this.localNames + ); + } + + public Result allocateLocal(PatioCodeGenLocalSpace space, Optional name) { + var result = this.localNames.generateName(space, name); + + return new FunctionContext( + this.instructions, + result.allocator() + ).toResult(new PatioLocal(result.name())); + } + + private Result toResult(T value) { + return new Result<>(value, this); + } + + public record Result(T value, FunctionContext context) {} + } + + public static final PatioCodeGenContext EMPTY = new PatioCodeGenContext( + FunctionContext.EMPTY + ); + + public PatioCodeGenContext addInstruction(PatioInstruction instruction) { + return new PatioCodeGenContext( + this.functionContext.addInstruction(instruction) + ); + } + + public PatioCodeGenResult allocateLocal(PatioCodeGenLocalSpace space, String name) { + var result = this.functionContext.allocateLocal(space, Optional.of(name)); + + return new PatioCodeGenContext(result.context).toResult(result.value); + } + + public PatioCodeGenResult allocateLocal(PatioCodeGenLocalSpace space) { + var result = this.functionContext.allocateLocal(space, Optional.empty()); + + return new PatioCodeGenContext(result.context).toResult(result.value); + } + + private PatioCodeGenResult toResult(T value) { + return new PatioCodeGenResult<>(value, this); + } } diff --git a/src/main/java/org/shedlang/compiler/patio/PatioCodeGenLocalSpace.java b/src/main/java/org/shedlang/compiler/patio/PatioCodeGenLocalSpace.java new file mode 100644 index 00000000..dfbcf4ee --- /dev/null +++ b/src/main/java/org/shedlang/compiler/patio/PatioCodeGenLocalSpace.java @@ -0,0 +1,18 @@ +package org.shedlang.compiler.patio; + +public enum PatioCodeGenLocalSpace { + CALL_ARG_POSITIONAL("callArgPositional"), + CALL_ARG_NAMED("callArgNamed"), + RECEIVER("receiver");; + + private final String name; + + PatioCodeGenLocalSpace(String name) { + this.name = name; + } + + @Override + public String toString() { + return name; + } +} diff --git a/src/main/java/org/shedlang/compiler/patio/PatioCodeGenResult.java b/src/main/java/org/shedlang/compiler/patio/PatioCodeGenResult.java new file mode 100644 index 00000000..5644a3b1 --- /dev/null +++ b/src/main/java/org/shedlang/compiler/patio/PatioCodeGenResult.java @@ -0,0 +1,4 @@ +package org.shedlang.compiler.patio; + +public record PatioCodeGenResult(T value, PatioCodeGenContext context) { +} diff --git a/src/main/java/org/shedlang/compiler/patio/PatioLocal.java b/src/main/java/org/shedlang/compiler/patio/PatioLocal.java new file mode 100644 index 00000000..bdd1a7ab --- /dev/null +++ b/src/main/java/org/shedlang/compiler/patio/PatioLocal.java @@ -0,0 +1,4 @@ +package org.shedlang.compiler.patio; + +public record PatioLocal(String name) { +} -- cgit v1.2.3