* [Tarantool-patches] [PATCH luajit 1/2] ARM64: Make tobit conversions match JIT backend behavior.
2026-07-21 14:53 [Tarantool-patches] [PATCH luajit 0/2] Fix tobit conversion on arm architectures Sergey Kaplun via Tarantool-patches
@ 2026-07-21 14:53 ` Sergey Kaplun via Tarantool-patches
2026-07-21 14:53 ` [Tarantool-patches] [PATCH luajit 2/2] ARM: Make hard-float " Sergey Kaplun via Tarantool-patches
1 sibling, 0 replies; 3+ messages in thread
From: Sergey Kaplun via Tarantool-patches @ 2026-07-21 14:53 UTC (permalink / raw)
To: Sergey Bronnikov, Evgeniy Temirgaleev; +Cc: tarantool-patches
From: Mike Pall <mike>
Thanks to Peter Cawley.
(cherry picked from commit cdc2db3aeac442e139c3b1fda715fdfa78da8791)
On the aarch64 architecture, the `tobit()` function incorrectly
truncates instead of rounding to the nearest integer. This leads to
inconsistency between various VMs (comparing to x86/x64, for example)
and between the arm64 VM and JIT.
This patch uses an addition of 2^52 + 2^51 constant to the given
argument to convert it to the nearest integer value. After reading the
lowest 32 bits of the register, we get the expected result.
Sergey Kaplun:
* added the description and the test for the problem
Part of tarantool/tarantool#12880
---
src/vm_arm64.dasc | 20 ++++---------
.../lj-1253-tobit-conversion.test.lua | 28 +++++++++++++++++++
2 files changed, 34 insertions(+), 14 deletions(-)
create mode 100644 test/tarantool-tests/lj-1253-tobit-conversion.test.lua
diff --git a/src/vm_arm64.dasc b/src/vm_arm64.dasc
index 57131140..4ffd7378 100644
--- a/src/vm_arm64.dasc
+++ b/src/vm_arm64.dasc
@@ -1613,22 +1613,14 @@ static void build_subroutines(BuildCtx *ctx)
|
|//-- Bit library --------------------------------------------------------
|
- |// FP number to bit conversion for soft-float. Clobbers CARG1-CARG3
+ |// FP number to bit conversion. Clobbers CARG1-CARG2, FARG1-FARG2.
|->vm_tobit_fb:
| bls ->fff_fallback
- | add CARG2, CARG1, CARG1
- | mov CARG3, #1076
- | sub CARG3, CARG3, CARG2, lsr #53
- | cmp CARG3, #53
- | bhi >1
- | and CARG2, CARG2, #U64x(001fffff,ffffffff)
- | orr CARG2, CARG2, #U64x(00200000,00000000)
- | cmp CARG1, #0
- | lsr CARG2, CARG2, CARG3
- | cneg CARG1w, CARG2w, mi
- | br lr
- |1:
- | mov CARG1w, #0
+ | fmov FARG1, CARG1
+ | movz CARG2, #0x4338, lsl #48
+ | fmov FARG2, CARG2
+ | fadd FARG1, FARG1, FARG2
+ | fmov CARG1w, s0
| br lr
|
|.macro .ffunc_bit, name
diff --git a/test/tarantool-tests/lj-1253-tobit-conversion.test.lua b/test/tarantool-tests/lj-1253-tobit-conversion.test.lua
new file mode 100644
index 00000000..31cf97ca
--- /dev/null
+++ b/test/tarantool-tests/lj-1253-tobit-conversion.test.lua
@@ -0,0 +1,28 @@
+local tap = require('tap')
+
+-- Test file to demonstrate LuaJIT's incorrect bit.tobit
+-- behaviour for arm64.
+-- See also: https://github.com/LuaJIT/LuaJIT/issues/1253.
+
+local test = tap.test('lj-1253-tobit-conversion')
+
+test:plan(2)
+
+test:is(bit.tobit(1.7), 2, 'correct bit.tobit rounding')
+
+test:skipcond({
+ ['Test requires JIT enabled'] = not jit.status(),
+})
+
+local results = {}
+
+jit.opt.start('hotloop=1')
+
+for i = 1, 4 do
+ -- Use constants on trace.
+ results[i] = bit.tobit(1.7)
+end
+
+test:samevalues(results, 'consistent JIT and VM behaviour for bit.tobit')
+
+test:done(true)
--
2.55.0
^ permalink raw reply [flat|nested] 3+ messages in thread* [Tarantool-patches] [PATCH luajit 2/2] ARM: Make hard-float tobit conversions match JIT backend behavior.
2026-07-21 14:53 [Tarantool-patches] [PATCH luajit 0/2] Fix tobit conversion on arm architectures Sergey Kaplun via Tarantool-patches
2026-07-21 14:53 ` [Tarantool-patches] [PATCH luajit 1/2] ARM64: Make tobit conversions match JIT backend behavior Sergey Kaplun via Tarantool-patches
@ 2026-07-21 14:53 ` Sergey Kaplun via Tarantool-patches
1 sibling, 0 replies; 3+ messages in thread
From: Sergey Kaplun via Tarantool-patches @ 2026-07-21 14:53 UTC (permalink / raw)
To: Sergey Bronnikov, Evgeniy Temirgaleev; +Cc: tarantool-patches
From: Mike Pall <mike>
Reported by Peter Cawley.
(cherry picked from commit 32a683d226a3b57adbfeabff17d1ae0f7676545d)
On the arm architecture, the `tobit()` function incorrectly truncates
instead of rounding to the nearest integer. This leads to inconsistency
between various VMs (comparing to x86/x64, for example) and between the
arm VM and JIT.
This patch uses an addition of 2^52 + 2^51 constant to the given
argument to convert it to the nearest integer value. After reading the
lowest 32 bits of the register, we get the expected result.
The test is the same as for the previous commit.
Sergey Kaplun:
* added the description for the problem
Part of tarantool/tarantool#12880
---
src/vm_arm.dasc | 13 ++++++++++++-
1 file changed, 12 insertions(+), 1 deletion(-)
diff --git a/src/vm_arm.dasc b/src/vm_arm.dasc
index 7ed555f8..139f7fed 100644
--- a/src/vm_arm.dasc
+++ b/src/vm_arm.dasc
@@ -1829,9 +1829,19 @@ static void build_subroutines(BuildCtx *ctx)
|
|//-- Bit library --------------------------------------------------------
|
- |// FP number to bit conversion for soft-float. Clobbers r0-r3.
|->vm_tobit_fb:
| bhi ->fff_fallback
+ |.if FPU
+ |// FP number to bit conversion for hard-float. Clobbers r0, d0-d1.
+ | vldr d1, >9
+ | vmov d0, CARG1, CARG2
+ | vadd.f64 d0, d0, d1
+ | vmov CARG1, s0
+ | bx lr
+ |9:
+ | .long 0, 0x43380000 // (double)(2^52 + 2^51).
+ |.else
+ |// FP number to bit conversion for soft-float. Clobbers r0-r3.
|->vm_tobit:
| lsl RB, CARG2, #1
| adds RB, RB, #0x00200000
@@ -1856,6 +1866,7 @@ static void build_subroutines(BuildCtx *ctx)
| orr CARG1, CARG4, CARG1, lsl RB
| rsblt CARG1, CARG1, #0
| bx lr
+ |.endif
|
|.macro .ffunc_bit, name
| .ffunc_1 bit_..name
--
2.55.0
^ permalink raw reply [flat|nested] 3+ messages in thread