* [Tarantool-patches] [PATCH] Mark CONV as non-weak, to prevent elimination of its side-effect.
@ 2023-07-12 9:52 Maksim Kokryashkin via Tarantool-patches
2023-07-13 12:23 ` Sergey Bronnikov via Tarantool-patches
` (2 more replies)
0 siblings, 3 replies; 6+ messages in thread
From: Maksim Kokryashkin via Tarantool-patches @ 2023-07-12 9:52 UTC (permalink / raw)
To: tarantool-patches, sergeyb, skaplun, m.kokryashkin
From: Mike Pall <mike>
An unused guarded CONV int.num cannot be omitted in general.
(cherry-picked from commit 881d02d3117838acaf4fb844332c8e33cc95c8c5)
In some cases, an unused `CONV` omission may lead to a guard
absence, resulting in invalid control flow branching and
undefined behavior. For a comprehensive example of
the described situation, please refer to the comment
in `test/tarantool-tests/mark-conv-non-weak.test.lua`.
Maxim Kokryashkin:
* added the description and the test for the problem
Part of tarantool/tarantool#8825
---
src/lj_ir.h | 2 +-
.../mark-conv-non-weak.test.lua | 58 +++++++++++++++++++
2 files changed, 59 insertions(+), 1 deletion(-)
create mode 100644 test/tarantool-tests/mark-conv-non-weak.test.lua
diff --git a/src/lj_ir.h b/src/lj_ir.h
index e8bca275..bf9b9292 100644
--- a/src/lj_ir.h
+++ b/src/lj_ir.h
@@ -132,7 +132,7 @@
_(XBAR, S , ___, ___) \
\
/* Type conversions. */ \
- _(CONV, NW, ref, lit) \
+ _(CONV, N , ref, lit) \
_(TOBIT, N , ref, ref) \
_(TOSTR, N , ref, lit) \
_(STRTO, N , ref, ___) \
diff --git a/test/tarantool-tests/mark-conv-non-weak.test.lua b/test/tarantool-tests/mark-conv-non-weak.test.lua
new file mode 100644
index 00000000..aad39058
--- /dev/null
+++ b/test/tarantool-tests/mark-conv-non-weak.test.lua
@@ -0,0 +1,58 @@
+local tap = require('tap')
+local test = tap.test('mark-conv-non-weak'):skipcond({
+ ['Test requires JIT enabled'] = not jit.status(),
+})
+
+test:plan(1)
+
+local data = {0.1, 0, 0.1, 0, 0 / 0}
+local sum = 0
+
+jit.opt.start('hotloop=1', 'hotexit=1')
+
+-- When the last trace is recorded, the traced bytecode
+-- is the following before the patch:
+-- ---- TRACE 4 start 2/3 test.lua:6
+-- 0018 ADDVV 1 1 6
+-- 0019 ITERC 5 3 3
+-- 0000 . FUNCC ; ipairs_aux
+-- 0020 JITERL 5 1
+-- 0021 GGET 2 7 ; "assert"
+-- 0022 ISEQV 1 1
+-- 0023 JMP 4 => 0026
+-- 0024 KPRI 4 1
+-- 0025 JMP 5 => 0027
+-- 0027 CALL 2 1 2
+-- 0000 . FUNCC ; assert
+--
+-- And the following after the patch:
+-- ---- TRACE 4 start 2/2 test.lua:5
+-- 0016 ISNEV 6 6
+-- 0017 JMP 7 => 0019
+-- 0019 ITERC 5 3 3
+-- 0000 . FUNCC ; ipairs_aux
+-- 0020 JITERL 5 1
+-- 0021 GGET 2 7 ; "assert"
+-- 0022 ISEQV 1 1
+-- 0023 JMP 4 => 0026
+-- 0026 KPRI 4 2
+-- 0027 CALL 2 1 2
+-- 0000 . FUNCC ; assert
+-- 0028 RET0 0 1
+--
+-- The crucial difference here is the abscent
+-- `ISNEV` in the first case, which produces the
+-- desired guarded `CONV`, when translated to IR.
+--
+-- Since there is no guard, NaN is added to the sum,
+-- despite the test case logic.
+
+for _, val in ipairs(data) do
+ if val == val then
+ sum = sum + val
+ end
+end
+
+test:ok(sum == sum, 'NaN check was not omitted')
+
+os.exit(test:check() and 0 or 1)
--
2.39.2 (Apple Git-143)
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [Tarantool-patches] [PATCH] Mark CONV as non-weak, to prevent elimination of its side-effect.
2023-07-12 9:52 [Tarantool-patches] [PATCH] Mark CONV as non-weak, to prevent elimination of its side-effect Maksim Kokryashkin via Tarantool-patches
@ 2023-07-13 12:23 ` Sergey Bronnikov via Tarantool-patches
2023-07-17 15:11 ` Maxim Kokryashkin via Tarantool-patches
2023-08-24 7:26 ` Sergey Kaplun via Tarantool-patches
2023-11-23 6:31 ` Igor Munkin via Tarantool-patches
2 siblings, 1 reply; 6+ messages in thread
From: Sergey Bronnikov via Tarantool-patches @ 2023-07-13 12:23 UTC (permalink / raw)
To: Maksim Kokryashkin, tarantool-patches, skaplun, m.kokryashkin
Hi, Max!
thanks for the patch!
Links to the branch and PR are missed, but I found them:
branch: https://github.com/tarantool/luajit/tree/fckxorg/mark-conv-non-weak
PR: https://github.com/tarantool/tarantool/pull/8871
Test is passed after reverting the patch with fix.
Sergey
On 7/12/23 12:52, Maksim Kokryashkin wrote:
> From: Mike Pall <mike>
>
> An unused guarded CONV int.num cannot be omitted in general.
>
> (cherry-picked from commit 881d02d3117838acaf4fb844332c8e33cc95c8c5)
>
> In some cases, an unused `CONV` omission may lead to a guard
> absence, resulting in invalid control flow branching and
> undefined behavior. For a comprehensive example of
> the described situation, please refer to the comment
> in `test/tarantool-tests/mark-conv-non-weak.test.lua`.
>
> Maxim Kokryashkin:
> * added the description and the test for the problem
>
> Part of tarantool/tarantool#8825
> ---
> src/lj_ir.h | 2 +-
> .../mark-conv-non-weak.test.lua | 58 +++++++++++++++++++
> 2 files changed, 59 insertions(+), 1 deletion(-)
> create mode 100644 test/tarantool-tests/mark-conv-non-weak.test.lua
>
> diff --git a/src/lj_ir.h b/src/lj_ir.h
> index e8bca275..bf9b9292 100644
> --- a/src/lj_ir.h
> +++ b/src/lj_ir.h
> @@ -132,7 +132,7 @@
> _(XBAR, S , ___, ___) \
> \
> /* Type conversions. */ \
> - _(CONV, NW, ref, lit) \
> + _(CONV, N , ref, lit) \
> _(TOBIT, N , ref, ref) \
> _(TOSTR, N , ref, lit) \
> _(STRTO, N , ref, ___) \
> diff --git a/test/tarantool-tests/mark-conv-non-weak.test.lua b/test/tarantool-tests/mark-conv-non-weak.test.lua
> new file mode 100644
> index 00000000..aad39058
> --- /dev/null
> +++ b/test/tarantool-tests/mark-conv-non-weak.test.lua
> @@ -0,0 +1,58 @@
> +local tap = require('tap')
> +local test = tap.test('mark-conv-non-weak'):skipcond({
> + ['Test requires JIT enabled'] = not jit.status(),
> +})
> +
> +test:plan(1)
> +
> +local data = {0.1, 0, 0.1, 0, 0 / 0}
> +local sum = 0
> +
> +jit.opt.start('hotloop=1', 'hotexit=1')
> +
> +-- When the last trace is recorded, the traced bytecode
> +-- is the following before the patch:
> +-- ---- TRACE 4 start 2/3 test.lua:6
> +-- 0018 ADDVV 1 1 6
> +-- 0019 ITERC 5 3 3
> +-- 0000 . FUNCC ; ipairs_aux
> +-- 0020 JITERL 5 1
> +-- 0021 GGET 2 7 ; "assert"
> +-- 0022 ISEQV 1 1
> +-- 0023 JMP 4 => 0026
> +-- 0024 KPRI 4 1
> +-- 0025 JMP 5 => 0027
> +-- 0027 CALL 2 1 2
> +-- 0000 . FUNCC ; assert
> +--
> +-- And the following after the patch:
> +-- ---- TRACE 4 start 2/2 test.lua:5
> +-- 0016 ISNEV 6 6
> +-- 0017 JMP 7 => 0019
> +-- 0019 ITERC 5 3 3
> +-- 0000 . FUNCC ; ipairs_aux
> +-- 0020 JITERL 5 1
> +-- 0021 GGET 2 7 ; "assert"
> +-- 0022 ISEQV 1 1
> +-- 0023 JMP 4 => 0026
> +-- 0026 KPRI 4 2
> +-- 0027 CALL 2 1 2
> +-- 0000 . FUNCC ; assert
> +-- 0028 RET0 0 1
> +--
> +-- The crucial difference here is the abscent
> +-- `ISNEV` in the first case, which produces the
> +-- desired guarded `CONV`, when translated to IR.
> +--
> +-- Since there is no guard, NaN is added to the sum,
> +-- despite the test case logic.
> +
> +for _, val in ipairs(data) do
> + if val == val then
> + sum = sum + val
> + end
> +end
> +
> +test:ok(sum == sum, 'NaN check was not omitted')
> +
> +os.exit(test:check() and 0 or 1)
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [Tarantool-patches] [PATCH] Mark CONV as non-weak, to prevent elimination of its side-effect.
2023-07-13 12:23 ` Sergey Bronnikov via Tarantool-patches
@ 2023-07-17 15:11 ` Maxim Kokryashkin via Tarantool-patches
2023-11-20 8:24 ` Sergey Bronnikov via Tarantool-patches
0 siblings, 1 reply; 6+ messages in thread
From: Maxim Kokryashkin via Tarantool-patches @ 2023-07-17 15:11 UTC (permalink / raw)
To: Sergey Bronnikov; +Cc: Maksim Kokryashkin, tarantool-patches
[-- Attachment #1: Type: text/plain, Size: 5323 bytes --]
Hi!
It’s silly how it is escaped from my attention, that this patch
is essentially relevant only for `DUALNUM` mode. This issue
reproduces on arm64, or if you have LuaJIT built with
`-DLUJAIT_NUMMODE=2` option. I’ve altered the commit message
a bit to mention the mode name explicitly. Also, I’ve added an
additional comment to the test case itself.
Here is the diff:
===============================================
diff --git a/test/tarantool-tests/mark-conv-non-weak.test.lua b/test/tarantool-tests/mark-conv-non-weak.test.lua
index aad39058..9a325202 100644
--- a/test/tarantool-tests/mark-conv-non-weak.test.lua
+++ b/test/tarantool-tests/mark-conv-non-weak.test.lua
@@ -10,6 +10,10 @@ local sum = 0
jit.opt.start('hotloop=1', 'hotexit=1')
+-- XXX: The test fails before the patch only
+-- for `DUALNUM` mode. All of the IRs below are
+-- produced by the corresponding LuaJIT build.
+
-- When the last trace is recorded, the traced bytecode
-- is the following before the patch:
-- ---- TRACE 4 start 2/3 test.lua:6
===============================================
And here is the altered commit message:
===============================================
Mark CONV as non-weak, to prevent elimination of its side-effect.
An unused guarded CONV int.num cannot be omitted in general.
(cherry-picked from commit 881d02d3117838acaf4fb844332c8e33cc95c8c5)
In some cases, an unused `CONV int.num` omission in `DUALNUM` mode
may lead to a guard absence, resulting in invalid control flow
branching and undefined behavior. For a comprehensive example of
the described situation, please refer to the comment
in `test/tarantool-tests/mark-conv-non-weak.test.lua`.
Maxim Kokryashkin:
* added the description and the test for the problem
Part of tarantool/tarantool#8825
===============================================
--
Best regards,
Maxim Kokryashkin
>Четверг, 13 июля 2023, 15:23 +03:00 от Sergey Bronnikov <sergeyb@tarantool.org>:
>
>Hi, Max!
>
>
>thanks for the patch!
>
>Links to the branch and PR are missed, but I found them:
>
>branch: https://github.com/tarantool/luajit/tree/fckxorg/mark-conv-non-weak
>
>PR: https://github.com/tarantool/tarantool/pull/8871
>
>
>Test is passed after reverting the patch with fix.
>
>
>Sergey
>
>
>On 7/12/23 12:52, Maksim Kokryashkin wrote:
>> From: Mike Pall <mike>
>>
>> An unused guarded CONV int.num cannot be omitted in general.
>>
>> (cherry-picked from commit 881d02d3117838acaf4fb844332c8e33cc95c8c5)
>>
>> In some cases, an unused `CONV` omission may lead to a guard
>> absence, resulting in invalid control flow branching and
>> undefined behavior. For a comprehensive example of
>> the described situation, please refer to the comment
>> in `test/tarantool-tests/mark-conv-non-weak.test.lua`.
>>
>> Maxim Kokryashkin:
>> * added the description and the test for the problem
>>
>> Part of tarantool/tarantool#8825
>> ---
>> src/lj_ir.h | 2 +-
>> .../mark-conv-non-weak.test.lua | 58 +++++++++++++++++++
>> 2 files changed, 59 insertions(+), 1 deletion(-)
>> create mode 100644 test/tarantool-tests/mark-conv-non-weak.test.lua
>>
>> diff --git a/src/lj_ir.h b/src/lj_ir.h
>> index e8bca275..bf9b9292 100644
>> --- a/src/lj_ir.h
>> +++ b/src/lj_ir.h
>> @@ -132,7 +132,7 @@
>> _(XBAR, S , ___, ___) \
>> \
>> /* Type conversions. */ \
>> - _(CONV, NW, ref, lit) \
>> + _(CONV, N , ref, lit) \
>> _(TOBIT, N , ref, ref) \
>> _(TOSTR, N , ref, lit) \
>> _(STRTO, N , ref, ___) \
>> diff --git a/test/tarantool-tests/mark-conv-non-weak.test.lua b/test/tarantool-tests/mark-conv-non-weak.test.lua
>> new file mode 100644
>> index 00000000..aad39058
>> --- /dev/null
>> +++ b/test/tarantool-tests/mark-conv-non-weak.test.lua
>> @@ -0,0 +1,58 @@
>> +local tap = require('tap')
>> +local test = tap.test('mark-conv-non-weak'):skipcond({
>> + ['Test requires JIT enabled'] = not jit.status(),
>> +})
>> +
>> +test:plan(1)
>> +
>> +local data = {0.1, 0, 0.1, 0, 0 / 0}
>> +local sum = 0
>> +
>> +jit.opt.start('hotloop=1', 'hotexit=1')
>> +
>> +-- When the last trace is recorded, the traced bytecode
>> +-- is the following before the patch:
>> +-- ---- TRACE 4 start 2/3 test.lua:6
>> +-- 0018 ADDVV 1 1 6
>> +-- 0019 ITERC 5 3 3
>> +-- 0000 . FUNCC ; ipairs_aux
>> +-- 0020 JITERL 5 1
>> +-- 0021 GGET 2 7 ; "assert"
>> +-- 0022 ISEQV 1 1
>> +-- 0023 JMP 4 => 0026
>> +-- 0024 KPRI 4 1
>> +-- 0025 JMP 5 => 0027
>> +-- 0027 CALL 2 1 2
>> +-- 0000 . FUNCC ; assert
>> +--
>> +-- And the following after the patch:
>> +-- ---- TRACE 4 start 2/2 test.lua:5
>> +-- 0016 ISNEV 6 6
>> +-- 0017 JMP 7 => 0019
>> +-- 0019 ITERC 5 3 3
>> +-- 0000 . FUNCC ; ipairs_aux
>> +-- 0020 JITERL 5 1
>> +-- 0021 GGET 2 7 ; "assert"
>> +-- 0022 ISEQV 1 1
>> +-- 0023 JMP 4 => 0026
>> +-- 0026 KPRI 4 2
>> +-- 0027 CALL 2 1 2
>> +-- 0000 . FUNCC ; assert
>> +-- 0028 RET0 0 1
>> +--
>> +-- The crucial difference here is the abscent
>> +-- `ISNEV` in the first case, which produces the
>> +-- desired guarded `CONV`, when translated to IR.
>> +--
>> +-- Since there is no guard, NaN is added to the sum,
>> +-- despite the test case logic.
>> +
>> +for _, val in ipairs(data) do
>> + if val == val then
>> + sum = sum + val
>> + end
>> +end
>> +
>> +test:ok(sum == sum, 'NaN check was not omitted')
>> +
>> +os.exit(test:check() and 0 or 1)
[-- Attachment #2: Type: text/html, Size: 7473 bytes --]
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [Tarantool-patches] [PATCH] Mark CONV as non-weak, to prevent elimination of its side-effect.
2023-07-12 9:52 [Tarantool-patches] [PATCH] Mark CONV as non-weak, to prevent elimination of its side-effect Maksim Kokryashkin via Tarantool-patches
2023-07-13 12:23 ` Sergey Bronnikov via Tarantool-patches
@ 2023-08-24 7:26 ` Sergey Kaplun via Tarantool-patches
2023-11-23 6:31 ` Igor Munkin via Tarantool-patches
2 siblings, 0 replies; 6+ messages in thread
From: Sergey Kaplun via Tarantool-patches @ 2023-08-24 7:26 UTC (permalink / raw)
To: Maksim Kokryashkin; +Cc: tarantool-patches
Hi, Maxim!
Thanks for the patch!
Please consider my comment below.
On 12.07.23, Maksim Kokryashkin wrote:
> From: Mike Pall <mike>
>
> An unused guarded CONV int.num cannot be omitted in general.
>
> (cherry-picked from commit 881d02d3117838acaf4fb844332c8e33cc95c8c5)
>
> In some cases, an unused `CONV` omission may lead to a guard
> absence, resulting in invalid control flow branching and
> undefined behavior. For a comprehensive example of
> the described situation, please refer to the comment
> in `test/tarantool-tests/mark-conv-non-weak.test.lua`.
>
> Maxim Kokryashkin:
> * added the description and the test for the problem
>
> Part of tarantool/tarantool#8825
> ---
<snipped>
> +
> +jit.opt.start('hotloop=1', 'hotexit=1')
> +
> +-- When the last trace is recorded, the traced bytecode
> +-- is the following before the patch:
> +-- ---- TRACE 4 start 2/3 test.lua:6
> +-- 0018 ADDVV 1 1 6
> +-- 0019 ITERC 5 3 3
> +-- 0000 . FUNCC ; ipairs_aux
> +-- 0020 JITERL 5 1
> +-- 0021 GGET 2 7 ; "assert"
> +-- 0022 ISEQV 1 1
> +-- 0023 JMP 4 => 0026
> +-- 0024 KPRI 4 1
> +-- 0025 JMP 5 => 0027
> +-- 0027 CALL 2 1 2
> +-- 0000 . FUNCC ; assert
> +--
> +-- And the following after the patch:
> +-- ---- TRACE 4 start 2/2 test.lua:5
> +-- 0016 ISNEV 6 6
> +-- 0017 JMP 7 => 0019
> +-- 0019 ITERC 5 3 3
> +-- 0000 . FUNCC ; ipairs_aux
> +-- 0020 JITERL 5 1
> +-- 0021 GGET 2 7 ; "assert"
> +-- 0022 ISEQV 1 1
> +-- 0023 JMP 4 => 0026
> +-- 0026 KPRI 4 2
> +-- 0027 CALL 2 1 2
> +-- 0000 . FUNCC ; assert
> +-- 0028 RET0 0 1
> +--
> +-- The crucial difference here is the abscent
> +-- `ISNEV` in the first case, which produces the
> +-- desired guarded `CONV`, when translated to IR.
There are two important statements:
As you mentioned, the case is observed only in the DUALNUM mode.
As mentioned in the commit, this is due to `CONV int.num` IRs.
The comment for the test itself is misleading the reason of misbehaviour
isn't the wrong bytecode in the recording -- it's the consequence.
Let's use the reproducer, but with hotloop=2 to decrease amount of
traces:
| LUA_PATH="src/?.lua;;" src/luajit -jdump=X -e "
| local data = {0.1, 0, 0.1, 0, 0 / 0}
| local sum = 0
|
| jit.opt.start('hotloop=2', 'hotexit=1')
|
| for _, val in ipairs(data) do
| if val == val then
| sum = sum + val
| end
| end
|
| math.fmod(1,1)
|
| print(sum)
| "
This is output before the patch (see `<-- !!!` marks):
| ---- TRACE 1 exit 0
| 000056449701ff26 0000000041bb9880 00000000409cf228 0000000041bb9e94
| 00007fffa700cfa0 00000000409c2378 00000000409cf228 00000000409c3320
| 0000000000000000 0000000000000000 00007fd4e2d38938 00000000fffffffe
| 00007fffa700d3e8 000056446cea132a 00000000409c3098 0000000041bb9ee0
| +4.6863058149307e-310 +4.6863058151824e-310 +4.6863058151959e-310 +4.6863058152213e-310
| +4.6863058152444e-310 +4.6863058152873e-310 +4.6863058152729e-310 +4.6863058152444e-310
| +4.6863058152213e-310 +0 -0.66666666666667 +0.7999999995324
| -1.1429096284595 +0 +0 +0
| ---- TRACE 1 exit 3 <-- !!!
| 0000000041bb9848 0000000000000006 0000000041bb9828 0000000000000005
| 00007fffa700cfa0 0000000000000006 00000000409cf228 00000000409c3320
| 0000000000000000 0000000000000029 00007fd4e2d3ab28 00000000fffffffe
| 00007fffa700d3e8 000056446cea132a 00000000409c3098 0000000041bb9ee0
| +4.6863058149307e-310 +4.6863058151824e-310 +4.6863058151959e-310 +4.6863058152213e-310
| nan +0.2 nan nan <-- !!!
| +4.6863058152213e-310 +0 -0.66666666666667 +0.7999999995324
| -1.1429096284595 +0 +0 +0
| nan
And this is after:
| ---- TRACE 1 exit 0
| 0000556168ccff06 0000000041f8a880 0000000040275220 0000000041f8ae94
| 00007ffda4a82900 0000000040268378 0000000040275220 0000000040269320
| 0000000000000000 0000000000000000 00007fdd97c11938 00000000fffffffe
| 00007ffda4a82d48 000055613eb5132a 0000000040269090 0000000041f8aee0
| +4.6380982089931e-310 +4.6380982092477e-310 +4.6380982092617e-310 +4.6380982092839e-310
| +4.6380982093151e-310 +4.6380982093497e-310 +4.6380982093353e-310 +4.6380982093068e-310
| +4.6380982092837e-310 +0 -0.66666666666667 +0.7999999995324
| -1.1429096284595 +0 +0 +0
| ---- TRACE 1 exit 2 <-- !!!
| 0000000041f8a848 0000000000000006 0000000041f8a828 0000000041f8ae94
| 00007ffda4a82900 0000000000000005 0000000040275220 0000000080000000
| 0000000000000000 0000000000000029 00007fdd97c13b28 00000000fffffffe
| 00007ffda4a82d48 000055613eb5132a 0000000040269090 0000000041f8aee0
| +4.6380982089931e-310 +4.6380982092477e-310 +4.6380982092617e-310 +4.6380982092839e-310
| nan +0.2 nan -2147483648 <-- !!!
| +4.6380982092837e-310 +0 -0.66666666666667 +0.7999999995324
| -1.1429096284595 +0 +0 +0
| 0.2
As you can see different side exits are taken, and **this** leads to
different bytecodes on the recording of the side trace (this is observed
in the dump of the bytecode). So, the second side exit doesn't contain
NaN.
The IRs of the first trace are the following:
| ---- TRACE 1 start (command line):7
| ---- TRACE 1 IR
| .... SNAP #0 [ ---- ---- ---- ---- ---- ---- ---- ---- ]
| 0001 u8 XLOAD [0x41b864c1] V
| 0002 int BAND 0001 +12
| 0003 > int EQ 0002 +0
| 0004 > int SLOAD #7 T
| .... SNAP #1 [ ---- ---- ---- ---- ---- ---- ---- ---- ]
| 0005 > num SLOAD #2 T
| 0006 xmm7 num CONV 0004 num.int
| 0007 xmm7 + num ADD 0006 0005
| 0008 > fun SLOAD #3 T
| 0009 rdx > tab SLOAD #4 T
| 0010 rbp > int SLOAD #5 T
| 0011 > fun EQ 0008 ipairs_aux
| 0012 rbp + int ADD 0010 +1
| 0013 rcx int FLOAD 0009 tab.asize
| 0014 > int ABC 0013 0012
| 0015 rax p32 FLOAD 0009 tab.array
| 0016 p32 AREF 0015 0012
| 0017 xmm6 >+ num ALOAD 0016
| .... SNAP #2 [ ---- ---- 0007 ---- ---- 0012 0012 0017 ]
| 0018 ------------ LOOP ------------
| 0019 u8 XLOAD [0x41b864c1] V
| 0020 int BAND 0019 +12
| 0021 > int EQ 0020 +0
| 0022 rdi > int CONV 0017 int.num
| .... SNAP #3 [ ---- ---- 0007 ---- ---- 0012 0012 0017 ]
| 0023 xmm7 + num ADD 0017 0007
| 0024 rbp + int ADD 0012 +1
| 0025 > int ABC 0013 0024
| 0026 p32 AREF 0015 0024
| 0027 xmm6 >+ num ALOAD 0026
| 0028 xmm6 num PHI 0017 0027
| 0029 xmm7 num PHI 0007 0023
| 0030 rbp int PHI 0012 0024
| 0031 rbx nil RENAME 0012 #3
| 0032 xmm4 nil RENAME 0017 #2
| 0033 xmm5 nil RENAME 0007 #2
| ---- TRACE 1 stop -> loop
The skipped due to DCE conversion is the following:
| 0022 rdi > int CONV 0017 int.num
Also, from gdb we can check, that omitted conversion has `IRCONV_CHECK`
mode (I suppose that only check conversion can't be omitted, but Mike
prefer more coarse fix).
Also, it should be mentioned that we get this conversion due to type
instability in loop carried dependency (see `loop_unrool()` in
<src/lj_opt_loop.c>):
| else if (irt_isnum(irr->t) && irt_isinteger(t)) /* Fix num->int. */
| ref = tref_ref(emitir(IRTGI(IR_CONV), ref,
| IRCONV_INT_NUM|IRCONV_CHECK));
All this confusion is because of the too complex traces in the given
example. We have 4 traces, but I suppose that should be reduced to only
one with the necessary side exit to restore NaN value after missing
check.
I suggest to look forward for all places, where such int.num check
conversion is used:
| src/lj_record.c:491: tr[i] = emitir(IRTGI(IR_CONV), tr[i], IRCONV_INT_NUM|IRCONV_CHECK);
| src/lj_opt_loop.c:349: IRCONV_INT_NUM|IRCONV_CHECK));
| src/lj_ffrecord.c:529: tr = emitir(IRTGI(IR_CONV), tr, IRCONV_INT_NUM|IRCONV_CHECK);
| src/lj_opt_narrow.c:604: rc = emitir(IRTGI(IR_CONV), rc, IRCONV_INT_NUM|IRCONV_CHECK);
to create a testcase with one trace.
> +--
> +-- Since there is no guard, NaN is added to the sum,
> +-- despite the test case logic.
> +
> +for _, val in ipairs(data) do
> + if val == val then
> + sum = sum + val
> + end
> +end
> +
> +test:ok(sum == sum, 'NaN check was not omitted')
> +
> +os.exit(test:check() and 0 or 1)
> --
> 2.39.2 (Apple Git-143)
>
--
Best regards,
Sergey Kaplun
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [Tarantool-patches] [PATCH] Mark CONV as non-weak, to prevent elimination of its side-effect.
2023-07-17 15:11 ` Maxim Kokryashkin via Tarantool-patches
@ 2023-11-20 8:24 ` Sergey Bronnikov via Tarantool-patches
0 siblings, 0 replies; 6+ messages in thread
From: Sergey Bronnikov via Tarantool-patches @ 2023-11-20 8:24 UTC (permalink / raw)
To: Maxim Kokryashkin; +Cc: Maksim Kokryashkin, tarantool-patches
[-- Attachment #1: Type: text/plain, Size: 6011 bytes --]
Hello, Max
thanks for the patch! LGTM
On 7/17/23 18:11, Maxim Kokryashkin wrote:
> Hi!
> It’s silly how it is escaped from my attention, that this patch
> is essentially relevant only for `DUALNUM` mode. This issue
> reproduces on arm64, or if you have LuaJIT built with
> `-DLUJAIT_NUMMODE=2` option. I’ve altered the commit message
> a bit to mention the mode name explicitly. Also, I’ve added an
> additional comment to the test case itself.
> Here is the diff:
> ===============================================
> diff --git a/test/tarantool-tests/mark-conv-non-weak.test.lua
> b/test/tarantool-tests/mark-conv-non-weak.test.lua
> index aad39058..9a325202 100644
> --- a/test/tarantool-tests/mark-conv-non-weak.test.lua
> +++ b/test/tarantool-tests/mark-conv-non-weak.test.lua
> @@ -10,6 +10,10 @@ local sum = 0
> jit.opt.start('hotloop=1', 'hotexit=1')
> +-- XXX: The test fails before the patch only
> +-- for `DUALNUM` mode. All of the IRs below are
> +-- produced by the corresponding LuaJIT build.
> +
> -- When the last trace is recorded, the traced bytecode
> -- is the following before the patch:
> -- ---- TRACE 4 start 2/3 test.lua:6
> ===============================================
> And here is the altered commit message:
> ===============================================
> Mark CONV as non-weak, to prevent elimination of its side-effect.
> An unused guarded CONV int.num cannot be omitted in general.
> (cherry-picked from commit 881d02d3117838acaf4fb844332c8e33cc95c8c5)
> In some cases, an unused `CONV int.num` omission in `DUALNUM` mode
> may lead to a guard absence, resulting in invalid control flow
> branching and undefined behavior. For a comprehensive example of
> the described situation, please refer to the comment
> in `test/tarantool-tests/mark-conv-non-weak.test.lua`.
> Maxim Kokryashkin:
> * added the description and the test for the problem
> Part of tarantool/tarantool#8825
> ===============================================
> --
> Best regards,
> Maxim Kokryashkin
>
> Четверг, 13 июля 2023, 15:23 +03:00 от Sergey Bronnikov
> <sergeyb@tarantool.org>:
> Hi, Max!
>
>
> thanks for the patch!
>
> Links to the branch and PR are missed, but I found them:
>
> branch:
> https://github.com/tarantool/luajit/tree/fckxorg/mark-conv-non-weak
>
> PR: https://github.com/tarantool/tarantool/pull/8871
>
>
> Test is passed after reverting the patch with fix.
>
>
> Sergey
>
>
> On 7/12/23 12:52, Maksim Kokryashkin wrote:
> > From: Mike Pall <mike>
> >
> > An unused guarded CONV int.num cannot be omitted in general.
> >
> > (cherry-picked from commit 881d02d3117838acaf4fb844332c8e33cc95c8c5)
> >
> > In some cases, an unused `CONV` omission may lead to a guard
> > absence, resulting in invalid control flow branching and
> > undefined behavior. For a comprehensive example of
> > the described situation, please refer to the comment
> > in `test/tarantool-tests/mark-conv-non-weak.test.lua`.
> >
> > Maxim Kokryashkin:
> > * added the description and the test for the problem
> >
> > Part of tarantool/tarantool#8825
> > ---
> > src/lj_ir.h | 2 +-
> > .../mark-conv-non-weak.test.lua | 58 +++++++++++++++++++
> > 2 files changed, 59 insertions(+), 1 deletion(-)
> > create mode 100644 test/tarantool-tests/mark-conv-non-weak.test.lua
> >
> > diff --git a/src/lj_ir.h b/src/lj_ir.h
> > index e8bca275..bf9b9292 100644
> > --- a/src/lj_ir.h
> > +++ b/src/lj_ir.h
> > @@ -132,7 +132,7 @@
> > _(XBAR, S , ___, ___) \
> > \
> > /* Type conversions. */ \
> > - _(CONV, NW, ref, lit) \
> > + _(CONV, N , ref, lit) \
> > _(TOBIT, N , ref, ref) \
> > _(TOSTR, N , ref, lit) \
> > _(STRTO, N , ref, ___) \
> > diff --git a/test/tarantool-tests/mark-conv-non-weak.test.lua
> b/test/tarantool-tests/mark-conv-non-weak.test.lua
> > new file mode 100644
> > index 00000000..aad39058
> > --- /dev/null
> > +++ b/test/tarantool-tests/mark-conv-non-weak.test.lua
> > @@ -0,0 +1,58 @@
> > +local tap = require('tap')
> > +local test = tap.test('mark-conv-non-weak'):skipcond({
> > + ['Test requires JIT enabled'] = not jit.status(),
> > +})
> > +
> > +test:plan(1)
> > +
> > +local data = {0.1, 0, 0.1, 0, 0 / 0}
> > +local sum = 0
> > +
> > +jit.opt.start('hotloop=1', 'hotexit=1')
> > +
> > +-- When the last trace is recorded, the traced bytecode
> > +-- is the following before the patch:
> > +-- ---- TRACE 4 start 2/3 test.lua:6
> > +-- 0018 ADDVV 1 1 6
> > +-- 0019 ITERC 5 3 3
> > +-- 0000 . FUNCC ; ipairs_aux
> > +-- 0020 JITERL 5 1
> > +-- 0021 GGET 2 7 ; "assert"
> > +-- 0022 ISEQV 1 1
> > +-- 0023 JMP 4 => 0026
> > +-- 0024 KPRI 4 1
> > +-- 0025 JMP 5 => 0027
> > +-- 0027 CALL 2 1 2
> > +-- 0000 . FUNCC ; assert
> > +--
> > +-- And the following after the patch:
> > +-- ---- TRACE 4 start 2/2 test.lua:5
> > +-- 0016 ISNEV 6 6
> > +-- 0017 JMP 7 => 0019
> > +-- 0019 ITERC 5 3 3
> > +-- 0000 . FUNCC ; ipairs_aux
> > +-- 0020 JITERL 5 1
> > +-- 0021 GGET 2 7 ; "assert"
> > +-- 0022 ISEQV 1 1
> > +-- 0023 JMP 4 => 0026
> > +-- 0026 KPRI 4 2
> > +-- 0027 CALL 2 1 2
> > +-- 0000 . FUNCC ; assert
> > +-- 0028 RET0 0 1
> > +--
> > +-- The crucial difference here is the abscent
> > +-- `ISNEV` in the first case, which produces the
> > +-- desired guarded `CONV`, when translated to IR.
> > +--
> > +-- Since there is no guard, NaN is added to the sum,
> > +-- despite the test case logic.
> > +
> > +for _, val in ipairs(data) do
> > + if val == val then
> > + sum = sum + val
> > + end
> > +end
> > +
> > +test:ok(sum == sum, 'NaN check was not omitted')
> > +
> > +os.exit(test:check() and 0 or 1)
>
[-- Attachment #2: Type: text/html, Size: 11658 bytes --]
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [Tarantool-patches] [PATCH] Mark CONV as non-weak, to prevent elimination of its side-effect.
2023-07-12 9:52 [Tarantool-patches] [PATCH] Mark CONV as non-weak, to prevent elimination of its side-effect Maksim Kokryashkin via Tarantool-patches
2023-07-13 12:23 ` Sergey Bronnikov via Tarantool-patches
2023-08-24 7:26 ` Sergey Kaplun via Tarantool-patches
@ 2023-11-23 6:31 ` Igor Munkin via Tarantool-patches
2 siblings, 0 replies; 6+ messages in thread
From: Igor Munkin via Tarantool-patches @ 2023-11-23 6:31 UTC (permalink / raw)
To: Maksim Kokryashkin; +Cc: tarantool-patches
Max,
I've checked the patchset into all long-term branches in
tarantool/luajit and bumped a new version in master, release/2.11 and
release/2.10.
On 12.07.23, Maksim Kokryashkin via Tarantool-patches wrote:
> From: Mike Pall <mike>
>
> An unused guarded CONV int.num cannot be omitted in general.
>
> (cherry-picked from commit 881d02d3117838acaf4fb844332c8e33cc95c8c5)
>
> In some cases, an unused `CONV` omission may lead to a guard
> absence, resulting in invalid control flow branching and
> undefined behavior. For a comprehensive example of
> the described situation, please refer to the comment
> in `test/tarantool-tests/mark-conv-non-weak.test.lua`.
>
> Maxim Kokryashkin:
> * added the description and the test for the problem
>
> Part of tarantool/tarantool#8825
> ---
> src/lj_ir.h | 2 +-
> .../mark-conv-non-weak.test.lua | 58 +++++++++++++++++++
> 2 files changed, 59 insertions(+), 1 deletion(-)
> create mode 100644 test/tarantool-tests/mark-conv-non-weak.test.lua
>
<snipped>
> --
> 2.39.2 (Apple Git-143)
>
--
Best regards,
IM
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2023-11-23 6:37 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-07-12 9:52 [Tarantool-patches] [PATCH] Mark CONV as non-weak, to prevent elimination of its side-effect Maksim Kokryashkin via Tarantool-patches
2023-07-13 12:23 ` Sergey Bronnikov via Tarantool-patches
2023-07-17 15:11 ` Maxim Kokryashkin via Tarantool-patches
2023-11-20 8:24 ` Sergey Bronnikov via Tarantool-patches
2023-08-24 7:26 ` Sergey Kaplun via Tarantool-patches
2023-11-23 6:31 ` 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