Add object comparison opcodes to bytecode
This commit is contained in:
parent
fd1548c86c
commit
b4598bff98
@ -155,6 +155,10 @@ Note: Any opcode can be compiled to FALLBACK if not implemented in a VM pass.
|
||||
- CMP_NEQ_OBJ S, S -> S
|
||||
- CMP_REF_EQ_OBJ S, S -> S
|
||||
- CMP_REF_NEQ_OBJ S, S -> S
|
||||
- CMP_LT_OBJ S, S -> S
|
||||
- CMP_LTE_OBJ S, S -> S
|
||||
- CMP_GT_OBJ S, S -> S
|
||||
- CMP_GTE_OBJ S, S -> S
|
||||
|
||||
### Boolean ops
|
||||
- NOT_BOOL S -> S
|
||||
|
||||
@ -134,6 +134,7 @@ class BytecodeBuilder {
|
||||
Opcode.CMP_LTE_INT_REAL, Opcode.CMP_LTE_REAL_INT, Opcode.CMP_GT_INT_REAL, Opcode.CMP_GT_REAL_INT,
|
||||
Opcode.CMP_GTE_INT_REAL, Opcode.CMP_GTE_REAL_INT, Opcode.CMP_NEQ_INT_REAL, Opcode.CMP_NEQ_REAL_INT,
|
||||
Opcode.CMP_EQ_OBJ, Opcode.CMP_NEQ_OBJ, Opcode.CMP_REF_EQ_OBJ, Opcode.CMP_REF_NEQ_OBJ,
|
||||
Opcode.CMP_LT_OBJ, Opcode.CMP_LTE_OBJ, Opcode.CMP_GT_OBJ, Opcode.CMP_GTE_OBJ,
|
||||
Opcode.AND_BOOL, Opcode.OR_BOOL ->
|
||||
listOf(OperandKind.SLOT, OperandKind.SLOT, OperandKind.SLOT)
|
||||
Opcode.INC_INT, Opcode.DEC_INT, Opcode.RET ->
|
||||
|
||||
@ -404,6 +404,10 @@ class BytecodeCompiler {
|
||||
builder.emit(Opcode.CMP_LT_REAL_INT, a.slot, b.slot, out)
|
||||
CompiledValue(out, SlotType.BOOL)
|
||||
}
|
||||
a.type == SlotType.OBJ && b.type == SlotType.OBJ -> {
|
||||
builder.emit(Opcode.CMP_LT_OBJ, a.slot, b.slot, out)
|
||||
CompiledValue(out, SlotType.BOOL)
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
@ -427,6 +431,10 @@ class BytecodeCompiler {
|
||||
builder.emit(Opcode.CMP_LTE_REAL_INT, a.slot, b.slot, out)
|
||||
CompiledValue(out, SlotType.BOOL)
|
||||
}
|
||||
a.type == SlotType.OBJ && b.type == SlotType.OBJ -> {
|
||||
builder.emit(Opcode.CMP_LTE_OBJ, a.slot, b.slot, out)
|
||||
CompiledValue(out, SlotType.BOOL)
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
@ -450,6 +458,10 @@ class BytecodeCompiler {
|
||||
builder.emit(Opcode.CMP_GT_REAL_INT, a.slot, b.slot, out)
|
||||
CompiledValue(out, SlotType.BOOL)
|
||||
}
|
||||
a.type == SlotType.OBJ && b.type == SlotType.OBJ -> {
|
||||
builder.emit(Opcode.CMP_GT_OBJ, a.slot, b.slot, out)
|
||||
CompiledValue(out, SlotType.BOOL)
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
@ -473,6 +485,10 @@ class BytecodeCompiler {
|
||||
builder.emit(Opcode.CMP_GTE_REAL_INT, a.slot, b.slot, out)
|
||||
CompiledValue(out, SlotType.BOOL)
|
||||
}
|
||||
a.type == SlotType.OBJ && b.type == SlotType.OBJ -> {
|
||||
builder.emit(Opcode.CMP_GTE_OBJ, a.slot, b.slot, out)
|
||||
CompiledValue(out, SlotType.BOOL)
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
@ -102,6 +102,7 @@ object BytecodeDisassembler {
|
||||
Opcode.CMP_LTE_INT_REAL, Opcode.CMP_LTE_REAL_INT, Opcode.CMP_GT_INT_REAL, Opcode.CMP_GT_REAL_INT,
|
||||
Opcode.CMP_GTE_INT_REAL, Opcode.CMP_GTE_REAL_INT, Opcode.CMP_NEQ_INT_REAL, Opcode.CMP_NEQ_REAL_INT,
|
||||
Opcode.CMP_EQ_OBJ, Opcode.CMP_NEQ_OBJ, Opcode.CMP_REF_EQ_OBJ, Opcode.CMP_REF_NEQ_OBJ,
|
||||
Opcode.CMP_LT_OBJ, Opcode.CMP_LTE_OBJ, Opcode.CMP_GT_OBJ, Opcode.CMP_GTE_OBJ,
|
||||
Opcode.AND_BOOL, Opcode.OR_BOOL ->
|
||||
listOf(OperandKind.SLOT, OperandKind.SLOT, OperandKind.SLOT)
|
||||
Opcode.INC_INT, Opcode.DEC_INT, Opcode.RET ->
|
||||
|
||||
@ -583,6 +583,42 @@ class BytecodeVm {
|
||||
ip += fn.slotWidth
|
||||
frame.setBool(dst, frame.getObj(a) !== frame.getObj(b))
|
||||
}
|
||||
Opcode.CMP_LT_OBJ -> {
|
||||
val a = decoder.readSlot(code, ip)
|
||||
ip += fn.slotWidth
|
||||
val b = decoder.readSlot(code, ip)
|
||||
ip += fn.slotWidth
|
||||
val dst = decoder.readSlot(code, ip)
|
||||
ip += fn.slotWidth
|
||||
frame.setBool(dst, frame.getObj(a).compareTo(scope, frame.getObj(b)) < 0)
|
||||
}
|
||||
Opcode.CMP_LTE_OBJ -> {
|
||||
val a = decoder.readSlot(code, ip)
|
||||
ip += fn.slotWidth
|
||||
val b = decoder.readSlot(code, ip)
|
||||
ip += fn.slotWidth
|
||||
val dst = decoder.readSlot(code, ip)
|
||||
ip += fn.slotWidth
|
||||
frame.setBool(dst, frame.getObj(a).compareTo(scope, frame.getObj(b)) <= 0)
|
||||
}
|
||||
Opcode.CMP_GT_OBJ -> {
|
||||
val a = decoder.readSlot(code, ip)
|
||||
ip += fn.slotWidth
|
||||
val b = decoder.readSlot(code, ip)
|
||||
ip += fn.slotWidth
|
||||
val dst = decoder.readSlot(code, ip)
|
||||
ip += fn.slotWidth
|
||||
frame.setBool(dst, frame.getObj(a).compareTo(scope, frame.getObj(b)) > 0)
|
||||
}
|
||||
Opcode.CMP_GTE_OBJ -> {
|
||||
val a = decoder.readSlot(code, ip)
|
||||
ip += fn.slotWidth
|
||||
val b = decoder.readSlot(code, ip)
|
||||
ip += fn.slotWidth
|
||||
val dst = decoder.readSlot(code, ip)
|
||||
ip += fn.slotWidth
|
||||
frame.setBool(dst, frame.getObj(a).compareTo(scope, frame.getObj(b)) >= 0)
|
||||
}
|
||||
Opcode.NOT_BOOL -> {
|
||||
val src = decoder.readSlot(code, ip)
|
||||
ip += fn.slotWidth
|
||||
|
||||
@ -91,6 +91,10 @@ enum class Opcode(val code: Int) {
|
||||
NOT_BOOL(0x70),
|
||||
AND_BOOL(0x71),
|
||||
OR_BOOL(0x72),
|
||||
CMP_LT_OBJ(0x73),
|
||||
CMP_LTE_OBJ(0x74),
|
||||
CMP_GT_OBJ(0x75),
|
||||
CMP_GTE_OBJ(0x76),
|
||||
|
||||
JMP(0x80),
|
||||
JMP_IF_TRUE(0x81),
|
||||
|
||||
@ -271,4 +271,31 @@ class BytecodeVmTest {
|
||||
val neqResult = BytecodeVm().execute(neqFn, Scope(), emptyList())
|
||||
assertEquals(true, neqResult.toBool())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun objectComparisonUsesBytecodeOps() = kotlinx.coroutines.test.runTest {
|
||||
val ltExpr = ExpressionStatement(
|
||||
BinaryOpRef(
|
||||
BinOp.LT,
|
||||
ConstRef(ObjString("a").asReadonly),
|
||||
ConstRef(ObjString("b").asReadonly),
|
||||
),
|
||||
net.sergeych.lyng.Pos.builtIn
|
||||
)
|
||||
val ltFn = BytecodeCompiler().compileExpression("objLt", ltExpr) ?: error("bytecode compile failed")
|
||||
val ltResult = BytecodeVm().execute(ltFn, Scope(), emptyList())
|
||||
assertEquals(true, ltResult.toBool())
|
||||
|
||||
val gteExpr = ExpressionStatement(
|
||||
BinaryOpRef(
|
||||
BinOp.GTE,
|
||||
ConstRef(ObjString("b").asReadonly),
|
||||
ConstRef(ObjString("a").asReadonly),
|
||||
),
|
||||
net.sergeych.lyng.Pos.builtIn
|
||||
)
|
||||
val gteFn = BytecodeCompiler().compileExpression("objGte", gteExpr) ?: error("bytecode compile failed")
|
||||
val gteResult = BytecodeVm().execute(gteFn, Scope(), emptyList())
|
||||
assertEquals(true, gteResult.toBool())
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user