implements PR-05.0.3

This commit is contained in:
bQUARKz 2026-03-09 06:30:55 +00:00
parent bafab68eac
commit 0149b85e7d
Signed by: bquarkz
SSH Key Fingerprint: SHA256:Z7dgqoglWwoK6j6u4QC87OveEq74WOhFN+gitsxtkf8
12 changed files with 103 additions and 70 deletions

View File

@ -15,7 +15,9 @@ import p.studio.compiler.pbs.semantics.PbsFlowSemanticsValidator;
import p.studio.compiler.pbs.semantics.PbsSemanticsErrors;
import p.studio.compiler.source.diagnostics.DiagnosticSink;
import p.studio.compiler.source.diagnostics.DiagnosticPhase;
import p.studio.compiler.source.identifiers.CallableId;
import p.studio.compiler.source.identifiers.FileId;
import p.studio.compiler.source.identifiers.IntrinsicId;
import p.studio.compiler.source.tables.CallableSignatureRef;
import p.studio.compiler.source.tables.CallableTable;
import p.studio.compiler.source.tables.IntrinsicReference;
@ -186,17 +188,16 @@ public final class PbsFrontendCompiler {
}
}
final var callableIdTable = new CallableTable();
final var callableIdsByNameAndArity = new HashMap<String, List<Integer>>();
final var callableIdByDeclaration = new HashMap<PbsAst.FunctionDecl, Integer>();
final var returnSlotsByCallableId = new HashMap<Integer, Integer>();
final var callableIdsByNameAndArity = new HashMap<String, List<CallableId>>();
final var callableIdByDeclaration = new HashMap<PbsAst.FunctionDecl, CallableId>();
final var returnSlotsByCallableId = new HashMap<CallableId, Integer>();
final var intrinsicIdTable = new IntrinsicTable();
for (final var declaredFn : ast.functions()) {
final var callableId = callableIdTable.register(
normalizedModuleKey,
declaredFn.name(),
declaredFn.parameters().size(),
callableShapeKey(declaredFn))
.getId();
normalizedModuleKey,
declaredFn.name(),
declaredFn.parameters().size(),
callableShapeKey(declaredFn));
callableIdByDeclaration.put(declaredFn, callableId);
callableIdsByNameAndArity
.computeIfAbsent(callableArityKey(declaredFn.name(), declaredFn.parameters().size()), ignored -> new ArrayList<>())
@ -255,7 +256,7 @@ public final class PbsFrontendCompiler {
intrinsic.canonicalVersion(),
intrinsicIdTable
.register(intrinsic.canonicalName(), intrinsic.canonicalVersion())
.getId()),
),
callExpr.span()));
continue;
}

View File

@ -65,15 +65,15 @@ class PbsGoldenArtifactsTest {
.append("::")
.append(fn.callableName())
.append(" id=")
.append(fn.callableId())
.append(fn.callableId().getId())
.append('\n');
for (final var instruction : fn.instructions()) {
out.append(" ")
.append(instruction.kind())
.append(" calleeId=")
.append(instruction.calleeCallableId() == null ? "-" : instruction.calleeCallableId())
.append(instruction.calleeCallableId() == null ? "-" : instruction.calleeCallableId().getId())
.append(" intrinsicId=")
.append(instruction.intrinsicCall() == null ? "-" : instruction.intrinsicCall().intrinsicId())
.append(instruction.intrinsicCall() == null ? "-" : instruction.intrinsicCall().intrinsicId().getId())
.append('\n');
}
}

View File

