implements PR-037
This commit is contained in:
parent
e6bd796f4f
commit
574e890c21
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user