From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from [87.239.111.99] (localhost [127.0.0.1]) by dev.tarantool.org (Postfix) with ESMTP id 959DF192AC5F; Mon, 2 Mar 2026 10:53:38 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 dev.tarantool.org 959DF192AC5F DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=tarantool.org; s=dev; t=1772438018; bh=j7WISFShncDn1APvZLFI2kmeaMKpod2kvwzaDloeyNg=; h=To:Date:In-Reply-To:References:Subject:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc: From; b=IHp6KYG0TD2ezwPEj3zwLWsbZRA7/P6UmPPdeQX+Q4u0iMjvxPPj76u3qEvBtPoD5 KjHwHtd93ffpjJGZoISkJopvN3b62U002GAZ66z3kiifNAsdcUYVDmIoh2htbhUH6C lyJSQZ2cPb2IPnL+AO+BavCkpy9g+f0sSWI096HU= Received: from send220.i.mail.ru (send220.i.mail.ru [95.163.59.59]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by dev.tarantool.org (Postfix) with ESMTPS id 81B4A192AC52 for ; Mon, 2 Mar 2026 10:52:08 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 dev.tarantool.org 81B4A192AC52 Received: by exim-smtp-558f87dcd7-fq4lx with esmtpa (envelope-from ) id 1vwy4V-00000000798-2VWL; Mon, 02 Mar 2026 10:52:08 +0300 To: Sergey Bronnikov Date: Mon, 2 Mar 2026 10:52:54 +0300 Message-ID: X-Mailer: git-send-email 2.53.0 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Mailru-Src: smtp X-4EC0790: 10 X-7564579A: 646B95376F6C166E X-77F55803: 4F1203BC0FB41BD9FE49BA1A5307ACBFCA02A41DC4BD0C6BD81EB53FB98BE59700894C459B0CD1B9FC188EF2B12C07A891417EB218679B820702564D9F55ED4C955C1C3E78DE33ACF8D9167951636718 X-7FA49CB5: FF5795518A3D127A4AD6D5ED66289B5278DA827A17800CE7F09446BC3D835A58EA1F7E6F0F101C67BD4B6F7A4D31EC0BCC500DACC3FED6E28638F802B75D45FF8AA50765F7900637AC83A81C8FD4AD23D82A6BABE6F325AC2E85FA5F3EDFCBAA7353EFBB55337566487A753D4C0E5B9CFBD0D0035CB5C742BC5C5C503F68D681EDDE4B84EC9096A8389733CBF5DBD5E913377AFFFEAFD269176DF2183F8FC7C0F75B7380DB97F9D88941B15DA834481FCF19DD082D7633A0EF3E4896CB9E6436389733CBF5DBD5E9D5E8D9A59859A8B6D99FB7B2A39B4961CC7F00164DA146DA6F5DAA56C3B73B237318B6A418E8EAB8D32BA5DBAC0009BE9E8FC8737B5C224962EF7529D2A07B7B76E601842F6C81A12EF20D2F80756B5FB606B96278B59C4276E601842F6C81A127C277FBC8AE2E8B0D7DEFD7D73B8B6D3AA81AA40904B5D99C9F4D5AE37F343AD1F44FA8B9022EA23BBE47FD9DD3FB595F5C1EE8F4F765FC72CEEB2601E22B093A03B725D353964B0B7D0EA88DDEDAC722CA9DD8327EE4930A3850AC1BE2E7358734EF69C36C4A4DC4224003CC83647689D4C264860C145E X-C1DE0DAB: 0D63561A33F958A5108651DAB347E6C15002B1117B3ED696E173CBB45CD55FA1A9DAB4B68AE4D22F823CB91A9FED034534781492E4B8EEADF12279BA039A6965C79554A2A72441328621D336A7BC284946AD531847A6065A535571D14F44ED41 X-C8649E89: 1C3962B70DF3F0AD73CAD6646DEDE191716CD42B3DD1D34CAB70F9BE574AE9C625B6776AC983F447FC0B9F89525902EE6F57B2FD27647F25E66C117BDB76D65985DC378A02ECCD9AE673733DE60319E2F14AF2307B93BCA59B757D0F1B73DB26DF164C36FBA267A9B8341EE9D5BE9A0AC27E74FFE334F4E504A95AB9D17039A344196F3DA3F8C28F6536EB022892E5344C41F94D744909CECFA6C6B0C050A61A8CAF69B82BA93681CD72808BE417F3B9E0E7457915DAA85F X-D57D3AED: 3ZO7eAau8CL7WIMRKs4sN3D3tLDjz0dLbV79QFUyzQ2Ujvy7cMT6pYYqY16iZVKkSc3dCLJ7zSJH7+u4VD18S7Vl4ZUrpaVfd2+vE6kuoey4m4VkSEu53w8ahmwBjZKM/YPHZyZHvz5uv+WouB9+ObcCpyrx6l7KImUglyhkEat/+ysWwi0gdhEs0JGjl6ggRWTy1haxBpVdbIX1nthFXMZebaIdHP2ghjoIc/363UZI6Kf1ptIMVbwN8XFWZxQUlq3lMsxCaKs= X-Mailru-Sender: 583F1D7ACE8F49BDD951BA70C165859E4317413AC34EB10CD85FDC519B8364608BCEBD52E3818003942190F95798A970F2400F607609286E924004A7DEC283833C7120B22964430C52B393F8C72A41A84198E0F3ECE9B5443453F38A29522196 X-Mras: Ok Subject: [Tarantool-patches] [PATCH luajit 3/3] DUALNUM: Improve/fix edge cases of unary minus. X-BeenThere: tarantool-patches@dev.tarantool.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: Tarantool development patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , From: Sergey Kaplun via Tarantool-patches Reply-To: Sergey Kaplun Cc: tarantool-patches@dev.tarantool.org Errors-To: tarantool-patches-bounces@dev.tarantool.org Sender: "Tarantool-patches" From: Mike Pall Thanks to Sergey Kaplun. (cherry picked from commit 707c12bf00dafdfd3899b1a6c36435dbbf6c7022) In a single-number build (default for x86/x64), `-(0)` is always `-0` due to its number type. However, in DUALNUM mode, the `0` may have the integer type, and for this integer, `BC_UNM` has no effect. `0` may be represented via number or integer type, where the resulting `0` is constructed during initial parsing (`lj_strscan_scan()`) or arithmetic operations (`BC_MODVV`). This inconsistency may break the JIT semantics and lead to the assertion failure in the `lj_check_slots()`. This patch fixes the incorrect `BC_UNM` for integer operand 0. Also, the narrowing optimization for the unary minus should be more strict to avoid incorrect narrowing for integer slots and make JIT intact with the VM semantics. Sergey Kaplun: * added the description and the test for the problem Part of tarantool/tarantool#12134 --- src/lj_opt_narrow.c | 5 +- src/vm_arm.dasc | 5 +- src/vm_arm64.dasc | 2 + src/vm_mips.dasc | 6 ++- src/vm_mips64.dasc | 6 ++- src/vm_ppc.dasc | 7 ++- src/vm_x64.dasc | 4 ++ src/vm_x86.dasc | 5 ++ .../lj-1422-incorrect-unm-for-mzero.test.lua | 54 +++++++++++++++++++ .../tarantool-tests/lj-1422-unm-zero.test.lua | 12 +++++ 10 files changed, 99 insertions(+), 7 deletions(-) create mode 100644 test/tarantool-tests/lj-1422-incorrect-unm-for-mzero.test.lua create mode 100644 test/tarantool-tests/lj-1422-unm-zero.test.lua diff --git a/src/lj_opt_narrow.c b/src/lj_opt_narrow.c index 6e3e9533..3bf7320d 100644 --- a/src/lj_opt_narrow.c +++ b/src/lj_opt_narrow.c @@ -553,10 +553,9 @@ TRef lj_opt_narrow_unm(jit_State *J, TRef rc, TValue *vc) rc = conv_str_tonum(J, rc, vc); if (tref_isinteger(rc)) { uint32_t k = (uint32_t)numberVint(vc); - if ((tvisint(vc) || k != 0) && k != 0x80000000u) { + if (k != 0 && k != 0x80000000u) { TRef zero = lj_ir_kint(J, 0); - if (!tvisint(vc)) - emitir(IRTGI(IR_NE), rc, zero); + emitir(IRTGI(IR_NE), rc, zero); return emitir(IRTGI(IR_SUBOV), zero, rc); } rc = emitir(IRTN(IR_CONV), rc, IRCONV_NUM_INT); diff --git a/src/vm_arm.dasc b/src/vm_arm.dasc index 7095e660..785d13ac 100644 --- a/src/vm_arm.dasc +++ b/src/vm_arm.dasc @@ -2930,13 +2930,16 @@ static void build_ins(BuildCtx *ctx, BCOp op, int defop) | bhi ->vmeta_unm | eorne CARG2, CARG2, #0x80000000 | bne >5 - | rsbseq CARG1, CARG1, #0 + | rsbs CARG1, CARG1, #0 + | ldrdeq CARG12, >8 | ldrdvs CARG12, >9 |5: | strd CARG12, [BASE, RA] | ins_next3 | |.align 8 + |8: + | .long 0x00000000, 0x80000000 // -0. |9: | .long 0x00000000, 0x41e00000 // 2^31. break; diff --git a/src/vm_arm64.dasc b/src/vm_arm64.dasc index 6600e226..c64b736b 100644 --- a/src/vm_arm64.dasc +++ b/src/vm_arm64.dasc @@ -2481,6 +2481,8 @@ static void build_ins(BuildCtx *ctx, BCOp op, int defop) | movz CARG3, #0x41e0, lsl #48 // 2^31. | add TMP0, TMP0, TISNUM | csel TMP0, TMP0, CARG3, vc + | movz CARG3, #0x8000, lsl #48 // -0. + | csel TMP0, TMP0, CARG3, ne |5: | str TMP0, [BASE, RA, lsl #3] | ins_next diff --git a/src/vm_mips.dasc b/src/vm_mips.dasc index 32caabf7..dcb04ed8 100644 --- a/src/vm_mips.dasc +++ b/src/vm_mips.dasc @@ -3319,7 +3319,8 @@ static void build_ins(BuildCtx *ctx, BCOp op, int defop) | addu RA, BASE, RA | bne SFARG1HI, TISNUM, >2 |. lw SFARG1LO, LO(RB) - | lui TMP1, 0x8000 + | beqz SFARG1LO, >3 + |. lui TMP1, 0x8000 | beq SFARG1LO, TMP1, ->vmeta_unm // Meta handler deals with -2^31. |. negu SFARG1LO, SFARG1LO |1: @@ -3333,6 +3334,9 @@ static void build_ins(BuildCtx *ctx, BCOp op, int defop) |. lui TMP1, 0x8000 | b <1 |. xor SFARG1HI, SFARG1HI, TMP1 + |3: + | b <1 + |. lui SFARG1HI, 0x8000 // -0. break; case BC_LEN: | // RA = dst*8, RD = src*8 diff --git a/src/vm_mips64.dasc b/src/vm_mips64.dasc index 44fba36c..34da6473 100644 --- a/src/vm_mips64.dasc +++ b/src/vm_mips64.dasc @@ -3563,7 +3563,8 @@ static void build_ins(BuildCtx *ctx, BCOp op, int defop) | sextw CARG1, CARG1 | beq CARG1, TMP1, ->vmeta_unm // Meta handler deals with -2^31. |. negu CARG1, CARG1 - | zextw CARG1, CARG1 + | beqz CARG1, >3 + |. zextw CARG1, CARG1 | settp CARG1, TISNUM |1: | ins_next1 @@ -3575,6 +3576,9 @@ static void build_ins(BuildCtx *ctx, BCOp op, int defop) |. dsll TMP1, TMP1, 32 | b <1 |. xor CARG1, CARG1, TMP1 + |3: + | b <1 + |. dsll CARG1, TMP1, 32 break; case BC_LEN: | // RA = dst*8, RD = src*8 diff --git a/src/vm_ppc.dasc b/src/vm_ppc.dasc index 980ad897..88fa7b67 100644 --- a/src/vm_ppc.dasc +++ b/src/vm_ppc.dasc @@ -3803,11 +3803,13 @@ static void build_ins(BuildCtx *ctx, BCOp op, int defop) | bne >5 |.if GPR64 | lus TMP2, 0x8000 - | neg TMP0, TMP0 + | neg. TMP0, TMP0 + | beq >8 | cmplw TMP0, TMP2 | beq >4 |.else | nego. TMP0, TMP0 + | beq >8 | bso >4 |1: |.endif @@ -3834,6 +3836,9 @@ static void build_ins(BuildCtx *ctx, BCOp op, int defop) | stw TMP0, 4(RA) |.if DUALNUM | b <3 + |8: + | lus TMP1, 0x8000 // -0. + | b <7 |.else | ins_next2 |.endif diff --git a/src/vm_x64.dasc b/src/vm_x64.dasc index 8b6781a6..ee669887 100644 --- a/src/vm_x64.dasc +++ b/src/vm_x64.dasc @@ -3179,11 +3179,15 @@ static void build_ins(BuildCtx *ctx, BCOp op, int defop) |.if DUALNUM | checkint RB, >5 | neg RBd + | jz >3 | jo >4 | setint RB |9: | mov [BASE+RA*8], RB | ins_next + |3: + | mov64 RB, U64x(80000000,00000000) // -0. + | jmp <9 |4: | mov64 RB, U64x(41e00000,00000000) // 2^31. | jmp <9 diff --git a/src/vm_x86.dasc b/src/vm_x86.dasc index 7c11c78e..027bdcd6 100644 --- a/src/vm_x86.dasc +++ b/src/vm_x86.dasc @@ -3780,11 +3780,16 @@ static void build_ins(BuildCtx *ctx, BCOp op, int defop) | checkint RD, >5 | mov RB, [BASE+RD*8] | neg RB + | jz >3 | jo >4 | mov dword [BASE+RA*8+4], LJ_TISNUM + |8: | mov dword [BASE+RA*8], RB |9: | ins_next + |3: + | mov dword [BASE+RA*8+4], 0x80000000 // -0. + | jmp <8 |4: | mov dword [BASE+RA*8+4], 0x41e00000 // 2^31. | mov dword [BASE+RA*8], 0 diff --git a/test/tarantool-tests/lj-1422-incorrect-unm-for-mzero.test.lua b/test/tarantool-tests/lj-1422-incorrect-unm-for-mzero.test.lua new file mode 100644 index 00000000..7046784c --- /dev/null +++ b/test/tarantool-tests/lj-1422-incorrect-unm-for-mzero.test.lua @@ -0,0 +1,54 @@ +local tap = require('tap') + +-- This test demonstrates LuaJIT's inconsistencies in the VM and +-- the JIT engine in the DUALNUM mode for 0. +-- See also https://github.com/LuaJIT/LuaJIT/issues/1422. + +local test = tap.test('lj-1422-incorrect-unm-for-mzero'):skipcond({ + ['Test requires JIT enabled'] = not jit.status(), +}) + +test:plan(3) + +local tonumber = tonumber +local tostring = tostring + +local function always_number(val) + return tonumber(val) or 1 +end + +-- Yielded int type for non-x86 arches. +local function modvn(v1) + return always_number(v1) % 1 +end + +local function unm(v) + return -v +end + +jit.opt.start('hotloop=1', 'hotexit=1') + +always_number(nil) -- Root trace. +always_number(nil) + +local stack_slot = nil +for _ = 1, 5 do + always_number(0) -- Compile side trace. + -- The side trace crashes in the `rec_check_slots()` for non-x86 + -- arches before the patch. + stack_slot = tostring(unm(modvn(stack_slot))) +end + +test:is(stack_slot, '-0', 'correct result of the trace execution') + +-- `tonumber()` recording and conversion to number. +local results = {nil, nil, nil, nil} +for i = 1, 4 do + local slot = -tonumber('0') + results[i] = tostring(slot) +end + +test:is(results[1], '-0', 'correct result of the expression') +test:samevalues(results, 'correct result of the tonumber recording') + +test:done(true) diff --git a/test/tarantool-tests/lj-1422-unm-zero.test.lua b/test/tarantool-tests/lj-1422-unm-zero.test.lua new file mode 100644 index 00000000..77062418 --- /dev/null +++ b/test/tarantool-tests/lj-1422-unm-zero.test.lua @@ -0,0 +1,12 @@ +local tap = require('tap') + +-- The test file to demonstrate LuaJIT's incorrect BC_UNM for the +-- 0 operand for the DUALNUM mode. +-- See also https://github.com/LuaJIT/LuaJIT/issues/1422. + +local test = tap.test('lj-1422-unm-zero') +test:plan(1) + +test:ok(tostring(-0) == '-0', 'correct unary minus for 0') + +test:done(true) -- 2.53.0