implements PR-037
This commit is contained in:
parent
e6bd796f4f
commit
574e890c21
@ -1,17 +1,49 @@
|
|||||||
package p.studio.compiler.backend.irvm;
|
package p.studio.compiler.backend.irvm;
|
||||||
|
|
||||||
import p.studio.compiler.backend.bytecode.BytecodeEmitter;
|
import p.studio.compiler.backend.bytecode.BytecodeEmitter;
|
||||||
|
import p.studio.utilities.structures.ReadOnlyList;
|
||||||
|
|
||||||
public record IRVMProgram(
|
public record IRVMProgram(
|
||||||
boolean hasInternalOpcodes,
|
IRVMModule module,
|
||||||
BytecodeEmitter.EmissionPlan emissionPlan) {
|
BytecodeEmitter.EmissionPlan emissionPlan) {
|
||||||
|
|
||||||
public IRVMProgram {
|
public IRVMProgram {
|
||||||
|
module = module == null ? IRVMModule.empty() : module;
|
||||||
emissionPlan = emissionPlan == null ? BytecodeEmitter.EmissionPlan.empty() : emissionPlan;
|
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() {
|
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;
|
package p.studio.compiler.workspaces.stages;
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
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.messages.BuildingIssueSink;
|
||||||
import p.studio.compiler.models.BuilderPipelineContext;
|
import p.studio.compiler.models.BuilderPipelineContext;
|
||||||
import p.studio.compiler.workspaces.PipelineStage;
|
import p.studio.compiler.workspaces.PipelineStage;
|
||||||
@ -8,8 +10,40 @@ import p.studio.utilities.logs.LogAggregator;
|
|||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class OptimizeIRVMPipelineStage implements PipelineStage {
|
public class OptimizeIRVMPipelineStage implements PipelineStage {
|
||||||
|
private final OptimizeIRVMService optimizeIRVMService;
|
||||||
|
|
||||||
|
public OptimizeIRVMPipelineStage() {
|
||||||
|
this(new OptimizeIRVMService());
|
||||||
|
}
|
||||||
|
|
||||||
|
OptimizeIRVMPipelineStage(final OptimizeIRVMService optimizeIRVMService) {
|
||||||
|
this.optimizeIRVMService = optimizeIRVMService;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BuildingIssueSink run(BuilderPipelineContext ctx, LogAggregator logs) {
|
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();
|
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