implements PR-O1.5
This commit is contained in:
parent
e36c59fe26
commit
b5622bd9df
@ -30,14 +30,21 @@ public class BytecodeEmitter {
|
||||
for (final var op : function.operations()) {
|
||||
final var pc = code.size();
|
||||
switch (op.kind()) {
|
||||
case HALT -> writeOpNoImm(code, OP_HALT);
|
||||
case RET -> writeOpNoImm(code, OP_RET);
|
||||
case CALL_FUNC -> writeOpU32(code, OP_CALL, op.immediate());
|
||||
case HALT -> {
|
||||
writeOpNoImm(code, OP_HALT);
|
||||
spans.add(new BytecodeFunctionLayoutBuilder.InstructionSpan(pc, spanOrUnknown(op.span())));
|
||||
}
|
||||
case RET -> {
|
||||
writeOpNoImm(code, OP_RET);
|
||||
spans.add(new BytecodeFunctionLayoutBuilder.InstructionSpan(pc, spanOrUnknown(op.span())));
|
||||
}
|
||||
case CALL_FUNC -> {
|
||||
writeOpU32(code, OP_CALL, op.immediate());
|
||||
spans.add(new BytecodeFunctionLayoutBuilder.InstructionSpan(pc, spanOrUnknown(op.span())));
|
||||
}
|
||||
case INTRINSIC -> {
|
||||
writeOpU32(code, OP_INTRINSIC, op.immediate());
|
||||
if (op.span() != null) {
|
||||
spans.add(new BytecodeFunctionLayoutBuilder.InstructionSpan(pc, op.span()));
|
||||
}
|
||||
spans.add(new BytecodeFunctionLayoutBuilder.InstructionSpan(pc, spanOrUnknown(op.span())));
|
||||
}
|
||||
case HOSTCALL -> {
|
||||
final var decl = Objects.requireNonNull(op.syscallDecl(), "syscallDecl");
|
||||
@ -59,9 +66,7 @@ public class BytecodeEmitter {
|
||||
}
|
||||
final var index = syscallIndexByIdentity.get(identity);
|
||||
writeOpU32(code, OP_HOSTCALL, index);
|
||||
if (op.span() != null) {
|
||||
spans.add(new BytecodeFunctionLayoutBuilder.InstructionSpan(pc, op.span()));
|
||||
}
|
||||
spans.add(new BytecodeFunctionLayoutBuilder.InstructionSpan(pc, spanOrUnknown(op.span())));
|
||||
}
|
||||
case RAW_SYSCALL -> throw new BytecodeMarshalingException(
|
||||
BytecodeMarshalingErrorCode.MARSHAL_LINKAGE_RAW_SYSCALL_IN_PRELOAD,
|
||||
@ -98,6 +103,13 @@ public class BytecodeEmitter {
|
||||
out.writeBytes(ByteBuffer.allocate(4).order(ByteOrder.LITTLE_ENDIAN).putInt(immediate).array());
|
||||
}
|
||||
|
||||
private static BytecodeModule.SourceSpan spanOrUnknown(final BytecodeModule.SourceSpan span) {
|
||||
if (span == null) {
|
||||
return new BytecodeModule.SourceSpan(-1, 0, 0);
|
||||
}
|
||||
return span;
|
||||
}
|
||||
|
||||
private record SyscallIdentity(
|
||||
String module,
|
||||
String name,
|
||||
@ -154,26 +166,50 @@ public class BytecodeEmitter {
|
||||
}
|
||||
|
||||
public static Operation halt() {
|
||||
return new Operation(OperationKind.HALT, 0, null, null, null, null);
|
||||
return halt(null);
|
||||
}
|
||||
|
||||
public static Operation halt(final BytecodeModule.SourceSpan span) {
|
||||
return new Operation(OperationKind.HALT, 0, null, null, null, span);
|
||||
}
|
||||
|
||||
public static Operation ret() {
|
||||
return new Operation(OperationKind.RET, 0, null, null, null, null);
|
||||
return ret(null);
|
||||
}
|
||||
|
||||
public static Operation ret(final BytecodeModule.SourceSpan span) {
|
||||
return new Operation(OperationKind.RET, 0, null, null, null, span);
|
||||
}
|
||||
|
||||
public static Operation intrinsic(final int intrinsicId) {
|
||||
return new Operation(OperationKind.INTRINSIC, intrinsicId, null, null, null, null);
|
||||
return intrinsic(intrinsicId, null);
|
||||
}
|
||||
|
||||
public static Operation intrinsic(final int intrinsicId, final BytecodeModule.SourceSpan span) {
|
||||
return new Operation(OperationKind.INTRINSIC, intrinsicId, null, null, null, span);
|
||||
}
|
||||
|
||||
public static Operation callFunc(final int funcId) {
|
||||
return new Operation(OperationKind.CALL_FUNC, funcId, null, null, null, null);
|
||||
return callFunc(funcId, null);
|
||||
}
|
||||
|
||||
public static Operation callFunc(final int funcId, final BytecodeModule.SourceSpan span) {
|
||||
return new Operation(OperationKind.CALL_FUNC, funcId, null, null, null, span);
|
||||
}
|
||||
|
||||
public static Operation hostcall(
|
||||
final BytecodeModule.SyscallDecl decl,
|
||||
final Integer expectedArgSlots,
|
||||
final Integer expectedRetSlots) {
|
||||
return new Operation(OperationKind.HOSTCALL, 0, decl, expectedArgSlots, expectedRetSlots, null);
|
||||
return hostcall(decl, expectedArgSlots, expectedRetSlots, null);
|
||||
}
|
||||
|
||||
public static Operation hostcall(
|
||||
final BytecodeModule.SyscallDecl decl,
|
||||
final Integer expectedArgSlots,
|
||||
final Integer expectedRetSlots,
|
||||
final BytecodeModule.SourceSpan span) {
|
||||
return new Operation(OperationKind.HOSTCALL, 0, decl, expectedArgSlots, expectedRetSlots, span);
|
||||
}
|
||||
|
||||
public static Operation rawSyscall(final int syscallId) {
|
||||
|
||||
@ -1,8 +1,10 @@
|
||||
package p.studio.compiler.backend.irvm;
|
||||
|
||||
import p.studio.compiler.backend.bytecode.BytecodeEmitter;
|
||||
import p.studio.compiler.backend.bytecode.BytecodeModule;
|
||||
import p.studio.compiler.models.IRBackend;
|
||||
import p.studio.compiler.models.IRBackendExecutableFunction;
|
||||
import p.studio.compiler.source.Span;
|
||||
import p.studio.utilities.structures.ReadOnlyList;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@ -48,14 +50,15 @@ public class LowerToIRVMService {
|
||||
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()) {
|
||||
final var sourceSpan = toBytecodeSpan(fn.fileId().getId(), instr.span());
|
||||
switch (instr.kind()) {
|
||||
case HALT -> {
|
||||
instructions.add(new IRVMInstruction(IRVMOp.HALT, null));
|
||||
operations.add(BytecodeEmitter.Operation.halt());
|
||||
operations.add(BytecodeEmitter.Operation.halt(sourceSpan));
|
||||
}
|
||||
case RET -> {
|
||||
instructions.add(new IRVMInstruction(IRVMOp.RET, null));
|
||||
operations.add(BytecodeEmitter.Operation.ret());
|
||||
operations.add(BytecodeEmitter.Operation.ret(sourceSpan));
|
||||
}
|
||||
case CALL_FUNC -> {
|
||||
final var key = callableKey(instr.calleeModuleKey(), instr.calleeCallableName());
|
||||
@ -85,7 +88,7 @@ public class LowerToIRVMService {
|
||||
calleeFunction.returnSlots()));
|
||||
}
|
||||
instructions.add(new IRVMInstruction(IRVMOp.CALL, calleeId));
|
||||
operations.add(BytecodeEmitter.Operation.callFunc(calleeId));
|
||||
operations.add(BytecodeEmitter.Operation.callFunc(calleeId, sourceSpan));
|
||||
}
|
||||
case CALL_HOST -> {
|
||||
final var host = instr.hostCall();
|
||||
@ -98,12 +101,13 @@ public class LowerToIRVMService {
|
||||
host.argSlots(),
|
||||
host.retSlots()),
|
||||
host.argSlots(),
|
||||
host.retSlots()));
|
||||
host.retSlots(),
|
||||
sourceSpan));
|
||||
}
|
||||
case CALL_INTRINSIC -> {
|
||||
final var intrinsic = instr.intrinsicCall();
|
||||
instructions.add(new IRVMInstruction(IRVMOp.INTRINSIC, intrinsic.intrinsicId()));
|
||||
operations.add(BytecodeEmitter.Operation.intrinsic(intrinsic.intrinsicId()));
|
||||
operations.add(BytecodeEmitter.Operation.intrinsic(intrinsic.intrinsicId(), sourceSpan));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -160,4 +164,27 @@ public class LowerToIRVMService {
|
||||
final String callableName) {
|
||||
return (moduleKey == null ? "" : moduleKey) + "::" + callableName;
|
||||
}
|
||||
|
||||
private BytecodeModule.SourceSpan toBytecodeSpan(
|
||||
final int fallbackFileId,
|
||||
final Span span) {
|
||||
final var sourceSpan = span == null ? Span.none() : span;
|
||||
final var fileId = sourceSpan.getFileId() == null || sourceSpan.getFileId().isNone()
|
||||
? fallbackFileId
|
||||
: sourceSpan.getFileId().getId();
|
||||
return new BytecodeModule.SourceSpan(
|
||||
fileId,
|
||||
safeToInt(sourceSpan.getStart()),
|
||||
safeToInt(sourceSpan.getEnd()));
|
||||
}
|
||||
|
||||
private int safeToInt(final long value) {
|
||||
if (value > Integer.MAX_VALUE) {
|
||||
return Integer.MAX_VALUE;
|
||||
}
|
||||
if (value < Integer.MIN_VALUE) {
|
||||
return Integer.MIN_VALUE;
|
||||
}
|
||||
return (int) value;
|
||||
}
|
||||
}
|
||||
|
||||
@ -116,6 +116,33 @@ class BytecodeEmitterTest {
|
||||
assertEquals(0x2000, readU32(module.code(), 2));
|
||||
}
|
||||
|
||||
@Test
|
||||
void emitMustProducePcToSpanForEveryInstructionStartWhenSpansAreProvided() {
|
||||
final var emitter = new BytecodeEmitter();
|
||||
final var module = emitter.emit(new BytecodeEmitter.EmissionPlan(
|
||||
0,
|
||||
ReadOnlyList.empty(),
|
||||
ReadOnlyList.empty(),
|
||||
ReadOnlyList.from(
|
||||
new BytecodeEmitter.FunctionPlan(
|
||||
"main",
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
4,
|
||||
ReadOnlyList.from(
|
||||
BytecodeEmitter.Operation.halt(new BytecodeModule.SourceSpan(1, 0, 1)),
|
||||
BytecodeEmitter.Operation.callFunc(0, new BytecodeModule.SourceSpan(1, 2, 3)),
|
||||
BytecodeEmitter.Operation.intrinsic(0x2000, new BytecodeModule.SourceSpan(1, 4, 5)),
|
||||
BytecodeEmitter.Operation.ret(new BytecodeModule.SourceSpan(1, 6, 7)))))));
|
||||
|
||||
assertEquals(4, module.debugInfo().pcToSpan().size());
|
||||
assertEquals(0, module.debugInfo().pcToSpan().get(0).pc());
|
||||
assertEquals(2, module.debugInfo().pcToSpan().get(1).pc());
|
||||
assertEquals(8, module.debugInfo().pcToSpan().get(2).pc());
|
||||
assertEquals(14, module.debugInfo().pcToSpan().get(3).pc());
|
||||
}
|
||||
|
||||
private static int readU16(final byte[] bytes, final int offset) {
|
||||
return ByteBuffer.wrap(bytes, offset, 2).order(ByteOrder.LITTLE_ENDIAN).getShort() & 0xFFFF;
|
||||
}
|
||||
@ -124,4 +151,3 @@ class BytecodeEmitterTest {
|
||||
return ByteBuffer.wrap(bytes, offset, 4).order(ByteOrder.LITTLE_ENDIAN).getInt();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -52,6 +52,7 @@ class LowerToIRVMServiceTest {
|
||||
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());
|
||||
assertTrue(emissionOps.stream().allMatch(op -> op.span() != null));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user