perf(vm): in-place compare ops + Int-Int fast path
Mirror the treatment LessEqual already got onto Equal/NotEqual/Less/ Greater/GreaterEqual — rewrite sp directly, check the type tag for Int==Int in the hot branch, short-circuit to cachedTrue/cachedFalse without a second method call. Keeps the slow fallback for mixed / string / date types. Bench movement is minor on SQL paths (WHERE is already pcode and skips these ops); the win is on PRG comparisons that cache-miss out of the pcode path — FOR-condition short forms, IF chains, etc. Verification - go test ./... ALL PASS - FiveSql2 test_sql1999 43/43 - tests/compat_harbour 56/56 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -22,9 +22,26 @@ import "strings"
|
||||
// Equal pops two values, pushes boolean result.
|
||||
// Harbour: hb_vmEqual (hvm.c:3974)
|
||||
func (t *Thread) Equal() {
|
||||
b := t.pop()
|
||||
a := t.pop()
|
||||
t.push(MakeBool(valueEqual(a, b)))
|
||||
t.sp -= 2
|
||||
a := t.stack[t.sp]
|
||||
b := t.stack[t.sp+1]
|
||||
t.stack[t.sp+1] = cachedNil
|
||||
// Fast path: Int == Int
|
||||
if a.Type() == tInt && b.Type() == tInt {
|
||||
if int64(a.scalar) == int64(b.scalar) {
|
||||
t.stack[t.sp] = cachedTrue
|
||||
} else {
|
||||
t.stack[t.sp] = cachedFalse
|
||||
}
|
||||
t.sp++
|
||||
return
|
||||
}
|
||||
if valueEqual(a, b) {
|
||||
t.stack[t.sp] = cachedTrue
|
||||
} else {
|
||||
t.stack[t.sp] = cachedFalse
|
||||
}
|
||||
t.sp++
|
||||
}
|
||||
|
||||
// ExactEqual pops two values, pushes boolean result.
|
||||
@@ -37,9 +54,25 @@ func (t *Thread) ExactEqual() {
|
||||
|
||||
// NotEqual pops two values, pushes boolean result.
|
||||
func (t *Thread) NotEqual() {
|
||||
b := t.pop()
|
||||
a := t.pop()
|
||||
t.push(MakeBool(!valueEqual(a, b)))
|
||||
t.sp -= 2
|
||||
a := t.stack[t.sp]
|
||||
b := t.stack[t.sp+1]
|
||||
t.stack[t.sp+1] = cachedNil
|
||||
if a.Type() == tInt && b.Type() == tInt {
|
||||
if int64(a.scalar) != int64(b.scalar) {
|
||||
t.stack[t.sp] = cachedTrue
|
||||
} else {
|
||||
t.stack[t.sp] = cachedFalse
|
||||
}
|
||||
t.sp++
|
||||
return
|
||||
}
|
||||
if !valueEqual(a, b) {
|
||||
t.stack[t.sp] = cachedTrue
|
||||
} else {
|
||||
t.stack[t.sp] = cachedFalse
|
||||
}
|
||||
t.sp++
|
||||
}
|
||||
|
||||
// --- Relational operators ---
|
||||
@@ -47,13 +80,29 @@ func (t *Thread) NotEqual() {
|
||||
// Less pops two values, pushes boolean result.
|
||||
// Harbour: hb_vmLess (hvm.c:4176)
|
||||
func (t *Thread) Less() {
|
||||
b := t.pop()
|
||||
a := t.pop()
|
||||
t.sp -= 2
|
||||
a := t.stack[t.sp]
|
||||
b := t.stack[t.sp+1]
|
||||
t.stack[t.sp+1] = cachedNil
|
||||
if a.Type() == tInt && b.Type() == tInt {
|
||||
if int64(a.scalar) < int64(b.scalar) {
|
||||
t.stack[t.sp] = cachedTrue
|
||||
} else {
|
||||
t.stack[t.sp] = cachedFalse
|
||||
}
|
||||
t.sp++
|
||||
return
|
||||
}
|
||||
cmp, ok := valueCompare(a, b)
|
||||
if !ok {
|
||||
panic(t.argError("<", a, b))
|
||||
}
|
||||
t.push(MakeBool(cmp < 0))
|
||||
if cmp < 0 {
|
||||
t.stack[t.sp] = cachedTrue
|
||||
} else {
|
||||
t.stack[t.sp] = cachedFalse
|
||||
}
|
||||
t.sp++
|
||||
}
|
||||
|
||||
// LessEqual pops two values, pushes boolean result.
|
||||
@@ -86,24 +135,56 @@ func (t *Thread) LessEqual() {
|
||||
|
||||
// Greater pops two values, pushes boolean result.
|
||||
func (t *Thread) Greater() {
|
||||
b := t.pop()
|
||||
a := t.pop()
|
||||
t.sp -= 2
|
||||
a := t.stack[t.sp]
|
||||
b := t.stack[t.sp+1]
|
||||
t.stack[t.sp+1] = cachedNil
|
||||
if a.Type() == tInt && b.Type() == tInt {
|
||||
if int64(a.scalar) > int64(b.scalar) {
|
||||
t.stack[t.sp] = cachedTrue
|
||||
} else {
|
||||
t.stack[t.sp] = cachedFalse
|
||||
}
|
||||
t.sp++
|
||||
return
|
||||
}
|
||||
cmp, ok := valueCompare(a, b)
|
||||
if !ok {
|
||||
panic(t.argError(">", a, b))
|
||||
}
|
||||
t.push(MakeBool(cmp > 0))
|
||||
if cmp > 0 {
|
||||
t.stack[t.sp] = cachedTrue
|
||||
} else {
|
||||
t.stack[t.sp] = cachedFalse
|
||||
}
|
||||
t.sp++
|
||||
}
|
||||
|
||||
// GreaterEqual pops two values, pushes boolean result.
|
||||
func (t *Thread) GreaterEqual() {
|
||||
b := t.pop()
|
||||
a := t.pop()
|
||||
t.sp -= 2
|
||||
a := t.stack[t.sp]
|
||||
b := t.stack[t.sp+1]
|
||||
t.stack[t.sp+1] = cachedNil
|
||||
if a.Type() == tInt && b.Type() == tInt {
|
||||
if int64(a.scalar) >= int64(b.scalar) {
|
||||
t.stack[t.sp] = cachedTrue
|
||||
} else {
|
||||
t.stack[t.sp] = cachedFalse
|
||||
}
|
||||
t.sp++
|
||||
return
|
||||
}
|
||||
cmp, ok := valueCompare(a, b)
|
||||
if !ok {
|
||||
panic(t.argError(">=", a, b))
|
||||
}
|
||||
t.push(MakeBool(cmp >= 0))
|
||||
if cmp >= 0 {
|
||||
t.stack[t.sp] = cachedTrue
|
||||
} else {
|
||||
t.stack[t.sp] = cachedFalse
|
||||
}
|
||||
t.sp++
|
||||
}
|
||||
|
||||
// --- Logical operators ---
|
||||
|
||||
Reference in New Issue
Block a user