Incorrect narrowing for huge numbers.

Aberta
#1,236 1 comentário 1 reação 0 responsáveis Ver no GitHub

Ninguém assumiu esta issue ainda.

Avaliação

Dificuldade
4/5
Tempo estimado
3-5 dias
Facilidade para iniciantes
18/100
Tipo de issue
Bug
Clareza
Claramente especificada
Status de atividade
Estagnada
Stack de tecnologia
c
Domínio
compilers

Direção de pesquisa

The bug is in the narrowing pass of the JIT, so start in src/lj_opt_narrow.c, at narrow_conv_emit, where the integer conversion is emitted. Reproduce with src/luajit -Ohotloop=1 using the s + 1 - 0LL - s loop from the issue, and compare against jit.off(). Done when the traced results match the interpreter for values at or beyond 2^53, and the trace dump shows the range guard.

Escrita pelo modelo de indexação a partir do texto da issue.

Descrição

Mantissa precision of IEEE-754 doubles can't store integral types precision for |x| >= 2^53.
That means that premature folding optimization may lead to invalid results in cases like the following:

x + 1 + 0LL - x => 1LL; x >= 2^53
x - 1 + 0LL - x => -1LL; x <= -2^53

since it changes the semantics of operations to (int)x + 1LL instead of (int)((double)x + 1.) + 0LL.

Lua examples of this misbehaviour:

src/luajit -Ohotloop=1 -e '
local s = 2^53
local v = {}
for i = 1, 4 do
        v[i] = s + 1 - 0LL - s
end
jit.off()

for i = 1, 4 do
        print(i,v[i])
end
'
1       0LL
2       0LL
3       0LL
4       1LL

or vice versa for substracture:

src/luajit -Ohotloop=1 -e '
local s = -2^53
local v = {}
for i = 1, 4 do
        v[i] = s - 1 - 0LL - s
end
jit.off()

for i = 1, 4 do
        print(i,v[i])
end
'
1       0LL
2       0LL
3       0LL
4       -1LL

The start of the trace looks like the following with enabled narrowing:

---- TRACE 1 start (command line):4
---- TRACE 1 IR
0001    int SLOAD  #4    CI
0002 >  num SLOAD  #2    T
0007 >  cdt CNEWI  +11   +1  

And like the following with disabled:

0001    num SLOAD  #4    I
0002 >  num SLOAD  #2    T
0003    num ADD    0002  +1  
0004    i64 CONV   0003  i64.num none
0006    i64 CONV   0002  i64.num none
0007    i64 SUB    0004  0006
0008 >  cdt CNEWI  +11   0007

One of the ways to fix it is to add an assertion guard before corresponding conversions (it seems harmless for the SPEC benchmarks).

PoC workaround for the problem:
diff --git a/src/lj_opt_narrow.c b/src/lj_opt_narrow.c
index db0da10f..5dd3819c 100644
--- a/src/lj_opt_narrow.c
+++ b/src/lj_opt_narrow.c
@@ -370,6 +370,15 @@ static IRRef narrow_conv_emit(jit_State *J, NarrowConv *nc)
     if (op == NARROW_REF) {
       *sp++ = ref;
     } else if (op == NARROW_CONV) {
+      if (fins->o == IR_CONV && (fins->op2 & IRCONV_SRCMASK) == IRT_NUM) {
+        IRIns *srcins = IR(fins->op1);
+        if (srcins->o == IR_SUB)
+          emitir(IRTG(IR_GT, IRT_NUM), srcins->op1,
+                 lj_ir_knum(J, -(lua_Number)(1LL<<52)));
+        else if (srcins->o == IR_ADD)
+          emitir(IRTG(IR_LT, IRT_NUM), srcins->op1,
+                 lj_ir_knum(J, (lua_Number)(1LL<<52)));
+      }
       *sp++ = emitir_raw(convot, ref, convop2);  /* Raw emit avoids a loop. */
     } else if (op == NARROW_SEXT) {
       lj_assertJ(sp >= nc->stack+1, "stack underflow");

The start of a trace after the patch looks like the following:

---- TRACE 1 IR
0001    int SLOAD  #4    CI
0002 >  num SLOAD  #2    T
0004 >  num LT     0002  +4.5035996273705e+15
0008 >  cdt CNEWI  +11   +1 
Linguagem predominante
C
Estrelas
5.8k
Forks
1.2k
Métricas de merge de PRs
Nenhum PR com merge em 30d

Preparar o ambiente

Este projeto não oferece contêiner de desenvolvimento, Dockerfile nem guia de contribuição, então a configuração fica por sua conta: comece pelo README e veja nosso guia da primeira contribuição para os passos gerais.

Primeiros passos

  1. Leia a issue inteira e depois o guia de contribuição do projeto.
  2. Comente na issue dizendo que vai assumir — evita que duas pessoas façam o mesmo trabalho.
  3. Faça um fork do repositório e trabalhe em uma branch.
  4. Abra um pull request que referencie o número da issue.

Mais de LuaJIT/LuaJIT

Todas as issues de LuaJIT/LuaJIT

Issues semelhantes

Mais issues de C

Receba novas issues na sua caixa de entrada

Um resumo curto de issues do GitHub para quem está começando.