Elide redundant bool conversions in logical ops
This commit is contained in:
parent
3e654ddd60
commit
7c28296f92
@ -2339,60 +2339,36 @@ class BytecodeCompiler(
|
||||
|
||||
private fun compileLogicalAnd(ref: LogicalAndRef): CompiledValue? {
|
||||
val leftValue = compileRefWithFallback(ref.left(), SlotType.BOOL, Pos.builtIn) ?: return null
|
||||
val leftBool = if (leftValue.type == SlotType.BOOL) {
|
||||
leftValue
|
||||
} else {
|
||||
val slot = allocSlot()
|
||||
builder.emit(Opcode.OBJ_TO_BOOL, leftValue.slot, slot)
|
||||
CompiledValue(slot, SlotType.BOOL)
|
||||
}
|
||||
if (leftValue.type != SlotType.BOOL) return null
|
||||
val resultSlot = allocSlot()
|
||||
val falseId = builder.addConst(BytecodeConst.Bool(false))
|
||||
builder.emit(Opcode.CONST_BOOL, falseId, resultSlot)
|
||||
val endLabel = builder.label()
|
||||
builder.emit(
|
||||
Opcode.JMP_IF_FALSE,
|
||||
listOf(CmdBuilder.Operand.IntVal(leftBool.slot), CmdBuilder.Operand.LabelRef(endLabel))
|
||||
listOf(CmdBuilder.Operand.IntVal(leftValue.slot), CmdBuilder.Operand.LabelRef(endLabel))
|
||||
)
|
||||
val rightValue = compileRefWithFallback(ref.right(), SlotType.BOOL, Pos.builtIn) ?: return null
|
||||
val rightBool = if (rightValue.type == SlotType.BOOL) {
|
||||
rightValue
|
||||
} else {
|
||||
val slot = allocSlot()
|
||||
builder.emit(Opcode.OBJ_TO_BOOL, rightValue.slot, slot)
|
||||
CompiledValue(slot, SlotType.BOOL)
|
||||
}
|
||||
builder.emit(Opcode.MOVE_BOOL, rightBool.slot, resultSlot)
|
||||
if (rightValue.type != SlotType.BOOL) return null
|
||||
builder.emit(Opcode.MOVE_BOOL, rightValue.slot, resultSlot)
|
||||
builder.mark(endLabel)
|
||||
return CompiledValue(resultSlot, SlotType.BOOL)
|
||||
}
|
||||
|
||||
private fun compileLogicalOr(ref: LogicalOrRef): CompiledValue? {
|
||||
val leftValue = compileRefWithFallback(ref.left(), SlotType.BOOL, Pos.builtIn) ?: return null
|
||||
val leftBool = if (leftValue.type == SlotType.BOOL) {
|
||||
leftValue
|
||||
} else {
|
||||
val slot = allocSlot()
|
||||
builder.emit(Opcode.OBJ_TO_BOOL, leftValue.slot, slot)
|
||||
CompiledValue(slot, SlotType.BOOL)
|
||||
}
|
||||
if (leftValue.type != SlotType.BOOL) return null
|
||||
val resultSlot = allocSlot()
|
||||
val trueId = builder.addConst(BytecodeConst.Bool(true))
|
||||
builder.emit(Opcode.CONST_BOOL, trueId, resultSlot)
|
||||
val endLabel = builder.label()
|
||||
builder.emit(
|
||||
Opcode.JMP_IF_TRUE,
|
||||
listOf(CmdBuilder.Operand.IntVal(leftBool.slot), CmdBuilder.Operand.LabelRef(endLabel))
|
||||
listOf(CmdBuilder.Operand.IntVal(leftValue.slot), CmdBuilder.Operand.LabelRef(endLabel))
|
||||
)
|
||||
val rightValue = compileRefWithFallback(ref.right(), SlotType.BOOL, Pos.builtIn) ?: return null
|
||||
val rightBool = if (rightValue.type == SlotType.BOOL) {
|
||||
rightValue
|
||||
} else {
|
||||
val slot = allocSlot()
|
||||
builder.emit(Opcode.OBJ_TO_BOOL, rightValue.slot, slot)
|
||||
CompiledValue(slot, SlotType.BOOL)
|
||||
}
|
||||
builder.emit(Opcode.MOVE_BOOL, rightBool.slot, resultSlot)
|
||||
if (rightValue.type != SlotType.BOOL) return null
|
||||
builder.emit(Opcode.MOVE_BOOL, rightValue.slot, resultSlot)
|
||||
builder.mark(endLabel)
|
||||
return CompiledValue(resultSlot, SlotType.BOOL)
|
||||
}
|
||||
|
||||
@ -10,8 +10,9 @@ Candidates (not started)
|
||||
2) Mixed numeric ops (done)
|
||||
- Allow INT+REAL arithmetic to use primitive REAL ops (no obj fallback).
|
||||
- MixedCompareBenchmarkTest: 347 ms -> 275 ms.
|
||||
3) Boolean conversion
|
||||
- Skip OBJ_TO_BOOL when compiler already has a BOOL slot.
|
||||
3) Boolean conversion (done; do not revert without review)
|
||||
- Skip redundant OBJ_TO_BOOL in logical AND/OR when compiler already emits BOOL.
|
||||
- MixedCompareBenchmarkTest: 275 ms -> 249 ms.
|
||||
4) Range/loop hot path
|
||||
- Keep range iteration in INT ops, avoid accidental boxing.
|
||||
- Confirm loop-var slots avoid re-boxing in loop bodies.
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user