Hi, Sergey, thanks for the patch! The bug cannot be reproduced with reverted fix. CMake: cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug -DLUAJIT_NUMMODE=2 Sergey On 3/2/26 11:14, Sergey Kaplun wrote: > From: Mike Pall > > Reported by Sergey Kaplun. > > (cherry picked from commit 406cf69b3ae0a3ecd5ede2bb97b937b7a5d92074) > > `rec_for_loop()` narrows the FORL index values by getting them from the > runtime. In case when the `start`, `stop`, `step` control variables are > already loaded to the slots, their TRef isn't converted to the > corresponding type. This leads to the following inconsistent IR dump and > to the assertion failure later: > | 0002 > int SLOAD 10 TCI > | 0003 int ADD 0002 +1. > | 0004 > int LE 0003 +1. > | 0005 int ADD 0003 +1. > | 0006 > int GT 0005 +1. > > This patch adds the missing type conversion. > > Sergey Kaplun: > * added the description and the test for the problem > > Part of tarantool/tarantool#12134 > --- > > Branch:https://github.com/tarantool/luajit/tree/skaplun/lj-1413-missing-conv-fori > Related issues: > *https://github.com/LuaJIT/LuaJIT/issues/1413 > *https://github.com/tarantool/tarantool/issues/12134 > > src/lj_record.c | 25 +++++++---- > .../lj-1413-missing-conv-fori.test.lua | 43 +++++++++++++++++++ > 2 files changed, 60 insertions(+), 8 deletions(-) > create mode 100644 test/tarantool-tests/lj-1413-missing-conv-fori.test.lua > > diff --git a/src/lj_record.c b/src/lj_record.c > index ba409a61..abb6334a 100644 > --- a/src/lj_record.c > +++ b/src/lj_record.c > @@ -365,12 +365,27 @@ static TRef fori_load(jit_State *J, BCReg slot, IRType t, int mode) > mode + conv); > } > > +/* Convert FORI argument to expected target type. */ > +static TRef fori_conv(jit_State *J, TRef tr, IRType t) > +{ > + if (t == IRT_INT) { > + if (!tref_isinteger(tr)) > + return emitir(IRTGI(IR_CONV), tr, IRCONV_INT_NUM|IRCONV_CHECK); > + } else { > + if (!tref_isnum(tr)) > + return emitir(IRTN(IR_CONV), tr, IRCONV_NUM_INT); > + } > + return tr; > +} > + > /* Peek before FORI to find a const initializer. Otherwise load from slot. */ > static TRef fori_arg(jit_State *J, const BCIns *fori, BCReg slot, > IRType t, int mode) > { > TRef tr = J->base[slot]; > - if (!tr) { > + if (tr) { > + tr = fori_conv(J, tr, t); > + } else { > tr = find_kinit(J, fori, slot, t); > if (!tr) > tr = fori_load(J, slot, t, mode); > @@ -517,13 +532,7 @@ static LoopEvent rec_for(jit_State *J, const BCIns *fori, int isforl) > lj_assertJ(tref_isnumber_str(tr[i]), "bad FORI argument type"); > if (tref_isstr(tr[i])) > tr[i] = emitir(IRTG(IR_STRTO, IRT_NUM), tr[i], 0); > - if (t == IRT_INT) { > - if (!tref_isinteger(tr[i])) > - tr[i] = emitir(IRTGI(IR_CONV), tr[i], IRCONV_INT_NUM|IRCONV_CHECK); > - } else { > - if (!tref_isnum(tr[i])) > - tr[i] = emitir(IRTN(IR_CONV), tr[i], IRCONV_NUM_INT); > - } > + tr[i] = fori_conv(J, tr[i], t); > } > tr[FORL_EXT] = tr[FORL_IDX]; > stop = tr[FORL_STOP]; > diff --git a/test/tarantool-tests/lj-1413-missing-conv-fori.test.lua b/test/tarantool-tests/lj-1413-missing-conv-fori.test.lua > new file mode 100644 > index 00000000..ba1fa74a > --- /dev/null > +++ b/test/tarantool-tests/lj-1413-missing-conv-fori.test.lua > @@ -0,0 +1,43 @@ > +local tap = require('tap') > + > +-- Test file to demonstrate LuaJIT incorrect recording of FORI > +-- bytecode in the DUALNUM mode. > +-- See also:https://github.com/LuaJIT/LuaJIT/issues/1413. > + > +local test = tap.test('lj-1413-missing-conv-fori'):skipcond({ > + ['Test requires JIT enabled'] = not jit.status(), > +}) > + > +test:plan(1) > + > +local function always_number(val) > + -- Trace 3 starts as a side trace for the first one. > + return tonumber(val) or 1 > +end > + > +jit.opt.start('hotloop=1', 'hotexit=1') > + > +-- Compile the root trace with stitching. > +always_number() > +always_number('') > + > +-- An additional loop to evidentiate the issue for x86 arch in the > +-- DUALNUM mode. > +for _ = 1, 2 do > + -- Use '%' to force number slots. > + for i = always_number(9 % 1), 1 do > + -- The resulting IR for the trace 4 is the following: > + -- | 0002 > int SLOAD 10 TCI > + -- | 0003 int ADD 0002 +1. > + -- | 0004 > int LE 0003 +1. > + -- | 0005 int ADD 0003 +1. > + -- | 0006 > int GT 0005 +1. > + -- > + -- The problem is within the type mismatch between the result > + -- type and the right operand in the IRs. > + for _ = '9' % i, always_number('') do end -- Trace 4. > + end > +end > + > +test:ok(true, 'no assertion failure') > +test:done(true)