@ -5,6 +5,7 @@ import p.studio.compiler.backend.bytecode.BytecodeModule;
import p.studio.compiler.models.IRBackend;
import p.studio.compiler.models.IRBackendExecutableFunction;
import p.studio.compiler.source.Span;
import p.studio.compiler.source.identifiers.CallableId;
import p.studio.utilities.structures.ReadOnlyList;
import java.util.ArrayList;
@ -15,7 +16,7 @@ public class LowerToIRVMService {
private static final Comparator<IRBackendExecutableFunction> FUNCTION_ORDER = Comparator
.comparing(IRBackendExecutableFunction::moduleKey)
.thenComparing(IRBackendExecutableFunction::callableName)
.thenComparingInt(IRBackendExecutableFunction::callableId)
.thenComparingInt(function -> function.callableId().getIndex())
.thenComparingInt(IRBackendExecutableFunction::sourceStart);
private final IRVMValidator validator;
@ -42,7 +43,7 @@ public class LowerToIRVMService {
}
final var ordered = orderFunctions(backend.getExecutableFunctions());
final var funcIdByCallableId = new HashMap<Integer, Integer>();
final var funcIdByCallableId = new HashMap<CallableId, Integer>();
for (var i = 0; i < ordered.size(); i++) {
final var fn = ordered.get(i);
if (funcIdByCallableId.putIfAbsent(fn.callableId(), i) != null) {
@ -127,13 +128,14 @@ public class LowerToIRVMService {
}
case CALL_INTRINSIC -> {
final var intrinsic = instr.intrinsicCall();
if (intrinsic.intrinsicId() < 0 || intrinsic.intrinsicId() >= backend.getIntrinsicPool().size()) {
final var intrinsicIndex = intrinsic.intrinsicId().getIndex();
if (intrinsicIndex < 0 || intrinsicIndex >= backend.getIntrinsicPool().size()) {
throw new IRVMLoweringException(
IRVMLoweringErrorCode.LOWER_IRVM_INVALID_INTRINSIC_ID,
"invalid intrinsic id: " + intrinsic.intrinsicId());
}
instructions.add(new IRVMInstruction(IRVMOp.INTRINSIC, intrinsic.intrinsicId()));
operations.add(BytecodeEmitter.Operation.intrinsic(intrinsic.intrinsicId(), sourceSpan));
instructions.add(new IRVMInstruction(IRVMOp.INTRINSIC, intrinsicIndex));
operations.add(BytecodeEmitter.Operation.intrinsic(intrinsicIndex, sourceSpan));
functionPc += IRVMOp.INTRINSIC.immediateSize() + 2;
}
case LABEL -> {

View File

@ -6,7 +6,9 @@ import p.studio.compiler.backend.irvm.LowerToIRVMService;
import p.studio.compiler.models.IRBackend;
import p.studio.compiler.models.IRBackendExecutableFunction;
import p.studio.compiler.source.Span;
import p.studio.compiler.source.identifiers.CallableId;
import p.studio.compiler.source.identifiers.FileId;
import p.studio.compiler.source.identifiers.IntrinsicId;
import p.studio.compiler.source.tables.IntrinsicReference;
import p.studio.utilities.structures.ReadOnlyList;
@ -45,7 +47,7 @@ class GoldenArtifactsTest {
new FileId(1),
"app/main",
"main",
0,
new CallableId(0),
0,
20,
0,
@ -66,7 +68,7 @@ class GoldenArtifactsTest {
"",
"",
null,
new IRBackendExecutableFunction.IntrinsicCallMetadata("core.color.pack", 1, 0),
new IRBackendExecutableFunction.IntrinsicCallMetadata("core.color.pack", 1, new IntrinsicId(0)),
Span.none()),
new IRBackendExecutableFunction.Instruction(
IRBackendExecutableFunction.InstructionKind.RET,

View File

@ -4,7 +4,9 @@ import org.junit.jupiter.api.Test;
import p.studio.compiler.models.IRBackend;
import p.studio.compiler.models.IRBackendExecutableFunction;
import p.studio.compiler.source.Span;
import p.studio.compiler.source.identifiers.CallableId;
import p.studio.compiler.source.identifiers.FileId;
import p.studio.compiler.source.identifiers.IntrinsicId;
import p.studio.compiler.source.tables.IntrinsicReference;
import p.studio.utilities.structures.ReadOnlyList;
@ -137,7 +139,7 @@ class LowerToIRVMServiceTest {
new FileId(0),
moduleKey,
name,
callableId,
new CallableId(callableId),
0,
10,
0,
@ -166,7 +168,7 @@ class LowerToIRVMServiceTest {
IRBackendExecutableFunction.InstructionKind.CALL_FUNC,
moduleKey,
name,
calleeCallableId,
new CallableId(calleeCallableId),
null,
null,
Span.none());
@ -182,7 +184,7 @@ class LowerToIRVMServiceTest {
IRBackendExecutableFunction.InstructionKind.CALL_FUNC,
moduleKey,
name,
calleeCallableId,
new CallableId(calleeCallableId),
null,
null,
expectedArgSlots,
@ -214,7 +216,7 @@ class LowerToIRVMServiceTest {
"",
"",
null,
new IRBackendExecutableFunction.IntrinsicCallMetadata(canonicalName, canonicalVersion, intrinsicId),
new IRBackendExecutableFunction.IntrinsicCallMetadata(canonicalName, canonicalVersion, new IntrinsicId(intrinsicId)),
Span.none());
}

View File

@ -10,7 +10,9 @@ import p.studio.compiler.models.BuilderPipelineContext;
import p.studio.compiler.models.IRBackend;
import p.studio.compiler.models.IRBackendExecutableFunction;
import p.studio.compiler.source.Span;
import p.studio.compiler.source.identifiers.CallableId;
import p.studio.compiler.source.identifiers.FileId;
import p.studio.compiler.source.identifiers.IntrinsicId;
import p.studio.compiler.source.tables.IntrinsicReference;
import p.studio.compiler.workspaces.stages.EmitBytecodePipelineStage;
import p.studio.compiler.workspaces.stages.LowerToIRVMPipelineStage;
@ -188,7 +190,7 @@ class BackendGateIIntegrationTest {
new FileId(1),
"app/main",
name,
1,
new CallableId(1),
0,
10,
0,
@ -233,7 +235,7 @@ class BackendGateIIntegrationTest {
"",
"",
null,
new IRBackendExecutableFunction.IntrinsicCallMetadata(canonicalName, canonicalVersion, intrinsicId),
new IRBackendExecutableFunction.IntrinsicCallMetadata(canonicalName, canonicalVersion, new IntrinsicId(intrinsicId)),
Span.none());
}

View File

@ -12,6 +12,7 @@ import p.studio.compiler.models.BuilderPipelineContext;
import p.studio.compiler.models.IRBackend;
import p.studio.compiler.models.IRBackendExecutableFunction;
import p.studio.compiler.source.Span;
import p.studio.compiler.source.identifiers.CallableId;
import p.studio.compiler.source.identifiers.FileId;
import p.studio.utilities.logs.LogAggregator;
import p.studio.utilities.structures.ReadOnlyList;
@ -29,7 +30,7 @@ class BackendSafetyGateSUTest {
new FileId(1),
"app",
"main",
1,
new CallableId(1),
0,
10,
0,
@ -41,7 +42,7 @@ class BackendSafetyGateSUTest {
IRBackendExecutableFunction.InstructionKind.CALL_FUNC,
"app",
"missing",
99,
new CallableId(99),
null,
null,
0,
@ -114,7 +115,7 @@ class BackendSafetyGateSUTest {
new FileId(1),
"app",
"main",
1,
new CallableId(1),
0,
10,
0,

View File

@ -6,6 +6,7 @@ import p.studio.compiler.models.BuilderPipelineContext;
import p.studio.compiler.models.IRBackend;
import p.studio.compiler.models.IRBackendExecutableFunction;
import p.studio.compiler.source.Span;
import p.studio.compiler.source.identifiers.CallableId;
import p.studio.compiler.source.identifiers.FileId;
import p.studio.utilities.logs.LogAggregator;
import p.studio.utilities.structures.ReadOnlyList;
@ -39,7 +40,7 @@ class LowerToIRVMPipelineStageTest {
new FileId(0),
"app",
"main",
1,
new CallableId(1),
0,
10,
0,
@ -72,7 +73,7 @@ class LowerToIRVMPipelineStageTest {
new FileId(0),
"app",
"main",
1,
new CallableId(1),
0,
10,
0,

View File

@ -10,4 +10,8 @@ public class CallableId extends SourceIdentifier {
public static CallableId none() {
return NONE;
}
public boolean isNone() {
return this == NONE;
}
}

View File

@ -2,6 +2,8 @@ package p.studio.compiler.models;
import lombok.Builder;
import lombok.Getter;
import p.studio.compiler.source.identifiers.CallableId;
import p.studio.compiler.source.identifiers.IntrinsicId;
import p.studio.compiler.source.tables.CallableSignatureRef;
import p.studio.compiler.source.tables.CallableTable;
import p.studio.compiler.source.tables.IntrinsicReference;
@ -56,24 +58,24 @@ public class IRBackend {
requiredCapabilities.addAll(metadata.requiredCapabilities().asList());
}
private int[] reindexCallables(final ReadOnlyList<CallableSignatureRef> localCallableSignatures) {
private CallableId[] reindexCallables(final ReadOnlyList<CallableSignatureRef> localCallableSignatures) {
if (localCallableSignatures == null || localCallableSignatures.isEmpty()) {
return new int[0];
return new CallableId[0];
}
final var remap = new int[localCallableSignatures.size()];
final var remap = new CallableId[localCallableSignatures.size()];
for (var i = 0; i < localCallableSignatures.size(); i++) {
remap[i] = callableTable.register(localCallableSignatures.get(i)).getId();
remap[i] = callableTable.register(localCallableSignatures.get(i));
}
return remap;
}
private IRBackendExecutableFunction remapExecutableFunction(
final IRBackendExecutableFunction function,
final int[] callableRemap,
final int[] intrinsicRemap) {
final CallableId[] callableRemap,
final IntrinsicId[] intrinsicRemap) {
final var remappedInstructions = new ArrayList<IRBackendExecutableFunction.Instruction>(function.instructions().size());
for (final var instruction : function.instructions()) {
final Integer remappedCallee;
final CallableId remappedCallee;
if (instruction.calleeCallableId() == null) {
remappedCallee = null;
} else {
@ -117,34 +119,36 @@ public class IRBackend {
function.span());
}
private int remapCallableId(
final int localCallableId,
final int[] callableRemap,
private CallableId remapCallableId(
final CallableId localCallableId,
final CallableId[] callableRemap,
final String label) {
if (localCallableId < 0 || localCallableId >= callableRemap.length) {
final var localIndex = localCallableId.getIndex();
if (localIndex < 0 || localIndex >= callableRemap.length) {
throw new IllegalArgumentException("invalid local " + label + " callable id: " + localCallableId);
}
return callableRemap[localCallableId];
return callableRemap[localIndex];
}
private int[] reindexIntrinsics(final ReadOnlyList<IntrinsicReference> localIntrinsicPool) {
private IntrinsicId[] reindexIntrinsics(final ReadOnlyList<IntrinsicReference> localIntrinsicPool) {
if (localIntrinsicPool == null || localIntrinsicPool.isEmpty()) {
return new int[0];
return new IntrinsicId[0];
}
final var remap = new int[localIntrinsicPool.size()];
final var remap = new IntrinsicId[localIntrinsicPool.size()];
for (var i = 0; i < localIntrinsicPool.size(); i++) {
remap[i] = intrinsicTable.register(localIntrinsicPool.get(i)).getId();
remap[i] = intrinsicTable.register(localIntrinsicPool.get(i));
}
return remap;
}
private int remapIntrinsicId(
final int localIntrinsicId,
final int[] intrinsicRemap) {
if (localIntrinsicId < 0 || localIntrinsicId >= intrinsicRemap.length) {
private IntrinsicId remapIntrinsicId(
final IntrinsicId localIntrinsicId,
final IntrinsicId[] intrinsicRemap) {
final var localIndex = localIntrinsicId.getIndex();
if (localIndex < 0 || localIndex >= intrinsicRemap.length) {
throw new IllegalArgumentException("invalid local intrinsic id: " + localIntrinsicId);
}
return intrinsicRemap[localIntrinsicId];
return intrinsicRemap[localIndex];
}
private ReadOnlyList<CallableSignatureRef> emitCallableSignatures() {

View File

@ -1,7 +1,9 @@
package p.studio.compiler.models;
import p.studio.compiler.source.Span;
import p.studio.compiler.source.identifiers.CallableId;
import p.studio.compiler.source.identifiers.FileId;
import p.studio.compiler.source.identifiers.IntrinsicId;
import p.studio.utilities.structures.ReadOnlyList;
import java.util.Objects;
@ -10,7 +12,7 @@ public record IRBackendExecutableFunction(
FileId fileId,
String moduleKey,
String callableName,
int callableId,
CallableId callableId,
int sourceStart,
int sourceEnd,
int paramSlots,
@ -27,9 +29,11 @@ public record IRBackendExecutableFunction(
if (callableName.isBlank()) {
throw new IllegalArgumentException("callableName must not be blank");
}
if (callableId < 0) {
throw new IllegalArgumentException("callableId must be non-negative");
callableId = Objects.requireNonNull(callableId, "callableId");
if (callableId.isNone()) {
throw new IllegalArgumentException("callableId must not be none");
}
callableId.getIndex();
if (sourceStart < 0 || sourceEnd < 0 || sourceEnd < sourceStart) {
throw new IllegalArgumentException("invalid source span bounds");
}
@ -50,7 +54,7 @@ public record IRBackendExecutableFunction(
InstructionKind kind,
String calleeModuleKey,
String calleeCallableName,
Integer calleeCallableId,
CallableId calleeCallableId,
HostCallMetadata hostCall,
IntrinsicCallMetadata intrinsicCall,
String label,
@ -62,7 +66,7 @@ public record IRBackendExecutableFunction(
final InstructionKind kind,
final String calleeModuleKey,
final String calleeCallableName,
final Integer calleeCallableId,
final CallableId calleeCallableId,
final HostCallMetadata hostCall,
final IntrinsicCallMetadata intrinsicCall,
final Span span) {
@ -73,7 +77,7 @@ public record IRBackendExecutableFunction(
final InstructionKind kind,
final String calleeModuleKey,
final String calleeCallableName,
final Integer calleeCallableId,
final CallableId calleeCallableId,
final HostCallMetadata hostCall,
final IntrinsicCallMetadata intrinsicCall,
final Integer expectedArgSlots,
@ -111,8 +115,11 @@ public record IRBackendExecutableFunction(
calleeCallableName = calleeCallableName == null ? "" : calleeCallableName;
label = label == null ? "" : label;
targetLabel = targetLabel == null ? "" : targetLabel;
if (calleeCallableId != null && calleeCallableId < 0) {
throw new IllegalArgumentException("calleeCallableId must be non-negative");
if (calleeCallableId != null && calleeCallableId.isNone()) {
throw new IllegalArgumentException("calleeCallableId must not be none");
}
if (calleeCallableId != null) {
calleeCallableId.getIndex();
}
if (expectedArgSlots != null && expectedArgSlots < 0) {
throw new IllegalArgumentException("expectedArgSlots must be non-negative");
@ -224,7 +231,7 @@ public record IRBackendExecutableFunction(
public record IntrinsicCallMetadata(
String canonicalName,
long canonicalVersion,
int intrinsicId) {
IntrinsicId intrinsicId) {
public IntrinsicCallMetadata {
canonicalName = Objects.requireNonNull(canonicalName, "canonicalName");
if (canonicalName.isBlank()) {
@ -233,6 +240,11 @@ public record IRBackendExecutableFunction(
if (canonicalVersion < 0) {
throw new IllegalArgumentException("canonicalVersion must be non-negative");
}
intrinsicId = Objects.requireNonNull(intrinsicId, "intrinsicId");
if (intrinsicId.isNone()) {
throw new IllegalArgumentException("intrinsicId must not be none");
}
intrinsicId.getIndex();
}
}
}

View File

@ -2,7 +2,9 @@ package p.studio.compiler.models;
import org.junit.jupiter.api.Test;
import p.studio.compiler.source.Span;
import p.studio.compiler.source.identifiers.CallableId;
import p.studio.compiler.source.identifiers.FileId;
import p.studio.compiler.source.identifiers.IntrinsicId;
import p.studio.compiler.source.tables.CallableSignatureRef;
import p.studio.compiler.source.tables.IntrinsicReference;
import p.studio.utilities.structures.ReadOnlyList;
@ -27,7 +29,7 @@ class IRBackendExecutableContractTest {
IRBackendExecutableFunction.InstructionKind.CALL_FUNC,
"app/main",
"foo",
7,
new CallableId(7),
null,
null,
Span.none());
@ -40,7 +42,7 @@ class IRBackendExecutableContractTest {
new FileId(1),
"app",
"main",
1,
new CallableId(1),
10,
5,
0,
@ -54,7 +56,7 @@ class IRBackendExecutableContractTest {
new FileId(1),
"app",
"main",
1,
new CallableId(1),
0,
10,
0,
@ -72,7 +74,7 @@ class IRBackendExecutableContractTest {
IRBackendExecutableFunction.InstructionKind.CALL_FUNC,
"app/main",
"foo",
1,
new CallableId(1),
new IRBackendExecutableFunction.HostCallMetadata("gfx", "draw", 1, 0, 0),
null,
Span.none()));
@ -123,7 +125,7 @@ class IRBackendExecutableContractTest {
new FileId(1),
"app/main",
"entry",
0,
new CallableId(0),
0,
10,
0,
@ -149,7 +151,7 @@ class IRBackendExecutableContractTest {
new FileId(2),
"app/main",
"aux",
0,
new CallableId(0),
11,
20,
0,
@ -189,7 +191,7 @@ class IRBackendExecutableContractTest {
new FileId(1),
"app/main",
"entry",
0,
new CallableId(0),
0,
10,
0,
@ -201,7 +203,7 @@ class IRBackendExecutableContractTest {
"",
"",
null,
new IRBackendExecutableFunction.IntrinsicCallMetadata("core.color.pack", 1, 0),
new IRBackendExecutableFunction.IntrinsicCallMetadata("core.color.pack", 1, new IntrinsicId(0)),
Span.none())),
Span.none())),
IRReservedMetadata.empty(),
@ -214,7 +216,7 @@ class IRBackendExecutableContractTest {
new FileId(2),
"app/main",
"aux",
0,
new CallableId(0),
11,
20,
0,
@ -226,7 +228,7 @@ class IRBackendExecutableContractTest {
"",
"",
null,
new IRBackendExecutableFunction.IntrinsicCallMetadata("core.color.pack", 1, 0),
new IRBackendExecutableFunction.IntrinsicCallMetadata("core.color.pack", 1, new IntrinsicId(0)),
Span.none())),
Span.none())),
IRReservedMetadata.empty(),