implements PR-037

This commit is contained in:
bQUARKz 2026-03-07 16:48:32 +00:00
parent e6bd796f4f
commit 574e890c21
Signed by: bquarkz
SSH Key Fingerprint: SHA256:Z7dgqoglWwoK6j6u4QC87OveEq74WOhFN+gitsxtkf8
5 changed files with 208 additions and 3 deletions

View File

@ -1,17 +1,49 @@
package p.studio.compiler.backend.irvm;
import p.studio.compiler.backend.bytecode.BytecodeEmitter;
import p.studio.utilities.structures.ReadOnlyList;
public record IRVMProgram(
boolean hasInternalOpcodes,
IRVMModule module,
BytecodeEmitter.EmissionPlan emissionPlan) {
public IRVMProgram {
module = module == null ? IRVMModule.empty() : module;
emissionPlan = emissionPlan == null ? BytecodeEmitter.EmissionPlan.empty() : emissionPlan;
}
public IRVMProgram(final IRVMModule module) {
this(module, BytecodeEmitter.EmissionPlan.empty());
}
public IRVMProgram(
final boolean hasInternalOpcodes,
final BytecodeEmitter.EmissionPlan emissionPlan) {
this(new IRVMModule(
"core-v1",
ReadOnlyList.from(new IRVMFunction(
"__synthetic__",
0,
0,
0,
1,
ReadOnlyList.from(
new IRVMInstruction(hasInternalOpcodes ? IRVMOp.INTERNAL_EXT : IRVMOp.HALT, null))))),
emissionPlan);
}
public static IRVMProgram empty() {
return new IRVMProgram(false, BytecodeEmitter.EmissionPlan.empty());
return new IRVMProgram(IRVMModule.empty(), BytecodeEmitter.EmissionPlan.empty());
}
public boolean hasInternalOpcodes() {
for (final var function : module.functions()) {
for (final var instruction : function.instructions()) {
if (instruction.op().internal()) {
return true;
}
}
}
return false;
}
}

View File

@ -0,0 +1,26 @@
package p.studio.compiler.backend.irvm;
public class OptimizeIRVMService {
private final IRVMValidator validator;
public OptimizeIRVMService() {
this(new IRVMValidator());
}
OptimizeIRVMService(final IRVMValidator validator) {
this.validator = validator;
}
public IRVMProgram optimize(final IRVMProgram input) {
final var program = input == null ? IRVMProgram.empty() : input;
if (!"core-v1".equals(program.module().vmProfile())) {
throw new IllegalArgumentException("unsupported vm profile: " + program.module().vmProfile());
}
validator.validate(program.module(), false);
// Baseline pass manager: no-op pass preserving semantic shape.
final var optimized = program;
validator.validate(optimized.module(), false);
return optimized;
}
}

View File

@ -1,6 +1,8 @@
package p.studio.compiler.workspaces.stages;
import lombok.extern.slf4j.Slf4j;
import p.studio.compiler.backend.irvm.IRVMValidationException;
import p.studio.compiler.backend.irvm.OptimizeIRVMService;
import p.studio.compiler.messages.BuildingIssueSink;
import p.studio.compiler.models.BuilderPipelineContext;
import p.studio.compiler.workspaces.PipelineStage;
@ -8,8 +10,40 @@ import p.studio.utilities.logs.LogAggregator;
@Slf4j
public class OptimizeIRVMPipelineStage implements PipelineStage {
private final OptimizeIRVMService optimizeIRVMService;
public OptimizeIRVMPipelineStage() {
this(new OptimizeIRVMService());
}
OptimizeIRVMPipelineStage(final OptimizeIRVMService optimizeIRVMService) {
this.optimizeIRVMService = optimizeIRVMService;
}
@Override
public BuildingIssueSink run(BuilderPipelineContext ctx, LogAggregator logs) {
if (ctx.irvm == null) {
return BuildingIssueSink.empty()
.report(builder -> builder
.error(true)
.message("[BUILD]: IRVM is missing before OptimizeIRVM stage"));
}
try {
ctx.optimizedIrvm = optimizeIRVMService.optimize(ctx.irvm);
} catch (IRVMValidationException e) {
return BuildingIssueSink.empty()
.report(builder -> builder
.error(true)
.message("[BUILD]: optimize irvm validation failed (%s): %s"
.formatted(e.code().name(), e.getMessage()))
.exception(e));
} catch (RuntimeException e) {
return BuildingIssueSink.empty()
.report(builder -> builder
.error(true)
.message("[BUILD]: optimize irvm failed: " + e.getMessage())
.exception(e));
}
return BuildingIssueSink.empty();
}
}

