local tap = require('tap')

-- Test file to demonstrate LuaJIT's incorrect maintenance of the
-- IR chain during DCE.
-- See also: https://github.com/LuaJIT/LuaJIT/issues/1094.

local test = tap.test('lj-1094-ir-chain-dce'):skipcond({
  ['Test requires JIT enabled'] = not jit.status(),
})

test:plan(1)

jit.opt.start('hotloop=1')

-- XXX: The code below is generated by the fuzzer (locally) and
-- simplified as much as possible. The test leads to the assertion
-- failure only for GC64.

-- Simple noop function.
local __newindex = function() end
debug.setmetatable(0, {
    __newindex = __newindex,
})

local counter = 0
-- luacheck: no unused
local tab = {}
while true do
  -- The loop is still not recorded because the guard always
  -- fails.
  -- So, just try to compile it and check that there is no
  -- assertion failure.
  if counter > 2 then break end
  counter = counter + 1
  -- The pattern `-#{}` allows us to get CONV IRs. The first
  -- appearance of this IR (in the `(-#{}).key`) is considered
  -- unused by the compiler due to the corresponding "noop"
  -- `__newindex` function.
  -- The second usage of conversion (`tab[-#{}]`) is guarded (to
  -- the int type), so it can't be eliminated.
  -- As a result, the 0049 CONV references the 0040 NOP IR after
  -- DCE in the IR chain. The IR itself looks like the following
  -- by the `jit.dump` (NOPs are not printed):
  -- 0036    num CONV   0035  num.int
  -- 0037    num NEG    0036  0007
  -- 0042 >  tab TDUP   {0x40154030}
  -- 0043    int FLOAD  0014  tab.hmask
  -- 0044 >  int EQ     0043  +1
  -- 0045    p32 FLOAD  0014  tab.node
  -- 0046 >  p32 HREFK  0045  "__newindex" @0
  -- 0047 >  fun HLOAD  0046
  -- 0048 >  fun EQ     0047  "lj-1094-ir-chain-dce.test.lua":20
  -- 0049 >  int CONV   0037  int.num index

  -- XXX: TDUP prevents the corresponding second usage from being
  -- eliminated since the table insert semantics may change.
  -- XXX: Use some numbers to simplify reading the `jit.dump`
  -- output.
  tab, tab[-#{}], (-#{}).key = {tdup = 'tdup'}, 1, 2
end

test:ok(true, 'no assertion failure')

test:done(true)
