diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/bytecode/BytecodeCompiler.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/bytecode/BytecodeCompiler.kt index cfbeb06..523911a 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/bytecode/BytecodeCompiler.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/bytecode/BytecodeCompiler.kt @@ -1374,23 +1374,6 @@ class BytecodeCompiler( val rightRef = binaryRight(ref) var a = compileRefWithFallback(leftRef, null, refPos(ref)) ?: return null var b = compileRefWithFallback(rightRef, null, refPos(ref)) ?: return null - if (op in setOf(BinOp.PLUS, BinOp.MINUS, BinOp.STAR, BinOp.SLASH, BinOp.PERCENT)) { - val leftNeedsObj = a.type == SlotType.INT && b.type == SlotType.REAL - val rightNeedsObj = b.type == SlotType.INT && a.type == SlotType.REAL - if (leftNeedsObj || rightNeedsObj) { - val leftObj = if (leftNeedsObj) { - compileScopeSlotObj(leftRef) ?: a - } else { - a - } - val rightObj = if (rightNeedsObj) { - compileScopeSlotObj(rightRef) ?: b - } else { - b - } - return compileObjBinaryOp(leftRef, leftObj, rightObj, op, refPos(ref)) - } - } val intOps = setOf( BinOp.PLUS, BinOp.MINUS, BinOp.STAR, BinOp.SLASH, BinOp.PERCENT, BinOp.BAND, BinOp.BOR, BinOp.BXOR, BinOp.SHL, BinOp.SHR @@ -1413,7 +1396,11 @@ class BytecodeCompiler( } val typesMismatch = a.type != b.type && a.type != SlotType.UNKNOWN && b.type != SlotType.UNKNOWN val allowMixedNumeric = op in setOf(BinOp.PLUS, BinOp.MINUS, BinOp.STAR, BinOp.SLASH) - if (typesMismatch && op in setOf(BinOp.PLUS, BinOp.MINUS, BinOp.STAR, BinOp.SLASH, BinOp.PERCENT)) { + val isMixedNumeric = (a.type == SlotType.INT && b.type == SlotType.REAL) || + (a.type == SlotType.REAL && b.type == SlotType.INT) + if (typesMismatch && op in setOf(BinOp.PLUS, BinOp.MINUS, BinOp.STAR, BinOp.SLASH, BinOp.PERCENT) && + !(allowMixedNumeric && isMixedNumeric) + ) { return compileObjBinaryOp(leftRef, a, b, op, refPos(ref)) } if ((a.type == SlotType.UNKNOWN || b.type == SlotType.UNKNOWN) && diff --git a/notes/fast_ops_optimizations_plan.md b/notes/fast_ops_optimizations_plan.md index a040538..cbe8d64 100644 --- a/notes/fast_ops_optimizations_plan.md +++ b/notes/fast_ops_optimizations_plan.md @@ -7,8 +7,9 @@ Candidates (not started) 1) Primitive comparisons (done) - Emit fast CMP variants for known ObjString/ObjInt/ObjReal using temp/stable slots. - MixedCompareBenchmarkTest: 374 ms -> 347 ms. -2) Mixed numeric ops - - Ensure INT+REAL arithmetic uses INT_TO_REAL + REAL op with no extra moves/boxing. +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. 4) Range/loop hot path