View File

@ -0,0 +1,38 @@
package p.studio.compiler.workspaces;
import org.junit.jupiter.api.Test;
import p.studio.compiler.workspaces.stages.EmitBytecodePipelineStage;
import p.studio.compiler.workspaces.stages.FrontendPhasePipelineStage;
import p.studio.compiler.workspaces.stages.LoadSourcesPipelineStage;
import p.studio.compiler.workspaces.stages.LowerToIRVMPipelineStage;
import p.studio.compiler.workspaces.stages.OptimizeIRVMPipelineStage;
import p.studio.compiler.workspaces.stages.ResolveDepsPipelineStage;
import java.lang.reflect.Field;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertEquals;
class BuilderPipelineServiceOrderTest {
@Test
void canonicalOrderMustContainOptimizeBetweenLowerAndEmit() throws Exception {
final Field field = BuilderPipelineService.class.getDeclaredField("stages");
field.setAccessible(true);
@SuppressWarnings("unchecked")
final var stages = (List<PipelineStage>) field.get(BuilderPipelineService.INSTANCE);
final var stageTypes = stages.stream().map(Object::getClass).toList();
assertEquals(
List.of(
ResolveDepsPipelineStage.class,
LoadSourcesPipelineStage.class,
FrontendPhasePipelineStage.class,
LowerToIRVMPipelineStage.class,
OptimizeIRVMPipelineStage.class,
EmitBytecodePipelineStage.class),
stageTypes);
}
}

View File

@ -0,0 +1,75 @@
package p.studio.compiler.workspaces.stages;
import org.junit.jupiter.api.Test;
import p.studio.compiler.backend.irvm.IRVMFunction;
import p.studio.compiler.backend.irvm.IRVMInstruction;
import p.studio.compiler.backend.irvm.IRVMModule;
import p.studio.compiler.backend.irvm.IRVMOp;
import p.studio.compiler.backend.irvm.IRVMProgram;
import p.studio.compiler.messages.BuilderPipelineConfig;
import p.studio.compiler.models.BuilderPipelineContext;
import p.studio.utilities.logs.LogAggregator;
import p.studio.utilities.structures.ReadOnlyList;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
class OptimizeIRVMPipelineStageTest {
@Test
void runMustFailWhenIrvmIsMissing() {
final var ctx = BuilderPipelineContext.compilerContext(new BuilderPipelineConfig(false, "."));
final var stage = new OptimizeIRVMPipelineStage();
final var issues = stage.run(ctx, LogAggregator.empty());
assertTrue(issues.hasErrors());
assertEquals(1, issues.size());
}
@Test
void runMustProduceNoopOptimizedProgram() {
final var ctx = BuilderPipelineContext.compilerContext(new BuilderPipelineConfig(false, "."));
ctx.irvm = new IRVMProgram(new IRVMModule(
"core-v1",
ReadOnlyList.from(new IRVMFunction(
"main",
0,
0,
0,
1,
ReadOnlyList.from(
new IRVMInstruction(IRVMOp.HALT, null))))));
final var stage = new OptimizeIRVMPipelineStage();
final var issues = stage.run(ctx, LogAggregator.empty());
assertFalse(issues.hasErrors());
assertNotNull(ctx.optimizedIrvm);
assertEquals(ctx.irvm, ctx.optimizedIrvm);
}
@Test
void runMustRejectUnsupportedVmProfile() {
final var ctx = BuilderPipelineContext.compilerContext(new BuilderPipelineConfig(false, "."));
ctx.irvm = new IRVMProgram(new IRVMModule(
"experimental",
ReadOnlyList.from(new IRVMFunction(
"main",
0,
0,
0,
1,
ReadOnlyList.from(
new IRVMInstruction(IRVMOp.HALT, null))))));
final var stage = new OptimizeIRVMPipelineStage();
final var issues = stage.run(ctx, LogAggregator.empty());
assertTrue(issues.hasErrors());
assertEquals(1, issues.size());
}
}