optimizationluacompiler-optimizationbytecode

How does Lua take advantage of <const> when emitting bytecode?


I'm toying with Lua and using https://www.luac.nl/ to see how it translates to bytecode. I wanted to see if a pattern like if boolean_always_true then ... end where the boolean was defined with <const> would get optimized. Same for always false boolean.

local always_true <const> = true
local always_false <const> = false

function foo()
  if always_true then
      print("Hello World!")
  end
end

function bar()
  if always_false then
      print("Hello World!")
  end
end

ends up being

function foo() --line 4 through 8
1   GETTABUP    0 0 0   ; _ENV "print"
2   LOADK   1 1 ; "Hello World!"
3   CALL    0 2 1   ; 1 in 0 out
4   RETURN0

function bar() --line 10 through 14
1   LOADFALSE   0   
2   TEST    0 0 
3   JMP 3   to pc 7
4   GETTABUP    0 0 0   ; _ENV "print"
5   LOADK   1 1 ; "Hello World!"
6   CALL    0 2 1   ; 1 in 0 out
7   RETURN0 

Why does the always_true case gets optimized and the if disappears but the always_false case doesn't?

I tried different configurations of the code and looking at the produced bytecode with https://www.luac.nl/. I was expecting bar to just be RETURN0


Solution

  • This has nothing to do with <const>, you can use an old version of Lua (<= 5.1.4) to test the code below:

    function bar()
      if false then
          print("Hello World!")
      end
    end
    

    And you will see an optimized result:

    JMP        3    ;jump to return
    GETGLOBAL  0 -1
    LOADK      1 -2
    CALL       0 2 1    
    RETURN     0 1
    

    Very good, right? But an issue is hidden here. As is well known, the logical operators in Lua (and, or) are quite unique. In fact, they share the same logic as some statements such as if-else, and jumping up directly causes such a bug:

    -- version <= 5.1.4: nil
    print(((nil and nil) or false) and true)
    

    Due to the fact that the left expression ((nil and nil) or false) of the last and is clearly falsy, lua skips evaluating the value of the expression, resulting in some slight deviations in the final result. So lua's solution is to always evaluate falsy expressions.

    You may ask if there is a better solution, and I think there must be, but you also need to know that lua has very few developers.