* [Tarantool-patches] [PATCH luajit] Fix narrowing of unary minus. @ 2022-09-09 12:15 Maksim Kokryashkin via Tarantool-patches 2022-09-14 22:06 ` Sergey Kaplun via Tarantool-patches 2022-12-12 9:42 ` [Tarantool-patches] [PATCH luajit] " Igor Munkin via Tarantool-patches 0 siblings, 2 replies; 10+ messages in thread From: Maksim Kokryashkin via Tarantool-patches @ 2022-09-09 12:15 UTC (permalink / raw) To: tarantool-patches, imun, skaplun From: Mike Pall <mike> With DUALNUM mode disabled, unary minus narrowing can produce inconsistent results on zeros, returning both -0 and 0 on the same chunk of code. This patch fixes the inconsistency by adding checks for zeros. Part of tarantool/tarantool#7230 Resolves tarantool/tarantool#6976 --- Issue: https://github.com/tarantool/tarantool/issues/6976 Branch: https://github.com/tarantool/luajit/tree/fckxorg/gh-6976-narrowing-of-unary-minus PR: https://github.com/tarantool/tarantool/pull/7662 src/lj_opt_narrow.c | 9 +++-- .../gh-6976-narrowing-of-unary-minus.test.lua | 34 +++++++++++++++++++ 2 files changed, 41 insertions(+), 2 deletions(-) create mode 100644 test/tarantool-tests/gh-6976-narrowing-of-unary-minus.test.lua diff --git a/src/lj_opt_narrow.c b/src/lj_opt_narrow.c index cd96ca4b..bb61f97b 100644 --- a/src/lj_opt_narrow.c +++ b/src/lj_opt_narrow.c @@ -551,8 +551,13 @@ TRef lj_opt_narrow_unm(jit_State *J, TRef rc, TValue *vc) { rc = conv_str_tonum(J, rc, vc); if (tref_isinteger(rc)) { - if ((uint32_t)numberVint(vc) != 0x80000000u) - return emitir(IRTGI(IR_SUBOV), lj_ir_kint(J, 0), rc); + uint32_t k = (uint32_t)numberVint(vc); + if ((LJ_DUALNUM || k != 0) && k != 0x80000000u) { + TRef zero = lj_ir_kint(J, 0); + if (!LJ_DUALNUM) + emitir(IRTGI(IR_NE), rc, zero); + return emitir(IRTGI(IR_SUBOV), zero, rc); + } rc = emitir(IRTN(IR_CONV), rc, IRCONV_NUM_INT); } return emitir(IRTN(IR_NEG), rc, lj_ir_ksimd(J, LJ_KSIMD_NEG)); diff --git a/test/tarantool-tests/gh-6976-narrowing-of-unary-minus.test.lua b/test/tarantool-tests/gh-6976-narrowing-of-unary-minus.test.lua new file mode 100644 index 00000000..caae8c34 --- /dev/null +++ b/test/tarantool-tests/gh-6976-narrowing-of-unary-minus.test.lua @@ -0,0 +1,34 @@ +require("utils").skipcond( + jit.arch ~= "x86" and jit.arch ~= "x64", + "DUALNUM mode must be disabled" +) + +local tap = require("tap") +local test = tap.test("gh-6976-narrowing-of-unary-minus") +test:plan(1) + +jit.off() +jit.flush() +jit.opt.start('hotloop=1') +jit.on() + +local has_error = false + +-- The first two iterations are needed to write trace in a way +-- where `a` is treated like a non-zero integer value. After the +-- first two iterations 'a' becomes a zero integer, but it is still +-- processed by the same trace. Finally, roughly ten loop +-- iterations later, a new trace is formed, where `a` is treated +-- like a number. +for i=1,20 do + local a = 1 + if i > 2 then + a = 0 + end + a = -a + has_error = has_error or tostring(a):match("%-%d") == nil +end + +test:ok(has_error == false, "inconsistent unary minus result") +os.exit(test:check() and 0 or 1) + -- 2.32.1 (Apple Git-133) ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [Tarantool-patches] [PATCH luajit] Fix narrowing of unary minus. 2022-09-09 12:15 [Tarantool-patches] [PATCH luajit] Fix narrowing of unary minus Maksim Kokryashkin via Tarantool-patches @ 2022-09-14 22:06 ` Sergey Kaplun via Tarantool-patches 2022-09-20 11:16 ` [Tarantool-patches] [PATCH luajit v2] " Maksim Kokryashkin via Tarantool-patches 2022-12-12 9:42 ` [Tarantool-patches] [PATCH luajit] " Igor Munkin via Tarantool-patches 1 sibling, 1 reply; 10+ messages in thread From: Sergey Kaplun via Tarantool-patches @ 2022-09-14 22:06 UTC (permalink / raw) To: Maksim Kokryashkin; +Cc: tarantool-patches Hi, Maxim! Thanks for the patch! Please consider my comments below. On 09.09.22, Maksim Kokryashkin wrote: > From: Mike Pall <mike> > Please, don't forget the common cherry-picked header: | (cherry picked from commit 1e6e8aaa20626ac94cf907c69b0452f76e9f5fa5) It is necessary to recognize the original commit without grepping of LuaJIT source code. > With DUALNUM mode disabled, unary minus narrowing can produce > inconsistent results on zeros, returning both -0 and 0 on the > same chunk of code. > > This patch fixes the inconsistency by adding checks for zeros. I suggest to reformulate these paragraphes like the following: | LuaJIT narrowing optimization during BC_UNM recording may ignore | information about sign of zero for integer types of IR. So far the | resulting value on a trace is not the same as for the interpreter. | However, in DUALNUM mode with using of TValues containing integers the | -0 value is represented in the same way as the 0 value and there is no | difference between them. | | This patch fixes the non-DUALNUM mode behaviour. When the zero value is | identified during recording it should be cast to number so IR_CONV is | emitted. Also, this patch adds assertion guard checking that value on | which operation of unary minus is performed isn't zero. Feel free to modify it as you wish. > Don't be shy to mention your impact in this patch (description and tests) like it is done in previous backported commits. > Part of tarantool/tarantool#7230 > Resolves tarantool/tarantool#6976 Minor: Igor prefers to place the resolved issue first (as far as this is the main issue to close). I prefer the opposite order. But we've agreed with Igor's way, so let use it for consistency. > --- > Issue: https://github.com/tarantool/tarantool/issues/6976 > Branch: https://github.com/tarantool/luajit/tree/fckxorg/gh-6976-narrowing-of-unary-minus > PR: https://github.com/tarantool/tarantool/pull/7662 > > src/lj_opt_narrow.c | 9 +++-- > .../gh-6976-narrowing-of-unary-minus.test.lua | 34 +++++++++++++++++++ > 2 files changed, 41 insertions(+), 2 deletions(-) > create mode 100644 test/tarantool-tests/gh-6976-narrowing-of-unary-minus.test.lua > > diff --git a/src/lj_opt_narrow.c b/src/lj_opt_narrow.c > index cd96ca4b..bb61f97b 100644 > --- a/src/lj_opt_narrow.c > +++ b/src/lj_opt_narrow.c > @@ -551,8 +551,13 @@ TRef lj_opt_narrow_unm(jit_State *J, TRef rc, TValue *vc) > { > rc = conv_str_tonum(J, rc, vc); > if (tref_isinteger(rc)) { > - if ((uint32_t)numberVint(vc) != 0x80000000u) > - return emitir(IRTGI(IR_SUBOV), lj_ir_kint(J, 0), rc); > + uint32_t k = (uint32_t)numberVint(vc); > + if ((LJ_DUALNUM || k != 0) && k != 0x80000000u) { > + TRef zero = lj_ir_kint(J, 0); > + if (!LJ_DUALNUM) > + emitir(IRTGI(IR_NE), rc, zero); > + return emitir(IRTGI(IR_SUBOV), zero, rc); > + } Side note: I wonder how much it is better to use this brancn in narrowing optimization for non-DUALNUMBER mode, as far as we even add additional assertion guard for zero check (IR_NE). Assume we have the following code: | local r = 0 | for i = 1, 1e9 do | local a = -i | r = r + a | end | print(r) Before the patch we've had the following IRs for LOOP part: | ------ LOOP ------------ | 0009 > int SUBOV +0 0006 | 0010 num CONV 0009 num.int | 0011 + num ADD 0010 0005 | 0012 + int ADD 0006 +1 | 0013 > int LE 0012 +1000000000 | 0014 int PHI 0006 0012 | 0015 num PHI 0005 0011 And after patch: | ------ LOOP ------------ | 0010 > int NE 0007 +0 | 0011 > int SUBOV +0 0007 | 0012 num CONV 0011 num.int | 0013 + num ADD 0012 0006 | 0014 + int ADD 0007 +1 | 0015 > int LE 0014 +1000000000 | 0016 int PHI 0007 0014 | 0017 num PHI 0006 0013 This leads to the following additional instructions: | test ebp, ebp | jz 0x561394990018 ->2 I run 10 loops like the aforementioned one with 21e8 iterations. The average time for 5 runs (of 10 loops) before the patch: 25.763s The average time for 5 runs (of 10 loops) after the patch: 25.885s And, actually, if we skip this optimization with the following patch (I just skip the branch with SUBOV emitting for non-DUALNUMBER mode): =================================================================== diff --git a/src/lj_opt_narrow.c b/src/lj_opt_narrow.c index bb61f97b..aaa5b3cd 100644 --- a/src/lj_opt_narrow.c +++ b/src/lj_opt_narrow.c @@ -552,7 +552,7 @@ 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 ((LJ_DUALNUM || k != 0) && k != 0x80000000u) { + if ((LJ_DUALNUM) && k != 0x80000000u) { TRef zero = lj_ir_kint(J, 0); if (!LJ_DUALNUM) emitir(IRTGI(IR_NE), rc, zero); =================================================================== The IRs for the loop part are the following: | ------ LOOP ------------ | 0010 num CONV 0007 num.int | 0011 + num SUB 0006 0010 | 0012 + int ADD 0007 +1 | 0013 > int LE 0012 +1000000000 | 0014 int PHI 0007 0012 | 0015 num PHI 0006 0011 As you can see we have even 2 IRs instead of 4 (we skip assertion guard and creation of negative number -- we just use substitution instead of addition). I suppose for non-DUALNUM mode this is the __common__ case -- operations in doubles, not integers (it may be different for cdata indexes -- I don't check it). As far as we have only 3 instructions for this loop payload: | xorps xmm6, xmm6 | cvtsi2sd xmm6, ebp | subsd xmm7, xmm6 instead of old 8 instructions: | test ebp, ebp | jz 0x555995dc0018 ->2 | xor ebx, ebx | sub ebx, ebp | jo 0x555995dc0018 ->2 | xorps xmm6, xmm6 | cvtsi2sd xmm6, ebx | addsd xmm7, xmm6 the results are slightly better: 25.368s I understand, that the benchmark is kinda synthetic, but still... P.S. For others payload the result can be the diffirent, but this code looks like the most common, as I said before. I mean constructions like the following: | local a = -b; | c = d + a Also, it is converted to number anyway in HREF: | 0021 > int NE 0018 +0 | 0022 > int SUBOV +0 0018 | 0023 int FLOAD 0004 tab.asize | 0024 > int EQ 0023 +0 | 0025 num CONV 0022 num.int | 0026 p32 HREF 0004 0025 with the following assembly: | mov edi, [0x40162540] | mov esi, [rsp+0x10] | | test ebp, ebp | jz 0x558aff9c0018 ->2 | xor r15d, r15d | sub r15d, ebp | jo 0x558aff9c0018 ->2 | | mov ebx, [rsi+0x18] | test ebx, ebx | jnz 0x558aff9c0018 ->2 | | xorps xmm7, xmm7 | cvtsi2sd xmm7, r15d | | movq rdx, xmm7 for the following compiled code: | local a = tab[-i] -- type(tab) == 'table' Without NE, SUBOV emitting IRs are the following: | 0020 num CONV 0017 num.int | 0021 num NEG 0020 0003 | 0022 int FLOAD 0005 tab.asize | 0023 > int EQ 0022 +0 | 0024 p32 HREF 0005 0021 with the following assembly: | mov edi, [0x40093540] | mov esi, [rsp+0x10] | | xorps xmm7, xmm7 | cvtsi2sd xmm7, ebp | movsd [rsp+0x8], xmm7 | movaps xmm6, xmm7 | xorps xmm6, [0x400936f0] | | mov ebx, [rsi+0x18] | test ebx, ebx | jnz 0x55c341180018 ->2 | | movq rdx, xmm6 Average time when run 3 chunks like the following: | local r = require"table.new"(1e8, 0) | for i = 1, 1e8 do | local a = r[-i] | r[i] = a | end | print(r) With NE and SUBOV: 7.769s Without: 7.670s Also, it is obviously more natural to use this cast in DUALNUMBER mode, where integer TValues are usual. P.P.S. The patch itself as a bugfix LGTM. P.P.P.S. Thoughts? :) > rc = emitir(IRTN(IR_CONV), rc, IRCONV_NUM_INT); > } > return emitir(IRTN(IR_NEG), rc, lj_ir_ksimd(J, LJ_KSIMD_NEG)); > diff --git a/test/tarantool-tests/gh-6976-narrowing-of-unary-minus.test.lua b/test/tarantool-tests/gh-6976-narrowing-of-unary-minus.test.lua > new file mode 100644 > index 00000000..caae8c34 > --- /dev/null > +++ b/test/tarantool-tests/gh-6976-narrowing-of-unary-minus.test.lua Side note: This 6976 issue has no description, but OK :) > @@ -0,0 +1,34 @@ > +require("utils").skipcond( Minor: Use single quotes instead of double quotes. > + jit.arch ~= "x86" and jit.arch ~= "x64", > + "DUALNUM mode must be disabled" > +) Not sure that we must skip other arches, see argumentation below. > + > +local tap = require("tap") > +local test = tap.test("gh-6976-narrowing-of-unary-minus") > +test:plan(1) > + > +jit.off() > +jit.flush() > +jit.opt.start('hotloop=1') > +jit.on() Don't see the reason to restart the JIT compiler at this point. Just set the option is enough. > + > +local has_error = false > + > +-- The first two iterations are needed to write trace in a way > +-- where `a` is treated like a non-zero integer value. After the > +-- first two iterations 'a' becomes a zero integer, but it is still > +-- processed by the same trace. Finally, roughly ten loop These ten iterations are needed for side trace compilation. You can set hotexit=1 to start compiling trace at the first trace exit. But this is not necessary, see argumentation below. > +-- iterations later, a new trace is formed, where `a` is treated > +-- like a number. > +for i=1,20 do > + local a = 1 > + if i > 2 then > + a = 0 > + end > + a = -a > + has_error = has_error or tostring(a):match("%-%d") == nil > +end Actually, I don't see the reason for such complicated test case. We can just use the following (with better naming, etc.): | local res = require'table.new'(3, 0) | | for _ = 1, 3 do | local a = 0 | a = -a | table.insert(res, tostring(a)) | end We use `table.new()` here to avoid trace exits due to table rehashing (such trace exits return us to the interpreter and you see the -0 value instead of expected 0, when test failure expected without the patch). In your test case you actually want to verify, that behaviour for JIT compiled code and interpreter is the same. So we can run the loop above with JIT on/off and verify those tables' content is the same. From this point of view, there is no different for the DUALNUMBER mode in this test -- the results should be equal for the JIT and the interpreter (but it will be nice manner to write the comment with expected content for both modes). > + > +test:ok(has_error == false, "inconsistent unary minus result") For now we check only _recording_ for 0. But we should also check the added assertion guard. I suggest the test like the following: | local res2 = require"table.new"(3,0) | | for i = 2, 0, -1 do | table.insert(res2, tostring(-i)) | end > +os.exit(test:check() and 0 or 1) > + > -- > 2.32.1 (Apple Git-133) > -- Best regards, Sergey Kaplun ^ permalink raw reply [flat|nested] 10+ messages in thread
* [Tarantool-patches] [PATCH luajit v2] Fix narrowing of unary minus. 2022-09-14 22:06 ` Sergey Kaplun via Tarantool-patches @ 2022-09-20 11:16 ` Maksim Kokryashkin via Tarantool-patches 2022-09-21 8:48 ` Sergey Kaplun via Tarantool-patches 2022-09-25 21:31 ` sergos via Tarantool-patches 0 siblings, 2 replies; 10+ messages in thread From: Maksim Kokryashkin via Tarantool-patches @ 2022-09-20 11:16 UTC (permalink / raw) To: tarantool-patches, imun, skaplun From: Mike Pall <mike> (cherry picked from commit 1e6e8aaa20626ac94cf907c69b0452f76e9f5fa5) LuaJIT narrowing optimization during BC_UNM recording may ignore information about sign of zero for integer types of IR. So far the resulting value on a trace is not the same as for the interpreter. However, in DUALNUM mode with using of TValues containing integers the -0 value is represented in the same way as the 0 value and there is no difference between them. This patch fixes the non-DUALNUM mode behaviour. When the zero value is identified during recording it should be cast to number so IR_CONV is emitted. Also, this patch adds assertion guard checking that value on which operation of unary minus is performed isn't zero. Maxim Kokryashkin: * added the description and the test for the problem Resolves tarantool/tarantool#6976 Part of tarantool/tarantool#7230 --- Changes in v2: - Fixed test and commit message as per review by Sergey Branch and PR are updated. src/lj_opt_narrow.c | 9 +++- .../gh-6976-narrowing-of-unary-minus.test.lua | 51 +++++++++++++++++++ 2 files changed, 58 insertions(+), 2 deletions(-) create mode 100644 test/tarantool-tests/gh-6976-narrowing-of-unary-minus.test.lua diff --git a/src/lj_opt_narrow.c b/src/lj_opt_narrow.c index cd96ca4b..bb61f97b 100644 --- a/src/lj_opt_narrow.c +++ b/src/lj_opt_narrow.c @@ -551,8 +551,13 @@ TRef lj_opt_narrow_unm(jit_State *J, TRef rc, TValue *vc) { rc = conv_str_tonum(J, rc, vc); if (tref_isinteger(rc)) { - if ((uint32_t)numberVint(vc) != 0x80000000u) - return emitir(IRTGI(IR_SUBOV), lj_ir_kint(J, 0), rc); + uint32_t k = (uint32_t)numberVint(vc); + if ((LJ_DUALNUM || k != 0) && k != 0x80000000u) { + TRef zero = lj_ir_kint(J, 0); + if (!LJ_DUALNUM) + emitir(IRTGI(IR_NE), rc, zero); + return emitir(IRTGI(IR_SUBOV), zero, rc); + } rc = emitir(IRTN(IR_CONV), rc, IRCONV_NUM_INT); } return emitir(IRTN(IR_NEG), rc, lj_ir_ksimd(J, LJ_KSIMD_NEG)); diff --git a/test/tarantool-tests/gh-6976-narrowing-of-unary-minus.test.lua b/test/tarantool-tests/gh-6976-narrowing-of-unary-minus.test.lua new file mode 100644 index 00000000..18778a55 --- /dev/null +++ b/test/tarantool-tests/gh-6976-narrowing-of-unary-minus.test.lua @@ -0,0 +1,51 @@ +local tap = require('tap') +local test = tap.test('gh-6976-narrowing-of-unary-minus') +test:plan(2) + +jit.opt.start('hotloop=1', 'hotexit=1') + +local function check(routine) + jit.off() + jit.flush() + local interp_res = routine() + jit.on() + local jit_res = routine() + + for i = 1, #interp_res do + if interp_res[i] ~= jit_res[i] then + return false + end + end + + return true +end + +test:ok( + check( + function() + local res = require('table.new')(3, 0) + for _ = 1, 3 do + local zero = 0 + zero = -zero + table.insert(res, tostring(zero)) + end + return res + end + ), + 'incorrect recording for zero' +) + +test:ok( + check( + function() + local res = require('table.new')(3, 0) + for i = 2, 0, -1 do + table.insert(res, tostring(-i)) + end + return res + end + ), + 'assertion guard fail' +) + +os.exit(test:check() and 0 or 1) -- 2.32.1 (Apple Git-133) ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [Tarantool-patches] [PATCH luajit v2] Fix narrowing of unary minus. 2022-09-20 11:16 ` [Tarantool-patches] [PATCH luajit v2] " Maksim Kokryashkin via Tarantool-patches @ 2022-09-21 8:48 ` Sergey Kaplun via Tarantool-patches 2022-09-25 21:31 ` sergos via Tarantool-patches 1 sibling, 0 replies; 10+ messages in thread From: Sergey Kaplun via Tarantool-patches @ 2022-09-21 8:48 UTC (permalink / raw) To: Maksim Kokryashkin; +Cc: tarantool-patches Hi, Maxim! Thanks for the fixes! LGTM, except a few nits below. On 20.09.22, Maksim Kokryashkin wrote: > From: Mike Pall <mike> > <snipped> > src/lj_opt_narrow.c | 9 +++- > .../gh-6976-narrowing-of-unary-minus.test.lua | 51 +++++++++++++++++++ > 2 files changed, 58 insertions(+), 2 deletions(-) > create mode 100644 test/tarantool-tests/gh-6976-narrowing-of-unary-minus.test.lua > > diff --git a/src/lj_opt_narrow.c b/src/lj_opt_narrow.c > index cd96ca4b..bb61f97b 100644 > --- a/src/lj_opt_narrow.c > +++ b/src/lj_opt_narrow.c <snipped> > diff --git a/test/tarantool-tests/gh-6976-narrowing-of-unary-minus.test.lua b/test/tarantool-tests/gh-6976-narrowing-of-unary-minus.test.lua > new file mode 100644 > index 00000000..18778a55 > --- /dev/null > +++ b/test/tarantool-tests/gh-6976-narrowing-of-unary-minus.test.lua > @@ -0,0 +1,51 @@ > +local tap = require('tap') > +local test = tap.test('gh-6976-narrowing-of-unary-minus') > +test:plan(2) > + > +jit.opt.start('hotloop=1', 'hotexit=1') As far as we use `table.new` there is no table resizing, so there are no exits from traces to compile and 'hotexit=1' can be removed. > + > +local function check(routine) > + jit.off() > + jit.flush() > + local interp_res = routine() > + jit.on() > + local jit_res = routine() > + > + for i = 1, #interp_res do > + if interp_res[i] ~= jit_res[i] then > + return false > + end > + end > + > + return true > +end > + > +test:ok( Minor: I suggest the following indentation to make this chunk more readable: | test:ok(check(function() | local res = require('table.new')(3, 0) | for _ = 1, 3 do | local zero = 0 | zero = -zero | table.insert(res, tostring(zero)) | end | return res | end), 'incorrect recording for zero') Feel free to ignore. > + check( > + function() > + local res = require('table.new')(3, 0) Please, add a comment why do we use `table.new` here. > + for _ = 1, 3 do > + local zero = 0 > + zero = -zero > + table.insert(res, tostring(zero)) Minor: we need `tostring()` routine to get different strings for -0 and 0, as far as 0 == -0 as numbers. Please, add the corresponding comment. > + end > + return res > + end > + ), > + 'incorrect recording for zero' > +) > + Ditto, about indentation. Feel free to ignore. > +test:ok( > + check( > + function() > + local res = require('table.new')(3, 0) > + for i = 2, 0, -1 do > + table.insert(res, tostring(-i)) > + end > + return res > + end > + ), > + 'assertion guard fail' > +) > + > +os.exit(test:check() and 0 or 1) > -- > 2.32.1 (Apple Git-133) > -- Best regards, Sergey Kaplun ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [Tarantool-patches] [PATCH luajit v2] Fix narrowing of unary minus. 2022-09-20 11:16 ` [Tarantool-patches] [PATCH luajit v2] " Maksim Kokryashkin via Tarantool-patches 2022-09-21 8:48 ` Sergey Kaplun via Tarantool-patches @ 2022-09-25 21:31 ` sergos via Tarantool-patches 2022-09-29 9:58 ` Maxim Kokryashkin via Tarantool-patches 1 sibling, 1 reply; 10+ messages in thread From: sergos via Tarantool-patches @ 2022-09-25 21:31 UTC (permalink / raw) To: Maksim Kokryashkin; +Cc: tarantool-patches Hi! Thanks for the patch! I have two questions below. Sergos > On 20 Sep 2022, at 14:16, Maksim Kokryashkin via Tarantool-patches <tarantool-patches@dev.tarantool.org> wrote: > > From: Mike Pall <mike> > > (cherry picked from commit 1e6e8aaa20626ac94cf907c69b0452f76e9f5fa5) > > LuaJIT narrowing optimization during BC_UNM recording may ignore > information about sign of zero for integer types of IR. So far the > resulting value on a trace is not the same as for the interpreter. I didn’t get the point - how is it detected, otherwise than tostring()? If so - should we change the tostring() instead? Otherwise - we need a test that exposes this difference. > However, in DUALNUM mode with using of TValues containing integers the > -0 value is represented in the same way as the 0 value and there is no > difference between them. > > This patch fixes the non-DUALNUM mode behaviour. When the zero value is > identified during recording it should be cast to number so IR_CONV is > emitted. Also, this patch adds assertion guard checking that value on > which operation of unary minus is performed isn't zero. Does it mean I will exit the trace every time I met a `x = 0; x = -x` in it? > > Maxim Kokryashkin: > * added the description and the test for the problem > > Resolves tarantool/tarantool#6976 > Part of tarantool/tarantool#7230 > --- > > Changes in v2: > - Fixed test and commit message as per review by Sergey > > Branch and PR are updated. > > src/lj_opt_narrow.c | 9 +++- > .../gh-6976-narrowing-of-unary-minus.test.lua | 51 +++++++++++++++++++ > 2 files changed, 58 insertions(+), 2 deletions(-) > create mode 100644 test/tarantool-tests/gh-6976-narrowing-of-unary-minus.test.lua > > diff --git a/src/lj_opt_narrow.c b/src/lj_opt_narrow.c > index cd96ca4b..bb61f97b 100644 > --- a/src/lj_opt_narrow.c > +++ b/src/lj_opt_narrow.c > @@ -551,8 +551,13 @@ TRef lj_opt_narrow_unm(jit_State *J, TRef rc, TValue *vc) > { > rc = conv_str_tonum(J, rc, vc); > if (tref_isinteger(rc)) { > - if ((uint32_t)numberVint(vc) != 0x80000000u) > - return emitir(IRTGI(IR_SUBOV), lj_ir_kint(J, 0), rc); > + uint32_t k = (uint32_t)numberVint(vc); > + if ((LJ_DUALNUM || k != 0) && k != 0x80000000u) { > + TRef zero = lj_ir_kint(J, 0); > + if (!LJ_DUALNUM) > + emitir(IRTGI(IR_NE), rc, zero); > + return emitir(IRTGI(IR_SUBOV), zero, rc); > + } > rc = emitir(IRTN(IR_CONV), rc, IRCONV_NUM_INT); > } > return emitir(IRTN(IR_NEG), rc, lj_ir_ksimd(J, LJ_KSIMD_NEG)); > diff --git a/test/tarantool-tests/gh-6976-narrowing-of-unary-minus.test.lua b/test/tarantool-tests/gh-6976-narrowing-of-unary-minus.test.lua > new file mode 100644 > index 00000000..18778a55 > --- /dev/null > +++ b/test/tarantool-tests/gh-6976-narrowing-of-unary-minus.test.lua > @@ -0,0 +1,51 @@ > +local tap = require('tap') > +local test = tap.test('gh-6976-narrowing-of-unary-minus') > +test:plan(2) > + > +jit.opt.start('hotloop=1', 'hotexit=1') > + > +local function check(routine) > + jit.off() > + jit.flush() > + local interp_res = routine() > + jit.on() > + local jit_res = routine() > + > + for i = 1, #interp_res do > + if interp_res[i] ~= jit_res[i] then > + return false > + end > + end > + > + return true > +end > + > +test:ok( > + check( > + function() > + local res = require('table.new')(3, 0) > + for _ = 1, 3 do > + local zero = 0 > + zero = -zero > + table.insert(res, tostring(zero)) > + end > + return res > + end > + ), > + 'incorrect recording for zero' > +) > + > +test:ok( > + check( > + function() > + local res = require('table.new')(3, 0) > + for i = 2, 0, -1 do > + table.insert(res, tostring(-i)) > + end > + return res > + end > + ), > + 'assertion guard fail' > +) > + > +os.exit(test:check() and 0 or 1) > -- > 2.32.1 (Apple Git-133) > ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [Tarantool-patches] [PATCH luajit v2] Fix narrowing of unary minus. 2022-09-25 21:31 ` sergos via Tarantool-patches @ 2022-09-29 9:58 ` Maxim Kokryashkin via Tarantool-patches 2022-09-29 13:08 ` Sergey Kaplun via Tarantool-patches 2022-11-30 10:40 ` sergos via Tarantool-patches 0 siblings, 2 replies; 10+ messages in thread From: Maxim Kokryashkin via Tarantool-patches @ 2022-09-29 9:58 UTC (permalink / raw) To: sergos; +Cc: tarantool-patches, Maksim Kokryashkin [-- Attachment #1: Type: text/plain, Size: 3028 bytes --] Hi, Sergos! Thanks for the questions! Please consider my answers amd changes below. > >> LuaJIT narrowing optimization during BC_UNM recording may ignore >> information about sign of zero for integer types of IR. So far the >> resulting value on a trace is not the same as for the interpreter. > >I didn’t get the point - how is it detected, otherwise than tostring()? >If so - should we change the tostring() instead? >Otherwise - we need a test that exposes this difference I’ve changed the tests, so it’s now more clear that zero sign can affect arithmetic. Branch is force-pushed. Here is the diff: =============================================== --- a/test/tarantool-tests/gh-6976-narrowing-of-unary-minus.test.lua +++ b/test/tarantool-tests/gh-6976-narrowing-of-unary-minus.test.lua @@ -2,7 +2,7 @@ local test = tap.test('gh-6976-narrowing-of-unary-minus') test:plan(2) -jit.opt.start('hotloop=1', 'hotexit=1') +jit.opt.start('hotloop=1') local function check(routine) jit.off() @@ -20,32 +20,29 @@ return true end -test:ok( - check( - function() - local res = require('table.new')(3, 0) - for _ = 1, 3 do - local zero = 0 - zero = -zero - table.insert(res, tostring(zero)) - end - return res - end - ), - 'incorrect recording for zero' -) - -test:ok( - check( - function() - local res = require('table.new')(3, 0) - for i = 2, 0, -1 do - table.insert(res, tostring(-i)) - end - return res - end - ), - 'assertion guard fail' -) +test:ok(check(function() + -- We use `table.new()` here to avoid trace + -- exits due to table rehashing. + local res = require('table.new')(3, 0) + for _ = 1, 3 do + local zero = 0 + zero = -zero + -- There is no difference between 0 and -0 from + -- arithmetic perspective, unless you try to divide + -- something by them. + -- `1 / 0 = inf` and `1 / -0 = -inf` + table.insert(res, 1 / zero) + end + return res +end), 'incorrect recording for zero') + +test:ok(check(function() + -- See the comment about `table.new()` above. + local res = require('table.new')(3, 0) + for i = 2, 0, -1 do + table.insert(res, 1 / -i) + end + return res +end),'assertion guard fail') os.exit(test:check() and 0 or 1) =============================================== <snipped> > >> This patch fixes the non-DUALNUM mode behaviour. When the zero value is >> identified during recording it should be cast to number so IR_CONV is >> emitted. Also, this patch adds assertion guard checking that value on >> which operation of unary minus is performed isn't zero. > >Does it mean I will exit the trace every time I met a `x = 0; x = -x` in it? No, that assertion guard takes you back to the interpreter only if a trace for unary minus was recorded considering `x` as a non-zero value, and at some point in this trace `x` became zero. Best regards, Maxim Kokryashkin [-- Attachment #2: Type: text/html, Size: 4592 bytes --] ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [Tarantool-patches] [PATCH luajit v2] Fix narrowing of unary minus. 2022-09-29 9:58 ` Maxim Kokryashkin via Tarantool-patches @ 2022-09-29 13:08 ` Sergey Kaplun via Tarantool-patches 2022-10-03 9:57 ` Maxim Kokryashkin via Tarantool-patches 2022-11-30 10:40 ` sergos via Tarantool-patches 1 sibling, 1 reply; 10+ messages in thread From: Sergey Kaplun via Tarantool-patches @ 2022-09-29 13:08 UTC (permalink / raw) To: Maxim Kokryashkin; +Cc: Maksim Kokryashkin, tarantool-patches Hi, Maxim! Thanks for the fixes! LGTM, just a single nit below. On 29.09.22, Maxim Kokryashkin via Tarantool-patches wrote: > > Hi, Sergos! > Thanks for the questions! > Please consider my answers amd changes below. <snipped> > Here is the diff: > =============================================== > --- a/test/tarantool-tests/gh-6976-narrowing-of-unary-minus.test.lua > +++ b/test/tarantool-tests/gh-6976-narrowing-of-unary-minus.test.lua <snipped> > +test:ok(check(function() > + -- See the comment about `table.new()` above. > + local res = require('table.new')(3, 0) > + for i = 2, 0, -1 do > + table.insert(res, 1 / -i) > + end > + return res > +end),'assertion guard fail') Typo: s/,/, / > <snipped> > Best regards, > Maxim Kokryashkin > -- Best regards, Sergey Kaplun ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [Tarantool-patches] [PATCH luajit v2] Fix narrowing of unary minus. 2022-09-29 13:08 ` Sergey Kaplun via Tarantool-patches @ 2022-10-03 9:57 ` Maxim Kokryashkin via Tarantool-patches 0 siblings, 0 replies; 10+ messages in thread From: Maxim Kokryashkin via Tarantool-patches @ 2022-10-03 9:57 UTC (permalink / raw) To: Sergey Kaplun; +Cc: Maksim Kokryashkin, tarantool-patches [-- Attachment #1: Type: text/plain, Size: 1076 bytes --] Hi, Sergey! I’ve fixed the nit you mentioned, the branch is force pushed. -- Best regards, Maxim Kokryashkin >Четверг, 29 сентября 2022, 16:11 +03:00 от Sergey Kaplun <skaplun@tarantool.org>: > >Hi, Maxim! > >Thanks for the fixes! >LGTM, just a single nit below. > >On 29.09.22, Maxim Kokryashkin via Tarantool-patches wrote: >> >> Hi, Sergos! >> Thanks for the questions! >> Please consider my answers amd changes below. > ><snipped> > >> Here is the diff: >> =============================================== >> --- a/test/tarantool-tests/gh-6976-narrowing-of-unary-minus.test.lua >> +++ b/test/tarantool-tests/gh-6976-narrowing-of-unary-minus.test.lua > ><snipped> > >> +test:ok(check(function() >> + -- See the comment about `table.new()` above. >> + local res = require('table.new')(3, 0) >> + for i = 2, 0, -1 do >> + table.insert(res, 1 / -i) >> + end >> + return res >> +end),'assertion guard fail') > >Typo: s/,/, / > >> > ><snipped> > >> Best regards, >> Maxim Kokryashkin >> > >-- >Best regards, >Sergey Kaplun [-- Attachment #2: Type: text/html, Size: 1734 bytes --] ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [Tarantool-patches] [PATCH luajit v2] Fix narrowing of unary minus. 2022-09-29 9:58 ` Maxim Kokryashkin via Tarantool-patches 2022-09-29 13:08 ` Sergey Kaplun via Tarantool-patches @ 2022-11-30 10:40 ` sergos via Tarantool-patches 1 sibling, 0 replies; 10+ messages in thread From: sergos via Tarantool-patches @ 2022-11-30 10:40 UTC (permalink / raw) To: Maxim Kokryashkin; +Cc: tarantool-patches, Maksim Kokryashkin [-- Attachment #1: Type: text/plain, Size: 3390 bytes --] Hi! Thanks for the fixes, LGTM now. Sergos > On 29 Sep 2022, at 12:58, Maxim Kokryashkin <m.kokryashkin@tarantool.org> wrote: > > Hi, Sergos! > Thanks for the questions! > Please consider my answers amd changes below. > > > LuaJIT narrowing optimization during BC_UNM recording may ignore > > information about sign of zero for integer types of IR. So far the > > resulting value on a trace is not the same as for the interpreter. > > I didn’t get the point - how is it detected, otherwise than tostring()? > If so - should we change the tostring() instead? > Otherwise - we need a test that exposes this difference > I’ve changed the tests, so it’s now more clear that zero sign can affect arithmetic. > Branch is force-pushed. > Here is the diff: > =============================================== > --- a/test/tarantool-tests/gh-6976-narrowing-of-unary-minus.test.lua > +++ b/test/tarantool-tests/gh-6976-narrowing-of-unary-minus.test.lua > @@ -2,7 +2,7 @@ > local test = tap.test('gh-6976-narrowing-of-unary-minus') > test:plan(2) > > -jit.opt.start('hotloop=1', 'hotexit=1') > +jit.opt.start('hotloop=1') > > local function check(routine) > jit.off() > @@ -20,32 +20,29 @@ > return true > end > > -test:ok( > - check( > - function() > - local res = require('table.new')(3, 0) > - for _ = 1, 3 do > - local zero = 0 > - zero = -zero > - table.insert(res, tostring(zero)) > - end > - return res > - end > - ), > - 'incorrect recording for zero' > -) > - > -test:ok( > - check( > - function() > - local res = require('table.new')(3, 0) > - for i = 2, 0, -1 do > - table.insert(res, tostring(-i)) > - end > - return res > - end > - ), > - 'assertion guard fail' > -) > +test:ok(check(function() > + -- We use `table.new()` here to avoid trace > + -- exits due to table rehashing. > + local res = require('table.new')(3, 0) > + for _ = 1, 3 do > + local zero = 0 > + zero = -zero > + -- There is no difference between 0 and -0 from > + -- arithmetic perspective, unless you try to divide > + -- something by them. > + -- `1 / 0 = inf` and `1 / -0 = -inf` > + table.insert(res, 1 / zero) > + end > + return res > +end), 'incorrect recording for zero') > + > +test:ok(check(function() > + -- See the comment about `table.new()` above. > + local res = require('table.new')(3, 0) > + for i = 2, 0, -1 do > + table.insert(res, 1 / -i) > + end > + return res > +end),'assertion guard fail') > > os.exit(test:check() and 0 or 1) > =============================================== > <snipped> > > > This patch fixes the non-DUALNUM mode behaviour. When the zero value is > > identified during recording it should be cast to number so IR_CONV is > > emitted. Also, this patch adds assertion guard checking that value on > > which operation of unary minus is performed isn't zero. > > Does it mean I will exit the trace every time I met a `x = 0; x = -x` in it? > No, that assertion guard takes you back to the interpreter only if a > trace for unary minus was recorded considering `x` as a non-zero value, > and at some point in this trace `x` became zero. ok, it looks reasonable. > > > Best regards, > Maxim Kokryashkin > [-- Attachment #2: Type: text/html, Size: 5380 bytes --] ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [Tarantool-patches] [PATCH luajit] Fix narrowing of unary minus. 2022-09-09 12:15 [Tarantool-patches] [PATCH luajit] Fix narrowing of unary minus Maksim Kokryashkin via Tarantool-patches 2022-09-14 22:06 ` Sergey Kaplun via Tarantool-patches @ 2022-12-12 9:42 ` Igor Munkin via Tarantool-patches 1 sibling, 0 replies; 10+ messages in thread From: Igor Munkin via Tarantool-patches @ 2022-12-12 9:42 UTC (permalink / raw) To: Maksim Kokryashkin; +Cc: tarantool-patches Max, I've checked the patches into all long-term branches in tarantool/luajit and bumped a new version in master, 2.10 and 1.10. On 09.09.22, Maksim Kokryashkin wrote: > From: Mike Pall <mike> > > With DUALNUM mode disabled, unary minus narrowing can produce > inconsistent results on zeros, returning both -0 and 0 on the > same chunk of code. > > This patch fixes the inconsistency by adding checks for zeros. > > Part of tarantool/tarantool#7230 > Resolves tarantool/tarantool#6976 > --- > Issue: https://github.com/tarantool/tarantool/issues/6976 > Branch: https://github.com/tarantool/luajit/tree/fckxorg/gh-6976-narrowing-of-unary-minus > PR: https://github.com/tarantool/tarantool/pull/7662 > > src/lj_opt_narrow.c | 9 +++-- > .../gh-6976-narrowing-of-unary-minus.test.lua | 34 +++++++++++++++++++ > 2 files changed, 41 insertions(+), 2 deletions(-) > create mode 100644 test/tarantool-tests/gh-6976-narrowing-of-unary-minus.test.lua > <snipped> > -- > 2.32.1 (Apple Git-133) > -- Best regards, IM ^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2022-12-12 9:57 UTC | newest] Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2022-09-09 12:15 [Tarantool-patches] [PATCH luajit] Fix narrowing of unary minus Maksim Kokryashkin via Tarantool-patches 2022-09-14 22:06 ` Sergey Kaplun via Tarantool-patches 2022-09-20 11:16 ` [Tarantool-patches] [PATCH luajit v2] " Maksim Kokryashkin via Tarantool-patches 2022-09-21 8:48 ` Sergey Kaplun via Tarantool-patches 2022-09-25 21:31 ` sergos via Tarantool-patches 2022-09-29 9:58 ` Maxim Kokryashkin via Tarantool-patches 2022-09-29 13:08 ` Sergey Kaplun via Tarantool-patches 2022-10-03 9:57 ` Maxim Kokryashkin via Tarantool-patches 2022-11-30 10:40 ` sergos via Tarantool-patches 2022-12-12 9:42 ` [Tarantool-patches] [PATCH luajit] " Igor Munkin via Tarantool-patches
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox