implements PR-040
This commit is contained in:
parent
4e2cad60cb
commit
e1be8bbf49
@ -12,6 +12,7 @@ import java.util.Objects;
|
|||||||
public class BytecodeEmitter {
|
public class BytecodeEmitter {
|
||||||
private static final int OP_HALT = 0x01;
|
private static final int OP_HALT = 0x01;
|
||||||
private static final int OP_RET = 0x51;
|
private static final int OP_RET = 0x51;
|
||||||
|
private static final int OP_CALL = 0x50;
|
||||||
private static final int OP_HOSTCALL = 0x71;
|
private static final int OP_HOSTCALL = 0x71;
|
||||||
private static final int OP_SYSCALL = 0x70;
|
private static final int OP_SYSCALL = 0x70;
|
||||||
private static final int OP_INTRINSIC = 0x72;
|
private static final int OP_INTRINSIC = 0x72;
|
||||||
@ -31,6 +32,7 @@ public class BytecodeEmitter {
|
|||||||
switch (op.kind()) {
|
switch (op.kind()) {
|
||||||
case HALT -> writeOpNoImm(code, OP_HALT);
|
case HALT -> writeOpNoImm(code, OP_HALT);
|
||||||
case RET -> writeOpNoImm(code, OP_RET);
|
case RET -> writeOpNoImm(code, OP_RET);
|
||||||
|
case CALL_FUNC -> writeOpU32(code, OP_CALL, op.immediate());
|
||||||
case INTRINSIC -> {
|
case INTRINSIC -> {
|
||||||
writeOpU32(code, OP_INTRINSIC, op.immediate());
|
writeOpU32(code, OP_INTRINSIC, op.immediate());
|
||||||
if (op.span() != null) {
|
if (op.span() != null) {
|
||||||
@ -134,6 +136,7 @@ public class BytecodeEmitter {
|
|||||||
public enum OperationKind {
|
public enum OperationKind {
|
||||||
HALT,
|
HALT,
|
||||||
RET,
|
RET,
|
||||||
|
CALL_FUNC,
|
||||||
HOSTCALL,
|
HOSTCALL,
|
||||||
RAW_SYSCALL,
|
RAW_SYSCALL,
|
||||||
INTRINSIC,
|
INTRINSIC,
|
||||||
@ -162,6 +165,10 @@ public class BytecodeEmitter {
|
|||||||
return new Operation(OperationKind.INTRINSIC, intrinsicId, null, null, null, null);
|
return new Operation(OperationKind.INTRINSIC, intrinsicId, null, null, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Operation callFunc(final int funcId) {
|
||||||
|
return new Operation(OperationKind.CALL_FUNC, funcId, null, null, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
public static Operation hostcall(
|
public static Operation hostcall(
|
||||||
final BytecodeModule.SyscallDecl decl,
|
final BytecodeModule.SyscallDecl decl,
|
||||||
final Integer expectedArgSlots,
|
final Integer expectedArgSlots,
|
||||||
|
|||||||
@ -0,0 +1,7 @@
|
|||||||
|
package p.studio.compiler.backend.irvm;
|
||||||
|
|
||||||
|
public enum IRVMLoweringErrorCode {
|
||||||
|
LOWER_IRVM_EMPTY_EXECUTABLE_INPUT,
|
||||||
|
LOWER_IRVM_MISSING_CALLEE,
|
||||||
|
}
|
||||||
|
|
||||||
@ -0,0 +1,17 @@
|
|||||||
|
package p.studio.compiler.backend.irvm;
|
||||||
|
|
||||||
|
public class IRVMLoweringException extends RuntimeException {
|
||||||
|
private final IRVMLoweringErrorCode code;
|
||||||
|
|
||||||
|
public IRVMLoweringException(
|
||||||
|
final IRVMLoweringErrorCode code,
|
||||||
|
final String message) {
|
||||||
|
super(message);
|
||||||
|
this.code = code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IRVMLoweringErrorCode code() {
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@ -0,0 +1,145 @@
|
|||||||
|
package p.studio.compiler.backend.irvm;
|
||||||
|
|
||||||
|
import p.studio.compiler.backend.bytecode.BytecodeEmitter;
|
||||||
|
import p.studio.compiler.models.IRBackend;
|
||||||
|
import p.studio.compiler.models.IRBackendExecutableFunction;
|
||||||
|
import p.studio.utilities.structures.ReadOnlyList;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
public class LowerToIRVMService {
|
||||||
|
private static final Comparator<IRBackendExecutableFunction> FUNCTION_ORDER = Comparator
|
||||||
|
.comparing(IRBackendExecutableFunction::moduleKey)
|
||||||
|
.thenComparing(IRBackendExecutableFunction::callableName)
|
||||||
|
.thenComparingInt(IRBackendExecutableFunction::sourceStart);
|
||||||
|
|
||||||
|
private final IRVMValidator validator;
|
||||||
|
|
||||||
|
public LowerToIRVMService() {
|
||||||
|
this(new IRVMValidator());
|
||||||
|
}
|
||||||
|
|
||||||
|
LowerToIRVMService(final IRVMValidator validator) {
|
||||||
|
this.validator = validator;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IRVMProgram lower(final IRBackend backend) {
|
||||||
|
if (backend == null || backend.getExecutableFunctions().isEmpty()) {
|
||||||
|
throw new IRVMLoweringException(
|
||||||
|
IRVMLoweringErrorCode.LOWER_IRVM_EMPTY_EXECUTABLE_INPUT,
|
||||||
|
"IRBackend has no executable functions");
|
||||||
|
}
|
||||||
|
|
||||||
|
final var ordered = orderFunctions(backend.getExecutableFunctions());
|
||||||
|
final var funcIdByModuleAndName = new HashMap<String, Integer>();
|
||||||
|
for (var i = 0; i < ordered.size(); i++) {
|
||||||
|
final var fn = ordered.get(i);
|
||||||
|
final var key = callableKey(fn.moduleKey(), fn.callableName());
|
||||||
|
funcIdByModuleAndName.putIfAbsent(key, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
final var loweredFunctions = new ArrayList<IRVMFunction>(ordered.size());
|
||||||
|
final var emissionFunctions = new ArrayList<BytecodeEmitter.FunctionPlan>(ordered.size());
|
||||||
|
|
||||||
|
for (var i = 0; i < ordered.size(); i++) {
|
||||||
|
final var fn = ordered.get(i);
|
||||||
|
final var instructions = new ArrayList<IRVMInstruction>(fn.instructions().size());
|
||||||
|
final var operations = new ArrayList<BytecodeEmitter.Operation>(fn.instructions().size());
|
||||||
|
for (final var instr : fn.instructions()) {
|
||||||
|
switch (instr.kind()) {
|
||||||
|
case HALT -> {
|
||||||
|
instructions.add(new IRVMInstruction(IRVMOp.HALT, null));
|
||||||
|
operations.add(BytecodeEmitter.Operation.halt());
|
||||||
|
}
|
||||||
|
case RET -> {
|
||||||
|
instructions.add(new IRVMInstruction(IRVMOp.RET, null));
|
||||||
|
operations.add(BytecodeEmitter.Operation.ret());
|
||||||
|
}
|
||||||
|
case CALL_FUNC -> {
|
||||||
|
final var key = callableKey(instr.calleeModuleKey(), instr.calleeCallableName());
|
||||||
|
final var calleeId = funcIdByModuleAndName.get(key);
|
||||||
|
if (calleeId == null) {
|
||||||
|
throw new IRVMLoweringException(
|
||||||
|
IRVMLoweringErrorCode.LOWER_IRVM_MISSING_CALLEE,
|
||||||
|
"missing callee function: " + key);
|
||||||
|
}
|
||||||
|
instructions.add(new IRVMInstruction(IRVMOp.CALL, calleeId));
|
||||||
|
operations.add(BytecodeEmitter.Operation.callFunc(calleeId));
|
||||||
|
}
|
||||||
|
case CALL_HOST -> {
|
||||||
|
final var host = instr.hostCall();
|
||||||
|
instructions.add(new IRVMInstruction(IRVMOp.HOSTCALL, 0));
|
||||||
|
operations.add(BytecodeEmitter.Operation.hostcall(
|
||||||
|
new p.studio.compiler.backend.bytecode.BytecodeModule.SyscallDecl(
|
||||||
|
host.module(),
|
||||||
|
host.name(),
|
||||||
|
(int) host.version(),
|
||||||
|
host.argSlots(),
|
||||||
|
host.retSlots()),
|
||||||
|
host.argSlots(),
|
||||||
|
host.retSlots()));
|
||||||
|
}
|
||||||
|
case CALL_INTRINSIC -> {
|
||||||
|
final var intrinsic = instr.intrinsicCall();
|
||||||
|
instructions.add(new IRVMInstruction(IRVMOp.INTRINSIC, intrinsic.intrinsicId()));
|
||||||
|
operations.add(BytecodeEmitter.Operation.intrinsic(intrinsic.intrinsicId()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
loweredFunctions.add(new IRVMFunction(
|
||||||
|
fn.callableName(),
|
||||||
|
fn.paramSlots(),
|
||||||
|
fn.localSlots(),
|
||||||
|
fn.returnSlots(),
|
||||||
|
fn.maxStackSlots(),
|
||||||
|
ReadOnlyList.wrap(instructions)));
|
||||||
|
emissionFunctions.add(new BytecodeEmitter.FunctionPlan(
|
||||||
|
fn.callableName(),
|
||||||
|
fn.paramSlots(),
|
||||||
|
fn.localSlots(),
|
||||||
|
fn.returnSlots(),
|
||||||
|
fn.maxStackSlots(),
|
||||||
|
ReadOnlyList.wrap(operations)));
|
||||||
|
}
|
||||||
|
|
||||||
|
final var module = new IRVMModule("core-v1", ReadOnlyList.wrap(loweredFunctions));
|
||||||
|
validator.validate(module, false);
|
||||||
|
return new IRVMProgram(
|
||||||
|
module,
|
||||||
|
new BytecodeEmitter.EmissionPlan(
|
||||||
|
0,
|
||||||
|
ReadOnlyList.empty(),
|
||||||
|
ReadOnlyList.empty(),
|
||||||
|
ReadOnlyList.wrap(emissionFunctions)));
|
||||||
|
}
|
||||||
|
|
||||||
|
private ReadOnlyList<IRBackendExecutableFunction> orderFunctions(
|
||||||
|
final ReadOnlyList<IRBackendExecutableFunction> functions) {
|
||||||
|
final var sorted = new ArrayList<>(functions.asList());
|
||||||
|
sorted.sort(FUNCTION_ORDER);
|
||||||
|
var entrypoint = sorted.getFirst();
|
||||||
|
for (final var candidate : sorted) {
|
||||||
|
if ("main".equals(candidate.callableName())) {
|
||||||
|
entrypoint = candidate;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
final var ordered = new ArrayList<IRBackendExecutableFunction>(sorted.size());
|
||||||
|
ordered.add(entrypoint);
|
||||||
|
for (final var fn : sorted) {
|
||||||
|
if (fn != entrypoint) {
|
||||||
|
ordered.add(fn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ReadOnlyList.wrap(ordered);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String callableKey(
|
||||||
|
final String moduleKey,
|
||||||
|
final String callableName) {
|
||||||
|
return (moduleKey == null ? "" : moduleKey) + "::" + callableName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@ -1,6 +1,9 @@
|
|||||||
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.IRVMLoweringException;
|
||||||
|
import p.studio.compiler.backend.irvm.IRVMValidationException;
|
||||||
|
import p.studio.compiler.backend.irvm.LowerToIRVMService;
|
||||||
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 +11,41 @@ import p.studio.utilities.logs.LogAggregator;
|
|||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class LowerToIRVMPipelineStage implements PipelineStage {
|
public class LowerToIRVMPipelineStage implements PipelineStage {
|
||||||
|
private final LowerToIRVMService lowerToIRVMService;
|
||||||
|
|
||||||
|
public LowerToIRVMPipelineStage() {
|
||||||
|
this(new LowerToIRVMService());
|
||||||
|
}
|
||||||
|
|
||||||
|
LowerToIRVMPipelineStage(final LowerToIRVMService lowerToIRVMService) {
|
||||||
|
this.lowerToIRVMService = lowerToIRVMService;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BuildingIssueSink run(BuilderPipelineContext ctx, LogAggregator logs) {
|
public BuildingIssueSink run(BuilderPipelineContext ctx, LogAggregator logs) {
|
||||||
|
if (ctx.irBackend == null) {
|
||||||
|
return BuildingIssueSink.empty()
|
||||||
|
.report(builder -> builder
|
||||||
|
.error(true)
|
||||||
|
.message("[BUILD]: IRBackend is missing before LowerToIRVM stage"));
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
ctx.irvm = lowerToIRVMService.lower(ctx.irBackend);
|
||||||
|
} catch (IRVMLoweringException e) {
|
||||||
|
return BuildingIssueSink.empty()
|
||||||
|
.report(builder -> builder
|
||||||
|
.error(true)
|
||||||
|
.message("[BUILD]: lower to irvm failed (%s): %s"
|
||||||
|
.formatted(e.code().name(), e.getMessage()))
|
||||||
|
.exception(e));
|
||||||
|
} catch (IRVMValidationException e) {
|
||||||
|
return BuildingIssueSink.empty()
|
||||||
|
.report(builder -> builder
|
||||||
|
.error(true)
|
||||||
|
.message("[BUILD]: lower to irvm validation failed (%s): %s"
|
||||||
|
.formatted(e.code().name(), e.getMessage()))
|
||||||
|
.exception(e));
|
||||||
|
}
|
||||||
return BuildingIssueSink.empty();
|
return BuildingIssueSink.empty();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,148 @@
|
|||||||
|
package p.studio.compiler.backend.irvm;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import p.studio.compiler.models.IRBackend;
|
||||||
|
import p.studio.compiler.models.IRBackendExecutableFunction;
|
||||||
|
import p.studio.compiler.source.Span;
|
||||||
|
import p.studio.compiler.source.identifiers.FileId;
|
||||||
|
import p.studio.utilities.structures.ReadOnlyList;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
|
class LowerToIRVMServiceTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void lowerMustAssignEntrypointIdZeroAndSortRemainingDeterministically() {
|
||||||
|
final var backend = IRBackend.builder()
|
||||||
|
.executableFunctions(ReadOnlyList.from(
|
||||||
|
fn("aux", "app", ReadOnlyList.from(
|
||||||
|
callFunc("app", "main"),
|
||||||
|
ret())),
|
||||||
|
fn("main", "app", ReadOnlyList.from(
|
||||||
|
ret()))))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
final var lowered = new LowerToIRVMService().lower(backend);
|
||||||
|
|
||||||
|
assertEquals(2, lowered.module().functions().size());
|
||||||
|
assertEquals("main", lowered.module().functions().get(0).name());
|
||||||
|
assertEquals("aux", lowered.module().functions().get(1).name());
|
||||||
|
assertEquals(IRVMOp.CALL, lowered.module().functions().get(1).instructions().get(0).op());
|
||||||
|
assertEquals(0, lowered.module().functions().get(1).instructions().get(0).immediate());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void lowerMustMapHostAndIntrinsicCallsites() {
|
||||||
|
final var backend = IRBackend.builder()
|
||||||
|
.executableFunctions(ReadOnlyList.from(
|
||||||
|
fn("main", "app", ReadOnlyList.from(
|
||||||
|
callHost("gfx", "draw_pixel", 1, 2, 0),
|
||||||
|
callIntrinsic("core.color.pack", 1, 0x2001),
|
||||||
|
ret()))))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
final var lowered = new LowerToIRVMService().lower(backend);
|
||||||
|
|
||||||
|
final var instructions = lowered.module().functions().getFirst().instructions();
|
||||||
|
assertEquals(IRVMOp.HOSTCALL, instructions.get(0).op());
|
||||||
|
assertEquals(IRVMOp.INTRINSIC, instructions.get(1).op());
|
||||||
|
assertEquals(0x2001, instructions.get(1).immediate());
|
||||||
|
final var emissionOps = lowered.emissionPlan().functions().getFirst().operations();
|
||||||
|
assertEquals(p.studio.compiler.backend.bytecode.BytecodeEmitter.OperationKind.HOSTCALL, emissionOps.get(0).kind());
|
||||||
|
assertEquals(p.studio.compiler.backend.bytecode.BytecodeEmitter.OperationKind.INTRINSIC, emissionOps.get(1).kind());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void lowerMustRejectUnterminatedFunction() {
|
||||||
|
final var backend = IRBackend.builder()
|
||||||
|
.executableFunctions(ReadOnlyList.from(
|
||||||
|
fn("main", "app", ReadOnlyList.from(
|
||||||
|
callFunc("app", "main")))))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
final var thrown = assertThrows(IRVMValidationException.class, () -> new LowerToIRVMService().lower(backend));
|
||||||
|
assertEquals(IRVMValidationErrorCode.MARSHAL_VERIFY_PRECHECK_UNTERMINATED_PATH, thrown.code());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void lowerMustRejectMissingCallee() {
|
||||||
|
final var backend = IRBackend.builder()
|
||||||
|
.executableFunctions(ReadOnlyList.from(
|
||||||
|
fn("main", "app", ReadOnlyList.from(
|
||||||
|
callFunc("app", "missing"),
|
||||||
|
ret()))))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
final var thrown = assertThrows(IRVMLoweringException.class, () -> new LowerToIRVMService().lower(backend));
|
||||||
|
assertEquals(IRVMLoweringErrorCode.LOWER_IRVM_MISSING_CALLEE, thrown.code());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IRBackendExecutableFunction fn(
|
||||||
|
final String name,
|
||||||
|
final String moduleKey,
|
||||||
|
final ReadOnlyList<IRBackendExecutableFunction.Instruction> instructions) {
|
||||||
|
return new IRBackendExecutableFunction(
|
||||||
|
new FileId(0),
|
||||||
|
moduleKey,
|
||||||
|
name,
|
||||||
|
0,
|
||||||
|
10,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
4,
|
||||||
|
instructions,
|
||||||
|
Span.none());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IRBackendExecutableFunction.Instruction ret() {
|
||||||
|
return new IRBackendExecutableFunction.Instruction(
|
||||||
|
IRBackendExecutableFunction.InstructionKind.RET,
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
Span.none());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IRBackendExecutableFunction.Instruction callFunc(final String moduleKey, final String name) {
|
||||||
|
return new IRBackendExecutableFunction.Instruction(
|
||||||
|
IRBackendExecutableFunction.InstructionKind.CALL_FUNC,
|
||||||
|
moduleKey,
|
||||||
|
name,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
Span.none());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IRBackendExecutableFunction.Instruction callHost(
|
||||||
|
final String module,
|
||||||
|
final String name,
|
||||||
|
final long version,
|
||||||
|
final int argSlots,
|
||||||
|
final int retSlots) {
|
||||||
|
return new IRBackendExecutableFunction.Instruction(
|
||||||
|
IRBackendExecutableFunction.InstructionKind.CALL_HOST,
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
new IRBackendExecutableFunction.HostCallMetadata(module, name, version, argSlots, retSlots),
|
||||||
|
null,
|
||||||
|
Span.none());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IRBackendExecutableFunction.Instruction callIntrinsic(
|
||||||
|
final String canonicalName,
|
||||||
|
final long canonicalVersion,
|
||||||
|
final int intrinsicId) {
|
||||||
|
return new IRBackendExecutableFunction.Instruction(
|
||||||
|
IRBackendExecutableFunction.InstructionKind.CALL_INTRINSIC,
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
null,
|
||||||
|
new IRBackendExecutableFunction.IntrinsicCallMetadata(canonicalName, canonicalVersion, intrinsicId),
|
||||||
|
Span.none());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@ -0,0 +1,62 @@
|
|||||||
|
package p.studio.compiler.workspaces.stages;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import p.studio.compiler.messages.BuilderPipelineConfig;
|
||||||
|
import p.studio.compiler.models.BuilderPipelineContext;
|
||||||
|
import p.studio.compiler.models.IRBackend;
|
||||||
|
import p.studio.compiler.models.IRBackendExecutableFunction;
|
||||||
|
import p.studio.compiler.source.Span;
|
||||||
|
import p.studio.compiler.source.identifiers.FileId;
|
||||||
|
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.assertNotNull;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
|
class LowerToIRVMPipelineStageTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void runMustFailWhenIrBackendIsMissing() {
|
||||||
|
final var ctx = BuilderPipelineContext.compilerContext(new BuilderPipelineConfig(false, "."));
|
||||||
|
final var stage = new LowerToIRVMPipelineStage();
|
||||||
|
|
||||||
|
final var issues = stage.run(ctx, LogAggregator.empty());
|
||||||
|
|
||||||
|
assertTrue(issues.hasErrors());
|
||||||
|
assertEquals(1, issues.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void runMustLowerExecutableFunctionsToIrvm() {
|
||||||
|
final var ctx = BuilderPipelineContext.compilerContext(new BuilderPipelineConfig(false, "."));
|
||||||
|
ctx.irBackend = IRBackend.builder()
|
||||||
|
.executableFunctions(ReadOnlyList.from(new IRBackendExecutableFunction(
|
||||||
|
new FileId(0),
|
||||||
|
"app",
|
||||||
|
"main",
|
||||||
|
0,
|
||||||
|
10,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
ReadOnlyList.from(new IRBackendExecutableFunction.Instruction(
|
||||||
|
IRBackendExecutableFunction.InstructionKind.RET,
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
Span.none())),
|
||||||
|
Span.none())))
|
||||||
|
.build();
|
||||||
|
final var stage = new LowerToIRVMPipelineStage();
|
||||||
|
|
||||||
|
final var issues = stage.run(ctx, LogAggregator.empty());
|
||||||
|
|
||||||
|
assertTrue(!issues.hasErrors());
|
||||||
|
assertNotNull(ctx.irvm);
|
||||||
|
assertEquals(1, ctx.irvm.module().functions().size());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Loading…
x
Reference in New Issue
Block a user