implements PR-038
This commit is contained in:
parent
574e890c21
commit
0728637f58
@ -13,6 +13,8 @@ public class IRBackend {
|
||||
@Builder.Default
|
||||
private final ReadOnlyList<IRFunction> functions = ReadOnlyList.empty();
|
||||
@Builder.Default
|
||||
private final ReadOnlyList<IRBackendExecutableFunction> executableFunctions = ReadOnlyList.empty();
|
||||
@Builder.Default
|
||||
private final IRReservedMetadata reservedMetadata = IRReservedMetadata.empty();
|
||||
|
||||
public static IRBackendAggregator aggregator() {
|
||||
@ -21,6 +23,7 @@ public class IRBackend {
|
||||
|
||||
public static final class IRBackendAggregator {
|
||||
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.BuiltinTypeSurface> builtinTypeSurfaces = new ArrayList<>();
|
||||
private final ArrayList<IRReservedMetadata.BuiltinConstSurface> builtinConstSurfaces = new ArrayList<>();
|
||||
@ -31,6 +34,7 @@ public class IRBackend {
|
||||
return;
|
||||
}
|
||||
functions.addAll(backendFile.functions().asList());
|
||||
executableFunctions.addAll(backendFile.executableFunctions().asList());
|
||||
final var metadata = backendFile.reservedMetadata();
|
||||
hostMethodBindings.addAll(metadata.hostMethodBindings().asList());
|
||||
builtinTypeSurfaces.addAll(metadata.builtinTypeSurfaces().asList());
|
||||
@ -42,6 +46,7 @@ public class IRBackend {
|
||||
return IRBackend
|
||||
.builder()
|
||||
.functions(ReadOnlyList.wrap(functions))
|
||||
.executableFunctions(ReadOnlyList.wrap(executableFunctions))
|
||||
.reservedMetadata(new IRReservedMetadata(
|
||||
ReadOnlyList.wrap(hostMethodBindings),
|
||||
ReadOnlyList.wrap(builtinTypeSurfaces),
|
||||
@ -55,6 +60,7 @@ public class IRBackend {
|
||||
public String toString() {
|
||||
final var sb = new StringBuilder();
|
||||
sb.append("IRBackend{functions=").append(functions.size())
|
||||
.append(", executableFunctions=").append(executableFunctions.size())
|
||||
.append(", hostBindings=").append(reservedMetadata.hostMethodBindings().size())
|
||||
.append(", builtinTypes=").append(reservedMetadata.builtinTypeSurfaces().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(
|
||||
FileId fileId,
|
||||
ReadOnlyList<IRFunction> functions,
|
||||
ReadOnlyList<IRBackendExecutableFunction> executableFunctions,
|
||||
IRReservedMetadata reservedMetadata) {
|
||||
public IRBackendFile {
|
||||
fileId = Objects.requireNonNull(fileId, "fileId");
|
||||
functions = functions == null ? ReadOnlyList.empty() : functions;
|
||||
executableFunctions = executableFunctions == null ? ReadOnlyList.empty() : executableFunctions;
|
||||
reservedMetadata = reservedMetadata == null ? IRReservedMetadata.empty() : reservedMetadata;
|
||||
}
|
||||
|
||||
public IRBackendFile(
|
||||
final FileId fileId,
|
||||
final ReadOnlyList<IRFunction> functions) {
|
||||
this(fileId, functions, IRReservedMetadata.empty());
|
||||
this(fileId, functions, ReadOnlyList.empty(), IRReservedMetadata.empty());
|
||||
}
|
||||
|
||||
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