diff --git a/prometeu-compiler/frontends/prometeu-frontend-pbs/src/main/java/p/studio/compiler/services/PBSFrontendPhaseService.java b/prometeu-compiler/frontends/prometeu-frontend-pbs/src/main/java/p/studio/compiler/services/PBSFrontendPhaseService.java index fa920652..e41d9017 100644 --- a/prometeu-compiler/frontends/prometeu-frontend-pbs/src/main/java/p/studio/compiler/services/PBSFrontendPhaseService.java +++ b/prometeu-compiler/frontends/prometeu-frontend-pbs/src/main/java/p/studio/compiler/services/PBSFrontendPhaseService.java @@ -240,9 +240,19 @@ public class PBSFrontendPhaseService implements FrontendPhaseService { && entryPointCallableName != null && !entryPointCallableName.isBlank() && !entryPointModuleId.isNone()) { + final var existingBootGuard = globals.stream() + .filter(global -> moduleIdsMatch(entryPointModuleId, global.moduleId())) + .filter(global -> global.hiddenKind() == IRHiddenGlobalKind.BOOT_GUARD) + .findFirst() + .orElse(null); + final var bootGuardSlot = existingBootGuard != null + ? existingBootGuard.slot() + : nextGlobalSlot(globals, entryPointModuleId); final var wrapperCallableId = new CallableId(callableSignatures.size()); callableSignatures.add(new CallableSignatureRef(entryPointModuleId, entryPointCallableName, 0, "() -> unit")); final var instructions = new ArrayList(); + instructions.add(getGlobalInstruction(bootGuardSlot, frameExecutable.span())); + instructions.add(jumpIfTrueInstruction("bootstrap_done", frameExecutable.span())); for (final var moduleId : sortedModuleIds) { final var moduleInitCallableId = moduleInitCallableIds.get(moduleId); if (moduleInitCallableId == null) { @@ -271,6 +281,9 @@ public class PBSFrontendPhaseService implements FrontendPhaseService { 0, frameExecutable.span())); } + instructions.add(pushBoolInstruction(true, frameExecutable.span())); + instructions.add(setGlobalInstruction(bootGuardSlot, frameExecutable.span())); + instructions.add(labelInstruction("bootstrap_done", frameExecutable.span())); instructions.add(callInstruction(frameExecutable, frameExecutable.span())); instructions.add(retInstruction(frameExecutable.span())); executableFunctions.add(new IRBackendExecutableFunction( @@ -287,15 +300,13 @@ public class PBSFrontendPhaseService implements FrontendPhaseService { ReadOnlyList.wrap(instructions), frameExecutable.span())); - if (globals.stream().noneMatch(global -> - moduleIdsMatch(entryPointModuleId, global.moduleId()) - && global.hiddenKind() == IRHiddenGlobalKind.BOOT_GUARD)) { + if (existingBootGuard == null) { globals.add(new IRGlobal( frameExecutable.fileId(), entryPointModuleId, PbsFrontendCompiler.bootGuardGlobalName(entryPointModuleId), "bool", - 0, + bootGuardSlot, IRGlobalVisibility.MODULE, true, IRHiddenGlobalKind.BOOT_GUARD, @@ -325,6 +336,19 @@ public class PBSFrontendPhaseService implements FrontendPhaseService { .build(); } + private int nextGlobalSlot( + final ArrayList globals, + final ModuleId moduleId) { + var nextSlot = 0; + for (final var global : globals) { + if (!moduleIdsMatch(moduleId, global.moduleId())) { + continue; + } + nextSlot = Math.max(nextSlot, global.slot() + 1); + } + return nextSlot; + } + private ArrayList normalizeGlobalSlots(final ArrayList globals) { final var nextSlotByModule = new LinkedHashMap(); final var normalized = new ArrayList(globals.size()); @@ -390,6 +414,82 @@ public class PBSFrontendPhaseService implements FrontendPhaseService { span); } + private IRBackendExecutableFunction.Instruction getGlobalInstruction( + final int slot, + final Span span) { + return new IRBackendExecutableFunction.Instruction( + IRBackendExecutableFunction.InstructionKind.GET_GLOBAL, + "", + null, + null, + null, + slot, + null, + span); + } + + private IRBackendExecutableFunction.Instruction setGlobalInstruction( + final int slot, + final Span span) { + return new IRBackendExecutableFunction.Instruction( + IRBackendExecutableFunction.InstructionKind.SET_GLOBAL, + "", + null, + null, + null, + slot, + null, + span); + } + + private IRBackendExecutableFunction.Instruction pushBoolInstruction( + final boolean value, + final Span span) { + return new IRBackendExecutableFunction.Instruction( + IRBackendExecutableFunction.InstructionKind.PUSH_BOOL, + "", + null, + null, + null, + value ? "true" : "false", + null, + null, + null, + span); + } + + private IRBackendExecutableFunction.Instruction labelInstruction( + final String label, + final Span span) { + return new IRBackendExecutableFunction.Instruction( + IRBackendExecutableFunction.InstructionKind.LABEL, + "", + null, + null, + null, + label, + null, + null, + null, + span); + } + + private IRBackendExecutableFunction.Instruction jumpIfTrueInstruction( + final String targetLabel, + final Span span) { + return new IRBackendExecutableFunction.Instruction( + IRBackendExecutableFunction.InstructionKind.JMP_IF_TRUE, + "", + null, + null, + null, + null, + targetLabel, + null, + null, + span); + } + private ModuleId normalizeModuleId(final ModuleId moduleId) { return moduleId == null ? ModuleId.none() : moduleId; } diff --git a/prometeu-compiler/frontends/prometeu-frontend-pbs/src/test/java/p/studio/compiler/services/PBSFrontendPhaseServiceTest.java b/prometeu-compiler/frontends/prometeu-frontend-pbs/src/test/java/p/studio/compiler/services/PBSFrontendPhaseServiceTest.java index 1d2d6e34..ac6ab486 100644 --- a/prometeu-compiler/frontends/prometeu-frontend-pbs/src/test/java/p/studio/compiler/services/PBSFrontendPhaseServiceTest.java +++ b/prometeu-compiler/frontends/prometeu-frontend-pbs/src/test/java/p/studio/compiler/services/PBSFrontendPhaseServiceTest.java @@ -369,15 +369,21 @@ class PBSFrontendPhaseServiceTest { .orElseThrow(); assertTrue(bootGuard.isHidden()); assertTrue(bootGuard.name().startsWith("__pbs.boot_guard$m")); + assertEquals(1, bootGuard.slot()); final var wrapper = irBackend.getExecutableFunctions().stream() .filter(function -> irBackend.getEntryPointCallableName().equals(function.callableName())) .findFirst() .orElseThrow(); - assertEquals(4, wrapper.instructions().size()); - assertTrue(wrapper.instructions().get(0).calleeCallableName().startsWith("__pbs.module_init$m")); - assertTrue(wrapper.instructions().get(1).calleeCallableName().startsWith("__pbs.project_init$m")); - assertEquals("frame", wrapper.instructions().get(2).calleeCallableName()); - assertEquals(p.studio.compiler.models.IRBackendExecutableFunction.InstructionKind.RET, wrapper.instructions().get(3).kind()); + assertEquals(9, wrapper.instructions().size()); + assertEquals(p.studio.compiler.models.IRBackendExecutableFunction.InstructionKind.GET_GLOBAL, wrapper.instructions().get(0).kind()); + assertEquals(p.studio.compiler.models.IRBackendExecutableFunction.InstructionKind.JMP_IF_TRUE, wrapper.instructions().get(1).kind()); + assertTrue(wrapper.instructions().get(2).calleeCallableName().startsWith("__pbs.module_init$m")); + assertTrue(wrapper.instructions().get(3).calleeCallableName().startsWith("__pbs.project_init$m")); + assertEquals(p.studio.compiler.models.IRBackendExecutableFunction.InstructionKind.PUSH_BOOL, wrapper.instructions().get(4).kind()); + assertEquals(p.studio.compiler.models.IRBackendExecutableFunction.InstructionKind.SET_GLOBAL, wrapper.instructions().get(5).kind()); + assertEquals(p.studio.compiler.models.IRBackendExecutableFunction.InstructionKind.LABEL, wrapper.instructions().get(6).kind()); + assertEquals("frame", wrapper.instructions().get(7).calleeCallableName()); + assertEquals(p.studio.compiler.models.IRBackendExecutableFunction.InstructionKind.RET, wrapper.instructions().get(8).kind()); } @Test diff --git a/prometeu-compiler/prometeu-build-pipeline/src/main/java/p/studio/compiler/backend/bytecode/BytecodeEmitter.java b/prometeu-compiler/prometeu-build-pipeline/src/main/java/p/studio/compiler/backend/bytecode/BytecodeEmitter.java index a1dcb6fd..96359c59 100644 --- a/prometeu-compiler/prometeu-build-pipeline/src/main/java/p/studio/compiler/backend/bytecode/BytecodeEmitter.java +++ b/prometeu-compiler/prometeu-build-pipeline/src/main/java/p/studio/compiler/backend/bytecode/BytecodeEmitter.java @@ -35,6 +35,8 @@ public class BytecodeEmitter { private static final int OP_LTE = 0x3C; private static final int OP_GTE = 0x3D; private static final int OP_NEG = 0x3E; + private static final int OP_GET_GLOBAL = 0x40; + private static final int OP_SET_GLOBAL = 0x41; private static final int OP_GET_LOCAL = 0x42; private static final int OP_SET_LOCAL = 0x43; private static final int OP_PUSH_I32 = 0x17; @@ -81,10 +83,18 @@ public class BytecodeEmitter { writeOpU32(code, OP_GET_LOCAL, op.immediate()); spans.add(new BytecodeFunctionLayoutBuilder.InstructionSpan(pc, spanOrUnknown(op.span()))); } + case GET_GLOBAL -> { + writeOpU32(code, OP_GET_GLOBAL, op.immediate()); + spans.add(new BytecodeFunctionLayoutBuilder.InstructionSpan(pc, spanOrUnknown(op.span()))); + } case SET_LOCAL -> { writeOpU32(code, OP_SET_LOCAL, op.immediate()); spans.add(new BytecodeFunctionLayoutBuilder.InstructionSpan(pc, spanOrUnknown(op.span()))); } + case SET_GLOBAL -> { + writeOpU32(code, OP_SET_GLOBAL, op.immediate()); + spans.add(new BytecodeFunctionLayoutBuilder.InstructionSpan(pc, spanOrUnknown(op.span()))); + } case PUSH_BOOL -> { writeOpU8(code, OP_PUSH_BOOL, op.immediate() == 0 ? 0 : 1); spans.add(new BytecodeFunctionLayoutBuilder.InstructionSpan(pc, spanOrUnknown(op.span()))); @@ -307,7 +317,9 @@ public class BytecodeEmitter { PUSH_CONST, POP, GET_LOCAL, + GET_GLOBAL, SET_LOCAL, + SET_GLOBAL, PUSH_BOOL, PUSH_I32, ADD, @@ -397,10 +409,18 @@ public class BytecodeEmitter { return new Operation(OperationKind.GET_LOCAL, slot, null, null, null, span); } + public static Operation getGlobal(final int slot, final BytecodeModule.SourceSpan span) { + return new Operation(OperationKind.GET_GLOBAL, slot, null, null, null, span); + } + public static Operation setLocal(final int slot, final BytecodeModule.SourceSpan span) { return new Operation(OperationKind.SET_LOCAL, slot, null, null, null, span); } + public static Operation setGlobal(final int slot, final BytecodeModule.SourceSpan span) { + return new Operation(OperationKind.SET_GLOBAL, slot, null, null, null, span); + } + public static Operation pushBool(final boolean value, final BytecodeModule.SourceSpan span) { return new Operation(OperationKind.PUSH_BOOL, value ? 1 : 0, null, null, null, span); } diff --git a/prometeu-compiler/prometeu-build-pipeline/src/main/java/p/studio/compiler/backend/irvm/IRVMOp.java b/prometeu-compiler/prometeu-build-pipeline/src/main/java/p/studio/compiler/backend/irvm/IRVMOp.java index 93fecbce..e94390b7 100644 --- a/prometeu-compiler/prometeu-build-pipeline/src/main/java/p/studio/compiler/backend/irvm/IRVMOp.java +++ b/prometeu-compiler/prometeu-build-pipeline/src/main/java/p/studio/compiler/backend/irvm/IRVMOp.java @@ -37,6 +37,8 @@ public record IRVMOp( public static final IRVMOp LTE = new IRVMOp("LTE", 0x3C, 0, 2, 1, false, false, false); public static final IRVMOp GTE = new IRVMOp("GTE", 0x3D, 0, 2, 1, false, false, false); public static final IRVMOp NEG = new IRVMOp("NEG", 0x3E, 0, 1, 1, false, false, false); + public static final IRVMOp GET_GLOBAL = new IRVMOp("GET_GLOBAL", 0x40, 4, 0, 1, false, false, false); + public static final IRVMOp SET_GLOBAL = new IRVMOp("SET_GLOBAL", 0x41, 4, 1, 0, false, false, false); public static final IRVMOp GET_LOCAL = new IRVMOp("GET_LOCAL", 0x42, 4, 0, 1, false, false, false); public static final IRVMOp SET_LOCAL = new IRVMOp("SET_LOCAL", 0x43, 4, 1, 0, false, false, false); public static final IRVMOp INTERNAL_EXT = new IRVMOp("IRVM_EXT_NOP", 0xFFFF, 0, 0, 0, false, false, true); diff --git a/prometeu-compiler/prometeu-build-pipeline/src/main/java/p/studio/compiler/backend/irvm/IRVMProfileFeatureGate.java b/prometeu-compiler/prometeu-build-pipeline/src/main/java/p/studio/compiler/backend/irvm/IRVMProfileFeatureGate.java index 213820eb..e4c17499 100644 --- a/prometeu-compiler/prometeu-build-pipeline/src/main/java/p/studio/compiler/backend/irvm/IRVMProfileFeatureGate.java +++ b/prometeu-compiler/prometeu-build-pipeline/src/main/java/p/studio/compiler/backend/irvm/IRVMProfileFeatureGate.java @@ -13,7 +13,9 @@ public final class IRVMProfileFeatureGate { IRVMOp.RET, IRVMOp.PUSH_CONST, IRVMOp.POP, + IRVMOp.GET_GLOBAL, IRVMOp.GET_LOCAL, + IRVMOp.SET_GLOBAL, IRVMOp.SET_LOCAL, IRVMOp.CALL, IRVMOp.JMP, @@ -43,7 +45,9 @@ public final class IRVMProfileFeatureGate { IRVMOp.RET, IRVMOp.PUSH_CONST, IRVMOp.POP, + IRVMOp.GET_GLOBAL, IRVMOp.GET_LOCAL, + IRVMOp.SET_GLOBAL, IRVMOp.SET_LOCAL, IRVMOp.CALL, IRVMOp.JMP, diff --git a/prometeu-compiler/prometeu-build-pipeline/src/main/java/p/studio/compiler/backend/irvm/IRVMProgram.java b/prometeu-compiler/prometeu-build-pipeline/src/main/java/p/studio/compiler/backend/irvm/IRVMProgram.java index 070c828f..e0d59147 100644 --- a/prometeu-compiler/prometeu-build-pipeline/src/main/java/p/studio/compiler/backend/irvm/IRVMProgram.java +++ b/prometeu-compiler/prometeu-build-pipeline/src/main/java/p/studio/compiler/backend/irvm/IRVMProgram.java @@ -94,7 +94,9 @@ public record IRVMProgram( case 0x10 -> operation.kind() == BytecodeEmitter.OperationKind.PUSH_CONST && operation.immediate() == immediate; case 0x11 -> operation.kind() == BytecodeEmitter.OperationKind.POP; case 0x16 -> operation.kind() == BytecodeEmitter.OperationKind.PUSH_BOOL; + case 0x40 -> operation.kind() == BytecodeEmitter.OperationKind.GET_GLOBAL && operation.immediate() == immediate; case 0x42 -> operation.kind() == BytecodeEmitter.OperationKind.GET_LOCAL && operation.immediate() == immediate; + case 0x41 -> operation.kind() == BytecodeEmitter.OperationKind.SET_GLOBAL && operation.immediate() == immediate; case 0x43 -> operation.kind() == BytecodeEmitter.OperationKind.SET_LOCAL && operation.immediate() == immediate; case 0x17 -> operation.kind() == BytecodeEmitter.OperationKind.PUSH_I32 && operation.immediate() == immediate; case 0x20 -> operation.kind() == BytecodeEmitter.OperationKind.ADD; @@ -176,7 +178,9 @@ public record IRVMProgram( case 0x10 -> BytecodeEmitter.Operation.pushConst(immediate, null); case 0x11 -> BytecodeEmitter.Operation.pop(null); case 0x16 -> BytecodeEmitter.Operation.pushBool(immediate != 0, null); + case 0x40 -> BytecodeEmitter.Operation.getGlobal(immediate, null); case 0x42 -> BytecodeEmitter.Operation.getLocal(immediate, null); + case 0x41 -> BytecodeEmitter.Operation.setGlobal(immediate, null); case 0x43 -> BytecodeEmitter.Operation.setLocal(immediate, null); case 0x17 -> BytecodeEmitter.Operation.pushI32(immediate, null); case 0x20 -> BytecodeEmitter.Operation.add(null); @@ -248,7 +252,9 @@ public record IRVMProgram( case PUSH_CONST -> new IRVMInstruction(IRVMOp.PUSH_CONST, operation.immediate()); case POP -> new IRVMInstruction(IRVMOp.POP, null); case PUSH_BOOL -> new IRVMInstruction(IRVMOp.PUSH_BOOL, operation.immediate()); + case GET_GLOBAL -> new IRVMInstruction(IRVMOp.GET_GLOBAL, operation.immediate()); case GET_LOCAL -> new IRVMInstruction(IRVMOp.GET_LOCAL, operation.immediate()); + case SET_GLOBAL -> new IRVMInstruction(IRVMOp.SET_GLOBAL, operation.immediate()); case SET_LOCAL -> new IRVMInstruction(IRVMOp.SET_LOCAL, operation.immediate()); case PUSH_I32 -> new IRVMInstruction(IRVMOp.PUSH_I32, operation.immediate()); case ADD -> new IRVMInstruction(IRVMOp.ADD, null); diff --git a/prometeu-compiler/prometeu-build-pipeline/src/main/java/p/studio/compiler/backend/irvm/LowerToIRVMService.java b/prometeu-compiler/prometeu-build-pipeline/src/main/java/p/studio/compiler/backend/irvm/LowerToIRVMService.java index b22394d0..bfc62e20 100644 --- a/prometeu-compiler/prometeu-build-pipeline/src/main/java/p/studio/compiler/backend/irvm/LowerToIRVMService.java +++ b/prometeu-compiler/prometeu-build-pipeline/src/main/java/p/studio/compiler/backend/irvm/LowerToIRVMService.java @@ -124,6 +124,19 @@ public class LowerToIRVMService { operations.add(BytecodeEmitter.Operation.getLocal(slot, sourceSpan)); functionPc += IRVMOp.GET_LOCAL.immediateSize() + 2; } + case GET_GLOBAL -> { + final var slot = instr.expectedArgSlots(); + if (slot == null) { + throw loweringError( + fn, + instr, + IRVMLoweringErrorCode.LOWER_IRVM_MISSING_CALLEE, + "missing global slot for GET_GLOBAL"); + } + instructions.add(new IRVMInstruction(IRVMOp.GET_GLOBAL, slot)); + operations.add(BytecodeEmitter.Operation.getGlobal(slot, sourceSpan)); + functionPc += IRVMOp.GET_GLOBAL.immediateSize() + 2; + } case SET_LOCAL -> { final var slot = instr.expectedArgSlots(); if (slot == null) { @@ -137,6 +150,19 @@ public class LowerToIRVMService { operations.add(BytecodeEmitter.Operation.setLocal(slot, sourceSpan)); functionPc += IRVMOp.SET_LOCAL.immediateSize() + 2; } + case SET_GLOBAL -> { + final var slot = instr.expectedArgSlots(); + if (slot == null) { + throw loweringError( + fn, + instr, + IRVMLoweringErrorCode.LOWER_IRVM_MISSING_CALLEE, + "missing global slot for SET_GLOBAL"); + } + instructions.add(new IRVMInstruction(IRVMOp.SET_GLOBAL, slot)); + operations.add(BytecodeEmitter.Operation.setGlobal(slot, sourceSpan)); + functionPc += IRVMOp.SET_GLOBAL.immediateSize() + 2; + } case POP -> { instructions.add(new IRVMInstruction(IRVMOp.POP, null)); operations.add(BytecodeEmitter.Operation.pop(sourceSpan)); diff --git a/prometeu-compiler/prometeu-build-pipeline/src/test/java/p/studio/compiler/backend/irvm/LowerToIRVMServiceTest.java b/prometeu-compiler/prometeu-build-pipeline/src/test/java/p/studio/compiler/backend/irvm/LowerToIRVMServiceTest.java index 44129153..cae2b32a 100644 --- a/prometeu-compiler/prometeu-build-pipeline/src/test/java/p/studio/compiler/backend/irvm/LowerToIRVMServiceTest.java +++ b/prometeu-compiler/prometeu-build-pipeline/src/test/java/p/studio/compiler/backend/irvm/LowerToIRVMServiceTest.java @@ -86,8 +86,13 @@ class LowerToIRVMServiceTest { fn("boot", "app", 10, ReadOnlyList.from(ret())), fn("frame", "app", 20, ReadOnlyList.from(ret())), fn("__pbs.frame_wrapper$m0", "app", 40, ReadOnlyList.from( + getGlobal(0), + jmpIfTrue("bootstrap_done"), callFunc("app", "__pbs.module_init$m0", 31), callFunc("app", "__pbs.project_init$m0", 32), + pushBool(true), + setGlobal(0), + label("bootstrap_done"), callFunc("app", "frame", 20), ret())))) .build(); @@ -95,10 +100,14 @@ class LowerToIRVMServiceTest { final var lowered = new LowerToIRVMService().lower(backend); assertEquals("__pbs.frame_wrapper$m0", lowered.module().functions().get(0).name()); - assertEquals(IRVMOp.CALL, lowered.module().functions().get(0).instructions().get(0).op()); - assertEquals(IRVMOp.CALL, lowered.module().functions().get(0).instructions().get(1).op()); + assertEquals(IRVMOp.GET_GLOBAL, lowered.module().functions().get(0).instructions().get(0).op()); + assertEquals(IRVMOp.JMP_IF_TRUE, lowered.module().functions().get(0).instructions().get(1).op()); assertEquals(IRVMOp.CALL, lowered.module().functions().get(0).instructions().get(2).op()); - assertEquals(IRVMOp.RET, lowered.module().functions().get(0).instructions().get(3).op()); + assertEquals(IRVMOp.CALL, lowered.module().functions().get(0).instructions().get(3).op()); + assertEquals(IRVMOp.PUSH_BOOL, lowered.module().functions().get(0).instructions().get(4).op()); + assertEquals(IRVMOp.SET_GLOBAL, lowered.module().functions().get(0).instructions().get(5).op()); + assertEquals(IRVMOp.CALL, lowered.module().functions().get(0).instructions().get(6).op()); + assertEquals(IRVMOp.RET, lowered.module().functions().get(0).instructions().get(7).op()); assertEquals(IRVMOp.RET, lowered.module().functions().stream() .filter(function -> "frame".equals(function.name())) .findFirst() @@ -583,4 +592,57 @@ class LowerToIRVMServiceTest { null, Span.none()); } + + private static IRBackendExecutableFunction.Instruction jmpIfTrue(final String target) { + return new IRBackendExecutableFunction.Instruction( + IRBackendExecutableFunction.InstructionKind.JMP_IF_TRUE, + ModuleId.none(), + "", + null, + null, + null, + "", + target, + null, + null, + Span.none()); + } + + private static IRBackendExecutableFunction.Instruction getGlobal(final int slot) { + return new IRBackendExecutableFunction.Instruction( + IRBackendExecutableFunction.InstructionKind.GET_GLOBAL, + "", + null, + null, + null, + slot, + null, + Span.none()); + } + + private static IRBackendExecutableFunction.Instruction setGlobal(final int slot) { + return new IRBackendExecutableFunction.Instruction( + IRBackendExecutableFunction.InstructionKind.SET_GLOBAL, + "", + null, + null, + null, + slot, + null, + Span.none()); + } + + private static IRBackendExecutableFunction.Instruction pushBool(final boolean value) { + return new IRBackendExecutableFunction.Instruction( + IRBackendExecutableFunction.InstructionKind.PUSH_BOOL, + "", + null, + null, + null, + value ? "true" : "false", + null, + null, + null, + Span.none()); + } } diff --git a/prometeu-compiler/prometeu-frontend-api/src/main/java/p/studio/compiler/models/IRBackendExecutableFunction.java b/prometeu-compiler/prometeu-frontend-api/src/main/java/p/studio/compiler/models/IRBackendExecutableFunction.java index d0c3053f..30f7f410 100644 --- a/prometeu-compiler/prometeu-frontend-api/src/main/java/p/studio/compiler/models/IRBackendExecutableFunction.java +++ b/prometeu-compiler/prometeu-frontend-api/src/main/java/p/studio/compiler/models/IRBackendExecutableFunction.java @@ -271,6 +271,20 @@ public record IRBackendExecutableFunction( throw new IllegalArgumentException("GET_LOCAL must not carry call metadata"); } } + case GET_GLOBAL -> { + if (expectedArgSlots == null) { + throw new IllegalArgumentException("GET_GLOBAL requires global slot in expectedArgSlots"); + } + if (!label.isBlank() + || !targetLabel.isBlank() + || !calleeCallableName.isBlank() + || calleeCallableId != null + || hostCall != null + || intrinsicCall != null + || expectedRetSlots != null) { + throw new IllegalArgumentException("GET_GLOBAL must not carry call metadata"); + } + } case SET_LOCAL -> { if (expectedArgSlots == null) { throw new IllegalArgumentException("SET_LOCAL requires local slot in expectedArgSlots"); @@ -285,6 +299,20 @@ public record IRBackendExecutableFunction( throw new IllegalArgumentException("SET_LOCAL must not carry call metadata"); } } + case SET_GLOBAL -> { + if (expectedArgSlots == null) { + throw new IllegalArgumentException("SET_GLOBAL requires global slot in expectedArgSlots"); + } + if (!label.isBlank() + || !targetLabel.isBlank() + || !calleeCallableName.isBlank() + || calleeCallableId != null + || hostCall != null + || intrinsicCall != null + || expectedRetSlots != null) { + throw new IllegalArgumentException("SET_GLOBAL must not carry call metadata"); + } + } case CALL_FUNC -> { if (calleeCallableId == null) { throw new IllegalArgumentException("CALL_FUNC requires calleeCallableId"); @@ -363,7 +391,9 @@ public record IRBackendExecutableFunction( PUSH_BOOL, PUSH_CONST, GET_LOCAL, + GET_GLOBAL, SET_LOCAL, + SET_GLOBAL, POP, ADD, SUB,