implements PR-038
This commit is contained in:
parent
574e890c21
commit
0728637f58
@ -13,6 +13,8 @@ public class IRBackend {
|
|||||||
@Builder.Default
|
@Builder.Default
|
||||||
private final ReadOnlyList<IRFunction> functions = ReadOnlyList.empty();
|
private final ReadOnlyList<IRFunction> functions = ReadOnlyList.empty();
|
||||||
@Builder.Default
|
@Builder.Default
|
||||||
|
private final ReadOnlyList<IRBackendExecutableFunction> executableFunctions = ReadOnlyList.empty();
|
||||||
|
@Builder.Default
|
||||||
private final IRReservedMetadata reservedMetadata = IRReservedMetadata.empty();
|
private final IRReservedMetadata reservedMetadata = IRReservedMetadata.empty();
|
||||||
|
|
||||||
public static IRBackendAggregator aggregator() {
|
public static IRBackendAggregator aggregator() {
|
||||||
@ -21,6 +23,7 @@ public class IRBackend {
|
|||||||
|
|
||||||
public static final class IRBackendAggregator {
|
public static final class IRBackendAggregator {
|
||||||
private final ArrayList<IRFunction> functions = new ArrayList<>();
|
private final ArrayList<IRFunction> functions = new ArrayList<>();
|
||||||
|
private final ArrayList<IRBackendExecutableFunction> executableFunctions = new ArrayList<>();
|
||||||
private final ArrayList<IRReservedMetadata.HostMethodBinding> hostMethodBindings = new ArrayList<>();
|
private final ArrayList<IRReservedMetadata.HostMethodBinding> hostMethodBindings = new ArrayList<>();
|
||||||
private final ArrayList<IRReservedMetadata.BuiltinTypeSurface> builtinTypeSurfaces = new ArrayList<>();
|
private final ArrayList<IRReservedMetadata.BuiltinTypeSurface> builtinTypeSurfaces = new ArrayList<>();
|
||||||
private final ArrayList<IRReservedMetadata.BuiltinConstSurface> builtinConstSurfaces = new ArrayList<>();
|
private final ArrayList<IRReservedMetadata.BuiltinConstSurface> builtinConstSurfaces = new ArrayList<>();
|
||||||
@ -31,6 +34,7 @@ public class IRBackend {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
functions.addAll(backendFile.functions().asList());
|
functions.addAll(backendFile.functions().asList());
|
||||||
|
executableFunctions.addAll(backendFile.executableFunctions().asList());
|
||||||
final var metadata = backendFile.reservedMetadata();
|
final var metadata = backendFile.reservedMetadata();
|
||||||
hostMethodBindings.addAll(metadata.hostMethodBindings().asList());
|
hostMethodBindings.addAll(metadata.hostMethodBindings().asList());
|
||||||
builtinTypeSurfaces.addAll(metadata.builtinTypeSurfaces().asList());
|
builtinTypeSurfaces.addAll(metadata.builtinTypeSurfaces().asList());
|
||||||
@ -42,6 +46,7 @@ public class IRBackend {
|
|||||||
return IRBackend
|
return IRBackend
|
||||||
.builder()
|
.builder()
|
||||||
.functions(ReadOnlyList.wrap(functions))
|
.functions(ReadOnlyList.wrap(functions))
|
||||||
|
.executableFunctions(ReadOnlyList.wrap(executableFunctions))
|
||||||
.reservedMetadata(new IRReservedMetadata(
|
.reservedMetadata(new IRReservedMetadata(
|
||||||
ReadOnlyList.wrap(hostMethodBindings),
|
ReadOnlyList.wrap(hostMethodBindings),
|
||||||
ReadOnlyList.wrap(builtinTypeSurfaces),
|
ReadOnlyList.wrap(builtinTypeSurfaces),
|
||||||
@ -55,6 +60,7 @@ public class IRBackend {
|
|||||||
public String toString() {
|
public String toString() {
|
||||||
final var sb = new StringBuilder();
|
final var sb = new StringBuilder();
|
||||||
sb.append("IRBackend{functions=").append(functions.size())
|
sb.append("IRBackend{functions=").append(functions.size())
|
||||||
|
.append(", executableFunctions=").append(executableFunctions.size())
|
||||||
.append(", hostBindings=").append(reservedMetadata.hostMethodBindings().size())
|
.append(", hostBindings=").append(reservedMetadata.hostMethodBindings().size())
|
||||||
.append(", builtinTypes=").append(reservedMetadata.builtinTypeSurfaces().size())
|
.append(", builtinTypes=").append(reservedMetadata.builtinTypeSurfaces().size())
|
||||||
.append(", builtinConsts=").append(reservedMetadata.builtinConstSurfaces().size())
|
.append(", builtinConsts=").append(reservedMetadata.builtinConstSurfaces().size())
|
||||||
|
|||||||
@ -0,0 +1,93 @@
|
|||||||
|
package p.studio.compiler.models;
|
||||||
|
|
||||||
|
import p.studio.compiler.source.Span;
|
||||||
|
import p.studio.compiler.source.identifiers.FileId;
|
||||||
|
import p.studio.utilities.structures.ReadOnlyList;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
public record IRBackendExecutableFunction(
|
||||||
|
FileId fileId,
|
||||||
|
String moduleKey,
|
||||||
|
String callableName,
|
||||||
|
int sourceStart,
|
||||||
|
int sourceEnd,
|
||||||
|
int paramSlots,
|
||||||
|
int localSlots,
|
||||||
|
int returnSlots,
|
||||||
|
int maxStackSlots,
|
||||||
|
ReadOnlyList<Instruction> instructions,
|
||||||
|
Span span) {
|
||||||
|
|
||||||
|
public IRBackendExecutableFunction {
|
||||||
|
fileId = Objects.requireNonNull(fileId, "fileId");
|
||||||
|
moduleKey = moduleKey == null ? "" : moduleKey;
|
||||||
|
callableName = Objects.requireNonNull(callableName, "callableName");
|
||||||
|
instructions = instructions == null ? ReadOnlyList.empty() : instructions;
|
||||||
|
span = span == null ? Span.none() : span;
|
||||||
|
}
|
||||||
|
|
||||||
|
public record Instruction(
|
||||||
|
InstructionKind kind,
|
||||||
|
String calleeModuleKey,
|
||||||
|
String calleeCallableName,
|
||||||
|
HostCallMetadata hostCall,
|
||||||
|
IntrinsicCallMetadata intrinsicCall,
|
||||||
|
Span span) {
|
||||||
|
public Instruction {
|
||||||
|
Objects.requireNonNull(kind, "kind");
|
||||||
|
span = span == null ? Span.none() : span;
|
||||||
|
calleeModuleKey = calleeModuleKey == null ? "" : calleeModuleKey;
|
||||||
|
calleeCallableName = calleeCallableName == null ? "" : calleeCallableName;
|
||||||
|
switch (kind) {
|
||||||
|
case CALL_FUNC -> {
|
||||||
|
if (calleeCallableName.isBlank()) {
|
||||||
|
throw new IllegalArgumentException("CALL_FUNC requires calleeCallableName");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case CALL_HOST -> {
|
||||||
|
if (hostCall == null) {
|
||||||
|
throw new IllegalArgumentException("CALL_HOST requires hostCall metadata");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case CALL_INTRINSIC -> {
|
||||||
|
if (intrinsicCall == null) {
|
||||||
|
throw new IllegalArgumentException("CALL_INTRINSIC requires intrinsic metadata");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case HALT, RET -> {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum InstructionKind {
|
||||||
|
HALT,
|
||||||
|
RET,
|
||||||
|
CALL_FUNC,
|
||||||
|
CALL_HOST,
|
||||||
|
CALL_INTRINSIC,
|
||||||
|
}
|
||||||
|
|
||||||
|
public record HostCallMetadata(
|
||||||
|
String module,
|
||||||
|
String name,
|
||||||
|
long version,
|
||||||
|
int argSlots,
|
||||||
|
int retSlots) {
|
||||||
|
public HostCallMetadata {
|
||||||
|
module = Objects.requireNonNull(module, "module");
|
||||||
|
name = Objects.requireNonNull(name, "name");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public record IntrinsicCallMetadata(
|
||||||
|
String canonicalName,
|
||||||
|
long canonicalVersion,
|
||||||
|
int intrinsicId) {
|
||||||
|
public IntrinsicCallMetadata {
|
||||||
|
canonicalName = Objects.requireNonNull(canonicalName, "canonicalName");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@ -8,20 +8,29 @@ import java.util.Objects;
|
|||||||
public record IRBackendFile(
|
public record IRBackendFile(
|
||||||
FileId fileId,
|
FileId fileId,
|
||||||
ReadOnlyList<IRFunction> functions,
|
ReadOnlyList<IRFunction> functions,
|
||||||
|
ReadOnlyList<IRBackendExecutableFunction> executableFunctions,
|
||||||
IRReservedMetadata reservedMetadata) {
|
IRReservedMetadata reservedMetadata) {
|
||||||
public IRBackendFile {
|
public IRBackendFile {
|
||||||
fileId = Objects.requireNonNull(fileId, "fileId");
|
fileId = Objects.requireNonNull(fileId, "fileId");
|
||||||
functions = functions == null ? ReadOnlyList.empty() : functions;
|
functions = functions == null ? ReadOnlyList.empty() : functions;
|
||||||
|
executableFunctions = executableFunctions == null ? ReadOnlyList.empty() : executableFunctions;
|
||||||
reservedMetadata = reservedMetadata == null ? IRReservedMetadata.empty() : reservedMetadata;
|
reservedMetadata = reservedMetadata == null ? IRReservedMetadata.empty() : reservedMetadata;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IRBackendFile(
|
public IRBackendFile(
|
||||||
final FileId fileId,
|
final FileId fileId,
|
||||||
final ReadOnlyList<IRFunction> functions) {
|
final ReadOnlyList<IRFunction> functions) {
|
||||||
this(fileId, functions, IRReservedMetadata.empty());
|
this(fileId, functions, ReadOnlyList.empty(), IRReservedMetadata.empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IRBackendFile empty(final FileId fileId) {
|
public static IRBackendFile empty(final FileId fileId) {
|
||||||
return new IRBackendFile(fileId, ReadOnlyList.empty(), IRReservedMetadata.empty());
|
return new IRBackendFile(fileId, ReadOnlyList.empty(), ReadOnlyList.empty(), IRReservedMetadata.empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
public IRBackendFile(
|
||||||
|
final FileId fileId,
|
||||||
|
final ReadOnlyList<IRFunction> functions,
|
||||||
|
final IRReservedMetadata reservedMetadata) {
|
||||||
|
this(fileId, functions, ReadOnlyList.empty(), reservedMetadata);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,90 @@
|
|||||||
|
package p.studio.compiler.models;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import p.studio.compiler.source.Span;
|
||||||
|
import p.studio.compiler.source.identifiers.FileId;
|
||||||
|
import p.studio.utilities.structures.ReadOnlyList;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
|
|
||||||
|
class IRBackendExecutableContractTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void callInstructionMustRequireCategorySpecificMetadata() {
|
||||||
|
assertThrows(IllegalArgumentException.class, () -> new IRBackendExecutableFunction.Instruction(
|
||||||
|
IRBackendExecutableFunction.InstructionKind.CALL_HOST,
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
Span.none()));
|
||||||
|
|
||||||
|
final var callFunc = new IRBackendExecutableFunction.Instruction(
|
||||||
|
IRBackendExecutableFunction.InstructionKind.CALL_FUNC,
|
||||||
|
"app/main",
|
||||||
|
"foo",
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
Span.none());
|
||||||
|
assertEquals(IRBackendExecutableFunction.InstructionKind.CALL_FUNC, callFunc.kind());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void aggregatorMustPreserveExecutableFunctionOrderDeterministically() {
|
||||||
|
final var fileA = new IRBackendFile(
|
||||||
|
new FileId(1),
|
||||||
|
ReadOnlyList.empty(),
|
||||||
|
ReadOnlyList.from(new IRBackendExecutableFunction(
|
||||||
|
new FileId(1),
|
||||||
|
"app/main",
|
||||||
|
"entry",
|
||||||
|
0,
|
||||||
|
10,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
ReadOnlyList.from(new IRBackendExecutableFunction.Instruction(
|
||||||
|
IRBackendExecutableFunction.InstructionKind.HALT,
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
Span.none())),
|
||||||
|
Span.none())),
|
||||||
|
IRReservedMetadata.empty());
|
||||||
|
final var fileB = new IRBackendFile(
|
||||||
|
new FileId(2),
|
||||||
|
ReadOnlyList.empty(),
|
||||||
|
ReadOnlyList.from(new IRBackendExecutableFunction(
|
||||||
|
new FileId(2),
|
||||||
|
"app/main",
|
||||||
|
"aux",
|
||||||
|
11,
|
||||||
|
20,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
ReadOnlyList.from(new IRBackendExecutableFunction.Instruction(
|
||||||
|
IRBackendExecutableFunction.InstructionKind.RET,
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
Span.none())),
|
||||||
|
Span.none())),
|
||||||
|
IRReservedMetadata.empty());
|
||||||
|
|
||||||
|
final var aggregator = IRBackend.aggregator();
|
||||||
|
aggregator.merge(fileA);
|
||||||
|
aggregator.merge(fileB);
|
||||||
|
final var backend = aggregator.emit();
|
||||||
|
|
||||||
|
assertEquals(2, backend.getExecutableFunctions().size());
|
||||||
|
assertEquals("entry", backend.getExecutableFunctions().get(0).callableName());
|
||||||
|
assertEquals("aux", backend.getExecutableFunctions().get(1).callableName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Loading…
x
Reference in New Issue
Block a user