|
| 1 | +local tap = require('tap') |
| 2 | + |
| 3 | +-- Test file to demonstrate LuaJIT's incorrect fold optimization |
| 4 | +-- for Array Bound Check for constants. |
| 5 | +-- ABC(asize, k1), ABC(asize k2) ==> ABC(asize, max(k1, k2)). |
| 6 | +-- See also https://github.com/LuaJIT/LuaJIT/issues/794. |
| 7 | + |
| 8 | +local test = tap.test('lj-794-abc-fold-constants'):skipcond({ |
| 9 | + ['Test requires JIT enabled'] = not jit.status(), |
| 10 | +}) |
| 11 | + |
| 12 | +test:plan(2) |
| 13 | + |
| 14 | +local MAGIC_UNUSED = 42 |
| 15 | + |
| 16 | +local function abc_check_sign() |
| 17 | + local tab = {MAGIC_UNUSED} |
| 18 | + local return_value = 0 |
| 19 | + local abc_limit = 1 |
| 20 | + -- No need to run the loop on the first call. We will take |
| 21 | + -- the side exit anyway. |
| 22 | + for i = 1, 3 do |
| 23 | + -- Add an additional ABC check to be merged with. |
| 24 | + if i > 1 then |
| 25 | + -- luacheck: ignore |
| 26 | + return_value = tab[1] |
| 27 | + return_value = tab[abc_limit] |
| 28 | + -- XXX: Just use some negative number. |
| 29 | + abc_limit = -1000000 |
| 30 | + end |
| 31 | + end |
| 32 | + return return_value |
| 33 | +end |
| 34 | + |
| 35 | +jit.opt.start('hotloop=1') |
| 36 | + |
| 37 | +-- Compile the loop. |
| 38 | +abc_check_sign() |
| 39 | +-- Run the loop. |
| 40 | +test:is(abc_check_sign(), nil, 'correct ABC constant rule for negative values') |
| 41 | + |
| 42 | +-- Now test the second issue, when ABC optimization applies for |
| 43 | +-- operands across PHIs. |
| 44 | + |
| 45 | +-- XXX: Reset hotcounters to avoid collisions. |
| 46 | +jit.opt.start('hotloop=1') |
| 47 | + |
| 48 | +local tab_array = {} |
| 49 | +local small_tab = {MAGIC_UNUSED} |
| 50 | +local full_tab = {} |
| 51 | + |
| 52 | +-- First, create tables with different asizes, to be used in PHI. |
| 53 | +-- Create a large enough array part for the noticeable |
| 54 | +-- out-of-bounds access. |
| 55 | +for i = 1, 8 do |
| 56 | + full_tab[i] = MAGIC_UNUSED |
| 57 | +end |
| 58 | + |
| 59 | +-- Now, store these tables in the array. The PHI should be used in |
| 60 | +-- the trace to distinguish asizes from the variant and the |
| 61 | +-- invariant parts of the loop for the future ABC check. |
| 62 | +-- Nevertheless, before the patch, the ABC IR and the |
| 63 | +-- corresponding PHI are folded via optimization. This leads to |
| 64 | +-- incorrect behaviour. |
| 65 | +-- We need 5 iterations to execute both the variant and the |
| 66 | +-- invariant parts of the trace below. |
| 67 | +for i = 1, 5 do |
| 68 | + -- On the 3rd iteration, the recording is started. |
| 69 | + if i > 3 then |
| 70 | + tab_array[i] = small_tab |
| 71 | + else |
| 72 | + tab_array[i] = full_tab |
| 73 | + end |
| 74 | +end |
| 75 | + |
| 76 | +local result |
| 77 | +local alias_tab = tab_array[1] |
| 78 | +-- Compile a trace. |
| 79 | +-- Run 5 iterations to execute both the variant and the invariant |
| 80 | +-- parts. |
| 81 | +for i = 1, 5 do |
| 82 | + local previous_tab = alias_tab |
| 83 | + alias_tab = tab_array[i] |
| 84 | + -- Additional ABC check to fold. |
| 85 | + -- luacheck: ignore |
| 86 | + result = alias_tab[1] |
| 87 | + result = previous_tab[8] |
| 88 | +end |
| 89 | + |
| 90 | +test:is(result, nil, 'correct ABC constant rule across PHI') |
| 91 | + |
| 92 | +test:done(true) |
0 commit comments