a little bit of gfx
This commit is contained in:
parent
079db44cd1
commit
59e33d6639
@ -79,6 +79,10 @@ public final class PbsReservedMetadataExtractor {
|
|||||||
abiModule,
|
abiModule,
|
||||||
abiMethod,
|
abiMethod,
|
||||||
abiVersion,
|
abiVersion,
|
||||||
|
switch (signature.returnKind()) {
|
||||||
|
case INFERRED_UNIT, EXPLICIT_UNIT -> 0;
|
||||||
|
case PLAIN, RESULT -> 1;
|
||||||
|
},
|
||||||
capabilityAttribute.isPresent(),
|
capabilityAttribute.isPresent(),
|
||||||
capability,
|
capability,
|
||||||
signature.span()));
|
signature.span()));
|
||||||
|
|||||||
@ -28,6 +28,7 @@ final class PbsExecutableBodyLowerer {
|
|||||||
final PbsExecutableCallableRegistry callableRegistry,
|
final PbsExecutableCallableRegistry callableRegistry,
|
||||||
final IntrinsicTable intrinsicIdTable) {
|
final IntrinsicTable intrinsicIdTable) {
|
||||||
final var localSlotByNameId = initialLocalSlots(functionDecl, nameTable);
|
final var localSlotByNameId = initialLocalSlots(functionDecl, nameTable);
|
||||||
|
final var localOwnerByNameId = initialLocalOwners(functionDecl, nameTable, metadataIndex);
|
||||||
final var context = new PbsExecutableLoweringContext(
|
final var context = new PbsExecutableLoweringContext(
|
||||||
diagnostics,
|
diagnostics,
|
||||||
nameTable,
|
nameTable,
|
||||||
@ -35,6 +36,7 @@ final class PbsExecutableBodyLowerer {
|
|||||||
callableRegistry,
|
callableRegistry,
|
||||||
intrinsicIdTable,
|
intrinsicIdTable,
|
||||||
localSlotByNameId,
|
localSlotByNameId,
|
||||||
|
localOwnerByNameId,
|
||||||
functionDecl.parameters().size());
|
functionDecl.parameters().size());
|
||||||
final var terminated = lowerBlock(functionDecl.body(), context);
|
final var terminated = lowerBlock(functionDecl.body(), context);
|
||||||
finalizeFunctionInstructions(functionDecl, context, terminated);
|
finalizeFunctionInstructions(functionDecl, context, terminated);
|
||||||
@ -70,6 +72,20 @@ final class PbsExecutableBodyLowerer {
|
|||||||
return localSlotByNameId;
|
return localSlotByNameId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Map<NameId, String> initialLocalOwners(
|
||||||
|
final PbsAst.FunctionDecl functionDecl,
|
||||||
|
final NameTable nameTable,
|
||||||
|
final PbsExecutableMetadataIndex metadataIndex) {
|
||||||
|
final var localOwnerByNameId = new HashMap<NameId, String>();
|
||||||
|
for (final var parameter : functionDecl.parameters()) {
|
||||||
|
final var ownerCanonical = resolveBuiltinOwnerCanonical(parameter.typeRef(), metadataIndex);
|
||||||
|
if (!ownerCanonical.isBlank()) {
|
||||||
|
localOwnerByNameId.put(nameTable.register(parameter.name()), ownerCanonical);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return localOwnerByNameId;
|
||||||
|
}
|
||||||
|
|
||||||
private int returnSlotsFor(final PbsAst.FunctionDecl functionDecl) {
|
private int returnSlotsFor(final PbsAst.FunctionDecl functionDecl) {
|
||||||
return switch (functionDecl.returnKind()) {
|
return switch (functionDecl.returnKind()) {
|
||||||
case INFERRED_UNIT, EXPLICIT_UNIT -> 0;
|
case INFERRED_UNIT, EXPLICIT_UNIT -> 0;
|
||||||
@ -137,8 +153,10 @@ final class PbsExecutableBodyLowerer {
|
|||||||
private boolean lowerLetStatement(
|
private boolean lowerLetStatement(
|
||||||
final PbsAst.LetStatement letStatement,
|
final PbsAst.LetStatement letStatement,
|
||||||
final PbsExecutableLoweringContext context) {
|
final PbsExecutableLoweringContext context) {
|
||||||
|
final var localOwner = callsiteEmitter.resolveExpressionOwnerForLowering(letStatement.initializer(), context);
|
||||||
lowerExpression(letStatement.initializer(), context);
|
lowerExpression(letStatement.initializer(), context);
|
||||||
final var localSlot = context.declareLocalSlot(letStatement.name());
|
final var localSlot = context.declareLocalSlot(letStatement.name());
|
||||||
|
context.bindLocalOwner(letStatement.name(), localOwner);
|
||||||
emitSetLocal(localSlot, letStatement.span(), context);
|
emitSetLocal(localSlot, letStatement.span(), context);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -161,17 +179,40 @@ final class PbsExecutableBodyLowerer {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (assignStatement.operator() == PbsAst.AssignOperator.ASSIGN) {
|
if (assignStatement.operator() == PbsAst.AssignOperator.ASSIGN) {
|
||||||
|
final var localOwner = callsiteEmitter.resolveExpressionOwnerForLowering(assignStatement.value(), context);
|
||||||
lowerExpression(assignStatement.value(), context);
|
lowerExpression(assignStatement.value(), context);
|
||||||
|
context.bindLocalOwner(target.rootName(), localOwner);
|
||||||
emitSetLocal(targetSlot, assignStatement.span(), context);
|
emitSetLocal(targetSlot, assignStatement.span(), context);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
emitGetLocal(targetSlot, assignStatement.span(), context);
|
emitGetLocal(targetSlot, assignStatement.span(), context);
|
||||||
lowerExpression(assignStatement.value(), context);
|
lowerExpression(assignStatement.value(), context);
|
||||||
emitBinaryOperatorInstruction(compoundAssignBinaryOperator(assignStatement.operator()), assignStatement.span(), context);
|
emitBinaryOperatorInstruction(compoundAssignBinaryOperator(assignStatement.operator()), assignStatement.span(), context);
|
||||||
|
context.bindLocalOwner(target.rootName(), "");
|
||||||
emitSetLocal(targetSlot, assignStatement.span(), context);
|
emitSetLocal(targetSlot, assignStatement.span(), context);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String resolveBuiltinOwnerCanonical(
|
||||||
|
final PbsAst.TypeRef typeRef,
|
||||||
|
final PbsExecutableMetadataIndex metadataIndex) {
|
||||||
|
final var unwrapped = unwrapGroup(typeRef);
|
||||||
|
if (unwrapped == null || unwrapped.kind() != PbsAst.TypeRefKind.SIMPLE) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return metadataIndex.builtinCanonicalBySourceType().getOrDefault(unwrapped.name(), "");
|
||||||
|
}
|
||||||
|
|
||||||
|
private PbsAst.TypeRef unwrapGroup(final PbsAst.TypeRef typeRef) {
|
||||||
|
if (typeRef == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (typeRef.kind() != PbsAst.TypeRefKind.GROUP) {
|
||||||
|
return typeRef;
|
||||||
|
}
|
||||||
|
return unwrapGroup(typeRef.inner());
|
||||||
|
}
|
||||||
|
|
||||||
private boolean lowerReturnStatement(
|
private boolean lowerReturnStatement(
|
||||||
final PbsAst.ReturnStatement returnStatement,
|
final PbsAst.ReturnStatement returnStatement,
|
||||||
final PbsExecutableLoweringContext context) {
|
final PbsExecutableLoweringContext context) {
|
||||||
|
|||||||
@ -43,10 +43,28 @@ final class PbsExecutableCallsiteEmitter {
|
|||||||
final PbsExecutableLoweringContext context) {
|
final PbsExecutableLoweringContext context) {
|
||||||
return new PbsResolvedCallsiteCandidates(
|
return new PbsResolvedCallsiteCandidates(
|
||||||
resolveCallableCandidates(callExpr, calleeIdentity, context),
|
resolveCallableCandidates(callExpr, calleeIdentity, context),
|
||||||
context.hostByMethodName().getOrDefault(calleeIdentity.memberNameId(), List.of()),
|
resolveHostCandidates(callExpr, calleeIdentity, context),
|
||||||
resolveIntrinsicCandidates(callExpr, calleeIdentity, context));
|
resolveIntrinsicCandidates(callExpr, calleeIdentity, context));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<IRReservedMetadata.HostMethodBinding> resolveHostCandidates(
|
||||||
|
final PbsAst.CallExpr callExpr,
|
||||||
|
final PbsCalleeIdentity calleeIdentity,
|
||||||
|
final PbsExecutableLoweringContext context) {
|
||||||
|
final var hostCandidates = context.hostByMethodName().getOrDefault(calleeIdentity.memberNameId(), List.of());
|
||||||
|
if (hostCandidates.isEmpty()) {
|
||||||
|
return List.of();
|
||||||
|
}
|
||||||
|
final var ownerHint = hostOwnerHint(callExpr.callee());
|
||||||
|
if (ownerHint.isBlank()) {
|
||||||
|
return hostCandidates;
|
||||||
|
}
|
||||||
|
final var filtered = hostCandidates.stream()
|
||||||
|
.filter(candidate -> ownerHint.equals(candidate.ownerName()))
|
||||||
|
.toList();
|
||||||
|
return filtered;
|
||||||
|
}
|
||||||
|
|
||||||
private List<CallableId> resolveCallableCandidates(
|
private List<CallableId> resolveCallableCandidates(
|
||||||
final PbsAst.CallExpr callExpr,
|
final PbsAst.CallExpr callExpr,
|
||||||
final PbsCalleeIdentity calleeIdentity,
|
final PbsCalleeIdentity calleeIdentity,
|
||||||
@ -126,7 +144,7 @@ final class PbsExecutableCallsiteEmitter {
|
|||||||
final PbsAst.CallExpr callExpr,
|
final PbsAst.CallExpr callExpr,
|
||||||
final PbsExecutableLoweringContext context,
|
final PbsExecutableLoweringContext context,
|
||||||
final IRReservedMetadata.HostMethodBinding host) {
|
final IRReservedMetadata.HostMethodBinding host) {
|
||||||
final var effectiveArgSlots = callExpr.arguments().size() + implicitReceiverArgSlots(callExpr.callee());
|
final var effectiveArgSlots = callExpr.arguments().size() + implicitReceiverArgSlots(callExpr.callee(), context);
|
||||||
context.instructions().add(new IRBackendExecutableFunction.Instruction(
|
context.instructions().add(new IRBackendExecutableFunction.Instruction(
|
||||||
IRBackendExecutableFunction.InstructionKind.CALL_HOST,
|
IRBackendExecutableFunction.InstructionKind.CALL_HOST,
|
||||||
"",
|
"",
|
||||||
@ -135,7 +153,7 @@ final class PbsExecutableCallsiteEmitter {
|
|||||||
host.abiMethod(),
|
host.abiMethod(),
|
||||||
host.abiVersion(),
|
host.abiVersion(),
|
||||||
effectiveArgSlots,
|
effectiveArgSlots,
|
||||||
0),
|
host.retSlots()),
|
||||||
null,
|
null,
|
||||||
callExpr.span()));
|
callExpr.span()));
|
||||||
}
|
}
|
||||||
@ -144,7 +162,7 @@ final class PbsExecutableCallsiteEmitter {
|
|||||||
final PbsAst.CallExpr callExpr,
|
final PbsAst.CallExpr callExpr,
|
||||||
final PbsExecutableLoweringContext context,
|
final PbsExecutableLoweringContext context,
|
||||||
final IRReservedMetadata.IntrinsicSurface intrinsic) {
|
final IRReservedMetadata.IntrinsicSurface intrinsic) {
|
||||||
final var effectiveArgSlots = intrinsic.argSlots() + implicitReceiverArgSlots(callExpr.callee());
|
final var effectiveArgSlots = intrinsic.argSlots() + implicitReceiverArgSlots(callExpr.callee(), context);
|
||||||
context.instructions().add(new IRBackendExecutableFunction.Instruction(
|
context.instructions().add(new IRBackendExecutableFunction.Instruction(
|
||||||
IRBackendExecutableFunction.InstructionKind.CALL_INTRINSIC,
|
IRBackendExecutableFunction.InstructionKind.CALL_INTRINSIC,
|
||||||
"",
|
"",
|
||||||
@ -176,7 +194,7 @@ final class PbsExecutableCallsiteEmitter {
|
|||||||
reportUnsupportedLowering("executable lowering resolved callable without signature metadata", callExpr.span(), context);
|
reportUnsupportedLowering("executable lowering resolved callable without signature metadata", callExpr.span(), context);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final var effectiveArgSlots = callExpr.arguments().size() + implicitReceiverArgSlots(callExpr.callee());
|
final var effectiveArgSlots = callExpr.arguments().size() + implicitReceiverArgSlots(callExpr.callee(), context);
|
||||||
context.instructions().add(new IRBackendExecutableFunction.Instruction(
|
context.instructions().add(new IRBackendExecutableFunction.Instruction(
|
||||||
IRBackendExecutableFunction.InstructionKind.CALL_FUNC,
|
IRBackendExecutableFunction.InstructionKind.CALL_FUNC,
|
||||||
calleeSignature.moduleId(),
|
calleeSignature.moduleId(),
|
||||||
@ -211,15 +229,32 @@ final class PbsExecutableCallsiteEmitter {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String resolveExpressionOwnerForLowering(
|
||||||
|
final PbsAst.Expression expression,
|
||||||
|
final PbsExecutableLoweringContext context) {
|
||||||
|
return resolveExpressionOwner(expression, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String hostOwnerHint(final PbsAst.Expression callee) {
|
||||||
|
return switch (callee) {
|
||||||
|
case PbsAst.MemberExpr memberExpr -> {
|
||||||
|
final var rootName = memberRootName(memberExpr.receiver());
|
||||||
|
yield rootName == null ? "" : rootName;
|
||||||
|
}
|
||||||
|
case PbsAst.GroupExpr groupExpr -> hostOwnerHint(groupExpr.expression());
|
||||||
|
default -> "";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
private String resolveExpressionOwner(
|
private String resolveExpressionOwner(
|
||||||
final PbsAst.Expression expression,
|
final PbsAst.Expression expression,
|
||||||
final PbsExecutableLoweringContext context) {
|
final PbsExecutableLoweringContext context) {
|
||||||
if (expression == null) {
|
if (expression == null) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
return switch (expression) {
|
return switch (expression) {
|
||||||
case PbsAst.IdentifierExpr identifierExpr ->
|
case PbsAst.IdentifierExpr identifierExpr ->
|
||||||
context.builtinConstOwnerByNameId().getOrDefault(context.nameTable().register(identifierExpr.name()), "");
|
resolveIdentifierOwner(identifierExpr.name(), context);
|
||||||
case PbsAst.CallExpr callExpr -> resolveCallReturnOwner(callExpr, context);
|
case PbsAst.CallExpr callExpr -> resolveCallReturnOwner(callExpr, context);
|
||||||
case PbsAst.MemberExpr memberExpr -> resolveExpressionOwner(memberExpr.receiver(), context);
|
case PbsAst.MemberExpr memberExpr -> resolveExpressionOwner(memberExpr.receiver(), context);
|
||||||
case PbsAst.GroupExpr groupExpr -> resolveExpressionOwner(groupExpr.expression(), context);
|
case PbsAst.GroupExpr groupExpr -> resolveExpressionOwner(groupExpr.expression(), context);
|
||||||
@ -227,6 +262,16 @@ final class PbsExecutableCallsiteEmitter {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String resolveIdentifierOwner(
|
||||||
|
final String identifier,
|
||||||
|
final PbsExecutableLoweringContext context) {
|
||||||
|
final var localOwner = context.resolveLocalOwner(identifier);
|
||||||
|
if (!localOwner.isBlank()) {
|
||||||
|
return localOwner;
|
||||||
|
}
|
||||||
|
return context.builtinConstOwnerByNameId().getOrDefault(context.nameTable().register(identifier), "");
|
||||||
|
}
|
||||||
|
|
||||||
private String resolveCallReturnOwner(
|
private String resolveCallReturnOwner(
|
||||||
final PbsAst.CallExpr callExpr,
|
final PbsAst.CallExpr callExpr,
|
||||||
final PbsExecutableLoweringContext context) {
|
final PbsExecutableLoweringContext context) {
|
||||||
@ -302,17 +347,22 @@ final class PbsExecutableCallsiteEmitter {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private int implicitReceiverArgSlots(final PbsAst.Expression callee) {
|
private int implicitReceiverArgSlots(
|
||||||
|
final PbsAst.Expression callee,
|
||||||
|
final PbsExecutableLoweringContext context) {
|
||||||
if (!(callee instanceof PbsAst.MemberExpr memberExpr)) {
|
if (!(callee instanceof PbsAst.MemberExpr memberExpr)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return receiverProducesRuntimeValue(memberExpr.receiver()) ? 1 : 0;
|
return receiverProducesRuntimeValue(memberExpr.receiver(), context) ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean receiverProducesRuntimeValue(final PbsAst.Expression receiver) {
|
private boolean receiverProducesRuntimeValue(
|
||||||
|
final PbsAst.Expression receiver,
|
||||||
|
final PbsExecutableLoweringContext context) {
|
||||||
return switch (receiver) {
|
return switch (receiver) {
|
||||||
case PbsAst.CallExpr ignored -> true;
|
case PbsAst.CallExpr ignored -> true;
|
||||||
case PbsAst.GroupExpr groupExpr -> receiverProducesRuntimeValue(groupExpr.expression());
|
case PbsAst.IdentifierExpr identifierExpr -> context.resolveLocalSlot(identifierExpr.name()) != null;
|
||||||
|
case PbsAst.GroupExpr groupExpr -> receiverProducesRuntimeValue(groupExpr.expression(), context);
|
||||||
default -> false;
|
default -> false;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,6 +17,7 @@ final class PbsExecutableLoweringContext {
|
|||||||
private final PbsExecutableCallableRegistry callableRegistry;
|
private final PbsExecutableCallableRegistry callableRegistry;
|
||||||
private final IntrinsicTable intrinsicIdTable;
|
private final IntrinsicTable intrinsicIdTable;
|
||||||
private final Map<NameId, Integer> localSlotByNameId;
|
private final Map<NameId, Integer> localSlotByNameId;
|
||||||
|
private final Map<NameId, String> localOwnerByNameId;
|
||||||
private final ArrayList<IRBackendExecutableFunction.Instruction> instructions = new ArrayList<>();
|
private final ArrayList<IRBackendExecutableFunction.Instruction> instructions = new ArrayList<>();
|
||||||
private final ArrayDeque<PbsLoopTargets> loopTargets = new ArrayDeque<>();
|
private final ArrayDeque<PbsLoopTargets> loopTargets = new ArrayDeque<>();
|
||||||
private int nextLabelId = 0;
|
private int nextLabelId = 0;
|
||||||
@ -29,6 +30,7 @@ final class PbsExecutableLoweringContext {
|
|||||||
final PbsExecutableCallableRegistry callableRegistry,
|
final PbsExecutableCallableRegistry callableRegistry,
|
||||||
final IntrinsicTable intrinsicIdTable,
|
final IntrinsicTable intrinsicIdTable,
|
||||||
final Map<NameId, Integer> localSlotByNameId,
|
final Map<NameId, Integer> localSlotByNameId,
|
||||||
|
final Map<NameId, String> localOwnerByNameId,
|
||||||
final int initialLocalSlot) {
|
final int initialLocalSlot) {
|
||||||
this.diagnostics = diagnostics;
|
this.diagnostics = diagnostics;
|
||||||
this.nameTable = nameTable;
|
this.nameTable = nameTable;
|
||||||
@ -36,6 +38,7 @@ final class PbsExecutableLoweringContext {
|
|||||||
this.callableRegistry = callableRegistry;
|
this.callableRegistry = callableRegistry;
|
||||||
this.intrinsicIdTable = intrinsicIdTable;
|
this.intrinsicIdTable = intrinsicIdTable;
|
||||||
this.localSlotByNameId = localSlotByNameId == null ? new HashMap<>() : localSlotByNameId;
|
this.localSlotByNameId = localSlotByNameId == null ? new HashMap<>() : localSlotByNameId;
|
||||||
|
this.localOwnerByNameId = localOwnerByNameId == null ? new HashMap<>() : localOwnerByNameId;
|
||||||
this.nextLocalSlot = Math.max(0, initialLocalSlot);
|
this.nextLocalSlot = Math.max(0, initialLocalSlot);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,6 +58,10 @@ final class PbsExecutableLoweringContext {
|
|||||||
return metadataIndex.builtinConstOwnerByNameId();
|
return metadataIndex.builtinConstOwnerByNameId();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Map<String, String> builtinCanonicalBySourceType() {
|
||||||
|
return metadataIndex.builtinCanonicalBySourceType();
|
||||||
|
}
|
||||||
|
|
||||||
Map<PbsIntrinsicOwnerMethodKey, List<p.studio.compiler.models.IRReservedMetadata.IntrinsicSurface>> intrinsicByOwnerAndMethod() {
|
Map<PbsIntrinsicOwnerMethodKey, List<p.studio.compiler.models.IRReservedMetadata.IntrinsicSurface>> intrinsicByOwnerAndMethod() {
|
||||||
return metadataIndex.intrinsicByOwnerAndMethod();
|
return metadataIndex.intrinsicByOwnerAndMethod();
|
||||||
}
|
}
|
||||||
@ -83,6 +90,27 @@ final class PbsExecutableLoweringContext {
|
|||||||
return localSlotByNameId;
|
return localSlotByNameId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String resolveLocalOwner(final String localName) {
|
||||||
|
if (localName == null || localName.isBlank()) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return localOwnerByNameId.getOrDefault(nameTable.register(localName), "");
|
||||||
|
}
|
||||||
|
|
||||||
|
void bindLocalOwner(
|
||||||
|
final String localName,
|
||||||
|
final String ownerCanonicalName) {
|
||||||
|
if (localName == null || localName.isBlank()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final var nameId = nameTable.register(localName);
|
||||||
|
if (ownerCanonicalName == null || ownerCanonicalName.isBlank()) {
|
||||||
|
localOwnerByNameId.remove(nameId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
localOwnerByNameId.put(nameId, ownerCanonicalName);
|
||||||
|
}
|
||||||
|
|
||||||
Integer resolveLocalSlot(final String localName) {
|
Integer resolveLocalSlot(final String localName) {
|
||||||
if (localName == null || localName.isBlank()) {
|
if (localName == null || localName.isBlank()) {
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@ -42,6 +42,7 @@ public class PbsExecutableLoweringModels {
|
|||||||
|
|
||||||
record PbsExecutableMetadataIndex(
|
record PbsExecutableMetadataIndex(
|
||||||
Map<NameId, List<IRReservedMetadata.HostMethodBinding>> hostByMethodName,
|
Map<NameId, List<IRReservedMetadata.HostMethodBinding>> hostByMethodName,
|
||||||
|
Map<String, String> builtinCanonicalBySourceType,
|
||||||
Map<NameId, String> builtinConstOwnerByNameId,
|
Map<NameId, String> builtinConstOwnerByNameId,
|
||||||
Map<PbsIntrinsicOwnerMethodKey, List<IRReservedMetadata.IntrinsicSurface>> intrinsicByOwnerAndMethod,
|
Map<PbsIntrinsicOwnerMethodKey, List<IRReservedMetadata.IntrinsicSurface>> intrinsicByOwnerAndMethod,
|
||||||
Map<PbsIntrinsicCanonicalKey, String> intrinsicReturnOwnerByCanonical) {
|
Map<PbsIntrinsicCanonicalKey, String> intrinsicReturnOwnerByCanonical) {
|
||||||
|
|||||||
@ -42,6 +42,7 @@ final class PbsExecutableMetadataIndexFactory {
|
|||||||
diagnostics);
|
diagnostics);
|
||||||
return new PbsExecutableMetadataIndex(
|
return new PbsExecutableMetadataIndex(
|
||||||
hostByMethodName,
|
hostByMethodName,
|
||||||
|
builtinCanonicalBySourceType,
|
||||||
builtinConstOwnerByNameId,
|
builtinConstOwnerByNameId,
|
||||||
intrinsicByOwnerAndMethod,
|
intrinsicByOwnerAndMethod,
|
||||||
intrinsicReturnOwnerByCanonical);
|
intrinsicReturnOwnerByCanonical);
|
||||||
|
|||||||
@ -1,10 +1,5 @@
|
|||||||
[BuiltinType(name = "Color", version = 1)]
|
[BuiltinType(name = "Color", version = 1)]
|
||||||
declare builtin type Color(
|
declare builtin type Color(
|
||||||
pub r: int,
|
pub raw: int
|
||||||
pub g: int,
|
|
||||||
pub b: int,
|
|
||||||
pub a: int
|
|
||||||
) {
|
) {
|
||||||
[IntrinsicCall(name = "core.color.pack", version = 1)]
|
|
||||||
fn pack() -> int;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,109 @@
|
|||||||
import { Color } from @core:color;
|
import { Color } from @core:color;
|
||||||
|
|
||||||
declare host Gfx {
|
declare host LowGfx {
|
||||||
[Host(module = "gfx", name = "draw_pixel", version = 1)]
|
[Host(module = "gfx", name = "clear", version = 1)]
|
||||||
[Capability(name = "gfx")]
|
[Capability(name = "gfx")]
|
||||||
fn draw_pixel(x: int, y: int, color: Color) -> void;
|
fn clear(color: Color) -> void;
|
||||||
|
|
||||||
|
[Host(module = "gfx", name = "fill_rect", version = 1)]
|
||||||
|
[Capability(name = "gfx")]
|
||||||
|
fn fill_rect(x: int, y: int, w: int, h: int, color: Color) -> void;
|
||||||
|
|
||||||
|
[Host(module = "gfx", name = "draw_line", version = 1)]
|
||||||
|
[Capability(name = "gfx")]
|
||||||
|
fn draw_line(x1: int, y1: int, x2: int, y2: int, color: Color) -> void;
|
||||||
|
|
||||||
|
[Host(module = "gfx", name = "draw_circle", version = 1)]
|
||||||
|
[Capability(name = "gfx")]
|
||||||
|
fn draw_circle(x: int, y: int, r: int, color: Color) -> void;
|
||||||
|
|
||||||
|
[Host(module = "gfx", name = "draw_disc", version = 1)]
|
||||||
|
[Capability(name = "gfx")]
|
||||||
|
fn draw_disc(x: int, y: int, r: int, border_color: Color, fill_color: Color) -> void;
|
||||||
|
|
||||||
|
[Host(module = "gfx", name = "draw_square", version = 1)]
|
||||||
|
[Capability(name = "gfx")]
|
||||||
|
fn draw_square(x: int, y: int, w: int, h: int, border_color: Color, fill_color: Color) -> void;
|
||||||
|
|
||||||
|
[Host(module = "gfx", name = "set_sprite", version = 1)]
|
||||||
|
[Capability(name = "gfx")]
|
||||||
|
fn set_sprite(
|
||||||
|
asset_name: str,
|
||||||
|
index: int,
|
||||||
|
x: int,
|
||||||
|
y: int,
|
||||||
|
tile_id: int,
|
||||||
|
palette_id: int,
|
||||||
|
active: bool,
|
||||||
|
flip_x: bool,
|
||||||
|
flip_y: bool,
|
||||||
|
priority: int
|
||||||
|
) -> int;
|
||||||
|
|
||||||
|
[Host(module = "gfx", name = "draw_text", version = 1)]
|
||||||
|
[Capability(name = "gfx")]
|
||||||
|
fn draw_text(x: int, y: int, message: str, color: Color) -> void;
|
||||||
|
|
||||||
|
[Host(module = "gfx", name = "clear_565", version = 1)]
|
||||||
|
[Capability(name = "gfx")]
|
||||||
|
fn clear_565(color_565: int) -> void;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare service Gfx
|
||||||
|
{
|
||||||
|
fn clear(color: Color) -> void
|
||||||
|
{
|
||||||
|
LowGfx.clear(color);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fill_rect(x: int, y: int, w: int, h: int, color: Color) -> void
|
||||||
|
{
|
||||||
|
LowGfx.fill_rect(x, y, w, h, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn draw_line(x1: int, y1: int, x2: int, y2: int, color: Color) -> void
|
||||||
|
{
|
||||||
|
LowGfx.draw_line(x1, y1, x2, y2, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn draw_circle(x: int, y: int, r: int, color: Color) -> void
|
||||||
|
{
|
||||||
|
LowGfx.draw_circle(x, y, r, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn draw_disc(x: int, y: int, r: int, border_color: Color, fill_color: Color) -> void
|
||||||
|
{
|
||||||
|
LowGfx.draw_disc(x, y, r, border_color, fill_color);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn draw_square(x: int, y: int, w: int, h: int, border_color: Color, fill_color: Color) -> void
|
||||||
|
{
|
||||||
|
LowGfx.draw_square(x, y, w, h, border_color, fill_color);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_sprite(
|
||||||
|
asset_name: str,
|
||||||
|
index: int,
|
||||||
|
x: int,
|
||||||
|
y: int,
|
||||||
|
tile_id: int,
|
||||||
|
palette_id: int,
|
||||||
|
active: bool,
|
||||||
|
flip_x: bool,
|
||||||
|
flip_y: bool,
|
||||||
|
priority: int
|
||||||
|
) -> int
|
||||||
|
{
|
||||||
|
return LowGfx.set_sprite(asset_name, index, x, y, tile_id, palette_id, active, flip_x, flip_y, priority);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn draw_text(x: int, y: int, message: str, color: Color) -> void
|
||||||
|
{
|
||||||
|
LowGfx.draw_text(x, y, message, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clear_565(color_565: int) -> void
|
||||||
|
{
|
||||||
|
LowGfx.clear_565(color_565);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1 +1,2 @@
|
|||||||
pub host Gfx;
|
mod host LowGfx;
|
||||||
|
pub service Gfx;
|
||||||
|
|||||||
@ -304,12 +304,8 @@ class PbsFrontendCompilerTest {
|
|||||||
final var source = """
|
final var source = """
|
||||||
[BuiltinType(name = "Color", version = 1)]
|
[BuiltinType(name = "Color", version = 1)]
|
||||||
declare builtin type Color(
|
declare builtin type Color(
|
||||||
pub r: int,
|
pub raw: int
|
||||||
pub g: int,
|
|
||||||
pub b: int
|
|
||||||
) {
|
) {
|
||||||
[IntrinsicCall(name = "core.color.pack")]
|
|
||||||
fn pack() -> int;
|
|
||||||
}
|
}
|
||||||
declare host Gfx {
|
declare host Gfx {
|
||||||
[Host(module = "gfx", name = "draw_pixel", version = 1)]
|
[Host(module = "gfx", name = "draw_pixel", version = 1)]
|
||||||
@ -332,7 +328,7 @@ class PbsFrontendCompilerTest {
|
|||||||
assertEquals(1, fileBackend.reservedMetadata().requiredCapabilities().size());
|
assertEquals(1, fileBackend.reservedMetadata().requiredCapabilities().size());
|
||||||
assertEquals("gfx", fileBackend.reservedMetadata().requiredCapabilities().getFirst());
|
assertEquals("gfx", fileBackend.reservedMetadata().requiredCapabilities().getFirst());
|
||||||
assertEquals("Color", fileBackend.reservedMetadata().builtinTypeSurfaces().getFirst().canonicalTypeName());
|
assertEquals("Color", fileBackend.reservedMetadata().builtinTypeSurfaces().getFirst().canonicalTypeName());
|
||||||
assertEquals(3, fileBackend.reservedMetadata().builtinTypeSurfaces().getFirst().fields().size());
|
assertEquals(1, fileBackend.reservedMetadata().builtinTypeSurfaces().getFirst().fields().size());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -453,10 +449,7 @@ class PbsFrontendCompilerTest {
|
|||||||
final var source = """
|
final var source = """
|
||||||
[BuiltinType(name = "Color", version = 1)]
|
[BuiltinType(name = "Color", version = 1)]
|
||||||
declare builtin type Color(
|
declare builtin type Color(
|
||||||
pub r: int,
|
pub raw: int
|
||||||
pub g: int,
|
|
||||||
pub b: int,
|
|
||||||
pub a: int
|
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -116,7 +116,10 @@ class PbsGateUSdkInterfaceConformanceTest {
|
|||||||
.anyMatch(t -> t.sourceTypeName().equals("InputButton")
|
.anyMatch(t -> t.sourceTypeName().equals("InputButton")
|
||||||
&& t.intrinsics().stream().anyMatch(i -> i.canonicalName().equals("input.button.hold"))));
|
&& t.intrinsics().stream().anyMatch(i -> i.canonicalName().equals("input.button.hold"))));
|
||||||
assertTrue(positive.irBackend().getReservedMetadata().hostMethodBindings().stream()
|
assertTrue(positive.irBackend().getReservedMetadata().hostMethodBindings().stream()
|
||||||
.anyMatch(h -> h.ownerName().equals("Gfx")));
|
.anyMatch(h -> h.ownerName().equals("LowGfx")
|
||||||
|
&& h.abiModule().equals("gfx")
|
||||||
|
&& h.abiMethod().equals("clear")
|
||||||
|
&& h.abiVersion() == 1));
|
||||||
assertTrue(positive.irBackend().getReservedMetadata().hostMethodBindings().stream()
|
assertTrue(positive.irBackend().getReservedMetadata().hostMethodBindings().stream()
|
||||||
.anyMatch(h -> h.ownerName().equals("LowLog")
|
.anyMatch(h -> h.ownerName().equals("LowLog")
|
||||||
&& h.abiModule().equals("log")
|
&& h.abiModule().equals("log")
|
||||||
|
|||||||
@ -525,7 +525,7 @@ class PBSFrontendPhaseServiceTest {
|
|||||||
d.getCode().equals(PbsLinkErrors.E_LINK_IMPORT_SYMBOL_NOT_PUBLIC.name())));
|
d.getCode().equals(PbsLinkErrors.E_LINK_IMPORT_SYMBOL_NOT_PUBLIC.name())));
|
||||||
assertEquals(0, irBackend.getFunctions().size());
|
assertEquals(0, irBackend.getFunctions().size());
|
||||||
assertTrue(irBackend.getReservedMetadata().builtinTypeSurfaces().stream()
|
assertTrue(irBackend.getReservedMetadata().builtinTypeSurfaces().stream()
|
||||||
.anyMatch(t -> t.sourceTypeName().equals("Color") && t.fields().size() == 4));
|
.anyMatch(t -> t.sourceTypeName().equals("Color") && t.fields().size() == 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -578,7 +578,56 @@ class PBSFrontendPhaseServiceTest {
|
|||||||
d.getCode().equals(PbsLinkErrors.E_LINK_IMPORT_SYMBOL_NOT_PUBLIC.name())));
|
d.getCode().equals(PbsLinkErrors.E_LINK_IMPORT_SYMBOL_NOT_PUBLIC.name())));
|
||||||
assertEquals(0, irBackend.getFunctions().size());
|
assertEquals(0, irBackend.getFunctions().size());
|
||||||
assertTrue(irBackend.getReservedMetadata().hostMethodBindings().stream()
|
assertTrue(irBackend.getReservedMetadata().hostMethodBindings().stream()
|
||||||
.anyMatch(h -> h.ownerName().equals("Gfx") && h.sourceMethodName().equals("draw_pixel")));
|
.anyMatch(h -> h.ownerName().equals("LowGfx") && h.sourceMethodName().equals("clear")));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldLowerSdkGfxServiceFacadeCallsWithoutHostCallableAmbiguity() throws IOException {
|
||||||
|
final var projectRoot = tempDir.resolve("project-bootstrap-sdk-gfx-facade-call");
|
||||||
|
final var sourceRoot = projectRoot.resolve("src");
|
||||||
|
final var modulePath = sourceRoot.resolve("app");
|
||||||
|
Files.createDirectories(modulePath);
|
||||||
|
|
||||||
|
final var sourceFile = modulePath.resolve("source.pbs");
|
||||||
|
final var modBarrel = modulePath.resolve("mod.barrel");
|
||||||
|
Files.writeString(sourceFile, """
|
||||||
|
import { Gfx } from @sdk:gfx;
|
||||||
|
|
||||||
|
fn frame() -> void
|
||||||
|
{
|
||||||
|
Gfx.clear_565(6577);
|
||||||
|
}
|
||||||
|
""");
|
||||||
|
Files.writeString(modBarrel, "pub fn frame() -> void;");
|
||||||
|
|
||||||
|
final var projectTable = new ProjectTable();
|
||||||
|
final var fileTable = new FileTable(1);
|
||||||
|
final var projectId = projectTable.register(ProjectDescriptor.builder()
|
||||||
|
.rootPath(projectRoot)
|
||||||
|
.name("app")
|
||||||
|
.version("1.0.0")
|
||||||
|
.sourceRoots(ReadOnlyList.wrap(List.of(sourceRoot)))
|
||||||
|
.build());
|
||||||
|
|
||||||
|
registerFile(projectId, projectRoot, sourceFile, fileTable);
|
||||||
|
registerFile(projectId, projectRoot, modBarrel, fileTable);
|
||||||
|
|
||||||
|
final var ctx = new FrontendPhaseContext(
|
||||||
|
projectTable,
|
||||||
|
fileTable,
|
||||||
|
new BuildStack(ReadOnlyList.wrap(List.of(projectId))),
|
||||||
|
1);
|
||||||
|
final var diagnostics = DiagnosticSink.empty();
|
||||||
|
|
||||||
|
final var irBackend = new PBSFrontendPhaseService().compile(
|
||||||
|
ctx,
|
||||||
|
diagnostics,
|
||||||
|
LogAggregator.empty(),
|
||||||
|
BuildingIssueSink.empty());
|
||||||
|
|
||||||
|
assertTrue(diagnostics.stream().noneMatch(d ->
|
||||||
|
d.getCode().equals(PbsSemanticsErrors.E_SEM_EXEC_LOWERING_UNRESOLVED_CALLEE.name())));
|
||||||
|
assertTrue(irBackend.getExecutableFunctions().stream().anyMatch(function -> "frame".equals(function.callableName())));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -1008,6 +1057,69 @@ class PBSFrontendPhaseServiceTest {
|
|||||||
assertTrue(intrinsicCalls.contains("input.touch.x"));
|
assertTrue(intrinsicCalls.contains("input.touch.x"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldResolveIntrinsicCallsOnBuiltinValuesStoredInLocals() throws IOException {
|
||||||
|
final var projectRoot = tempDir.resolve("project-intrinsic-local-builtin-receiver");
|
||||||
|
final var sourceRoot = projectRoot.resolve("src");
|
||||||
|
Files.createDirectories(sourceRoot);
|
||||||
|
|
||||||
|
final var sourceFile = sourceRoot.resolve("main.pbs");
|
||||||
|
final var modBarrel = sourceRoot.resolve("mod.barrel");
|
||||||
|
Files.writeString(sourceFile, """
|
||||||
|
import { Input } from @sdk:input;
|
||||||
|
|
||||||
|
fn frame() -> void
|
||||||
|
{
|
||||||
|
let touch = Input.touch();
|
||||||
|
touch.x();
|
||||||
|
touch.y();
|
||||||
|
}
|
||||||
|
""");
|
||||||
|
Files.writeString(modBarrel, "pub fn frame() -> void;");
|
||||||
|
|
||||||
|
final var projectTable = new ProjectTable();
|
||||||
|
final var fileTable = new FileTable(1);
|
||||||
|
final var projectId = projectTable.register(ProjectDescriptor.builder()
|
||||||
|
.rootPath(projectRoot)
|
||||||
|
.name("main")
|
||||||
|
.version("1.0.0")
|
||||||
|
.sourceRoots(ReadOnlyList.wrap(List.of(sourceRoot)))
|
||||||
|
.build());
|
||||||
|
|
||||||
|
registerFile(projectId, projectRoot, sourceFile, fileTable);
|
||||||
|
registerFile(projectId, projectRoot, modBarrel, fileTable);
|
||||||
|
|
||||||
|
final var ctx = new FrontendPhaseContext(
|
||||||
|
projectTable,
|
||||||
|
fileTable,
|
||||||
|
new BuildStack(ReadOnlyList.wrap(List.of(projectId))),
|
||||||
|
1);
|
||||||
|
final var diagnostics = DiagnosticSink.empty();
|
||||||
|
|
||||||
|
final var irBackend = new PBSFrontendPhaseService().compile(
|
||||||
|
ctx,
|
||||||
|
diagnostics,
|
||||||
|
LogAggregator.empty(),
|
||||||
|
BuildingIssueSink.empty());
|
||||||
|
|
||||||
|
assertTrue(diagnostics.stream().noneMatch(d ->
|
||||||
|
d.getCode().equals(PbsSemanticsErrors.E_SEM_EXEC_LOWERING_UNRESOLVED_CALLEE.name())),
|
||||||
|
diagnostics.stream().map(d -> d.getCode() + ":" + d.getMessage()).toList().toString());
|
||||||
|
final var frameExecutable = irBackend.getExecutableFunctions().stream()
|
||||||
|
.filter(function -> "frame".equals(function.callableName()))
|
||||||
|
.findFirst()
|
||||||
|
.orElseThrow();
|
||||||
|
final var intrinsicCalls = frameExecutable.instructions().stream()
|
||||||
|
.filter(instruction ->
|
||||||
|
instruction.kind() == p.studio.compiler.models.IRBackendExecutableFunction.InstructionKind.CALL_INTRINSIC
|
||||||
|
&& instruction.intrinsicCall() != null)
|
||||||
|
.map(instruction -> instruction.intrinsicCall().canonicalName())
|
||||||
|
.toList();
|
||||||
|
assertTrue(intrinsicCalls.contains("input.touch"));
|
||||||
|
assertTrue(intrinsicCalls.contains("input.touch.x"));
|
||||||
|
assertTrue(intrinsicCalls.contains("input.touch.y"));
|
||||||
|
}
|
||||||
|
|
||||||
private void registerFile(
|
private void registerFile(
|
||||||
final ProjectId projectId,
|
final ProjectId projectId,
|
||||||
final Path projectRoot,
|
final Path projectRoot,
|
||||||
|
|||||||
@ -32,6 +32,7 @@ public record IRReservedMetadata(
|
|||||||
String abiModule,
|
String abiModule,
|
||||||
String abiMethod,
|
String abiMethod,
|
||||||
long abiVersion,
|
long abiVersion,
|
||||||
|
int retSlots,
|
||||||
boolean capabilityDeclared,
|
boolean capabilityDeclared,
|
||||||
String requiredCapability,
|
String requiredCapability,
|
||||||
Span span) {
|
Span span) {
|
||||||
@ -40,6 +41,9 @@ public record IRReservedMetadata(
|
|||||||
sourceMethodName = Objects.requireNonNull(sourceMethodName, "sourceMethodName");
|
sourceMethodName = Objects.requireNonNull(sourceMethodName, "sourceMethodName");
|
||||||
abiModule = Objects.requireNonNull(abiModule, "abiModule");
|
abiModule = Objects.requireNonNull(abiModule, "abiModule");
|
||||||
abiMethod = Objects.requireNonNull(abiMethod, "abiMethod");
|
abiMethod = Objects.requireNonNull(abiMethod, "abiMethod");
|
||||||
|
if (retSlots < 0) {
|
||||||
|
throw new IllegalArgumentException("host retSlots must be non-negative");
|
||||||
|
}
|
||||||
requiredCapability = requiredCapability == null ? "" : requiredCapability;
|
requiredCapability = requiredCapability == null ? "" : requiredCapability;
|
||||||
span = Objects.requireNonNull(span, "span");
|
span = Objects.requireNonNull(span, "span");
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,5 +6,5 @@
|
|||||||
"app_version": "0.1.0",
|
"app_version": "0.1.0",
|
||||||
"app_mode": "Game",
|
"app_mode": "Game",
|
||||||
"entrypoint": "0",
|
"entrypoint": "0",
|
||||||
"capabilities": ["log"]
|
"capabilities": ["log", "gfx"]
|
||||||
}
|
}
|
||||||
|
|||||||
Binary file not shown.
@ -1,8 +1,16 @@
|
|||||||
|
import { Color } from @core:color;
|
||||||
|
|
||||||
import { Log } from @sdk:log;
|
import { Log } from @sdk:log;
|
||||||
import { Input } from @sdk:input;
|
import { Input } from @sdk:input;
|
||||||
|
import { Gfx } from @sdk:gfx;
|
||||||
|
|
||||||
fn frame() -> void
|
fn frame() -> void
|
||||||
{
|
{
|
||||||
|
let touch = Input.touch();
|
||||||
|
|
||||||
|
Gfx.clear(new Color(6577));
|
||||||
|
Gfx.draw_square(touch.x() - 8, touch.y() - 8, 16, 16, new Color(65535), new Color(13271));
|
||||||
|
|
||||||
let a = 10;
|
let a = 10;
|
||||||
let b = 15;
|
let b = 15;
|
||||||
let total = a + b;
|
let total = a + b;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user