-- Inlineable analysis: -- `a` is inlineable at P if -- `a` is dead after P and -- `a` isn't used within the prior use-range local utils = require 'luainlua.common.utils' local cfg = require 'luainlua.cfg.cfg' local undump = require 'luainlua.bytecode.undump' local worklist = require 'luainlua.common.worklist' local liveness = require 'luainlua.cfg.liveness' local TOP = 'TOP' local inlineable = {} local woot = function(n) n = unpack(n) return n > 255 and {} or {n} end local A = function(instr) return woot {instr.A.raw} end local B = function(instr) return woot {instr.B.raw} end local C = function(instr) return woot {instr.C.raw} end local function top(number) return function(instr) local x = unpack(number(instr)) if x == 0 then return {TOP} end return {x} end end local function range(from, number) return function(instr) local left = unpack(from(instr)) local num = unpack(number(instr)) local registers = {} if num == TOP then return {left} end for i = 0, num do table.insert(registers, left + i) end return registers end end local function offset(start, amount, invert) return function(instr) local left = unpack(start(instr)) local off = unpack(amount(instr)) if left == TOP then return {TOP} end return {invert and (left - off) or (left + off)} end end local function constant(n) return function() return {n} end end local function kill(...) local actions = {...} return function(self, pc, instr, current, graph, node) local new = utils.copy(current) for action in utils.loop(actions) do for register in utils.loop(action(instr)) do new[register] = {[pc] = "inlineable"} end end return new end end local function use(...) local actions = {...} return function(self, pc, instr, current, graph, node) local new = utils.copy(current) for action in utils.loop(actions) do for register in utils.loop(action(instr)) do for pc in pairs(current[register] or {}) do new[register][pc] = "clobbered" end end end return new end end local actions = { {"MOVE", kill(A), use(B)}, --R(A) := R(B) {"LOADK", kill(A), use()}, --R(A) := Kst(Bx) {"LOADKX", kill(A), use()}, --R(A) := Kst(extra arg) {"LOADBOOL", kill(A), use()}, --R(A) := (Bool)B; if (C) pc++ {"LOADNIL", kill(range(A, offset(B, A, true))), use()}, --R(A) := ... := R(B) := nil {"GETUPVAL", kill(A), use()}, --R(A) := UpValue[B] {"GETTABUP", kill(A), use(C)}, --R(A) := UpValue[B][RK(C)] {"GETTABLE", kill(A), use(B, C)}, --R(A) := R(B)[RK(C)] {"SETTABUP", kill(), use(B, C)}, --UpValue[A][RK(B)] := RK(C) {"SETUPVAL", kill(), use(A)}, --UpValue[B] := R(A) {"SETTABLE", kill(), use(A, B, C)}, --R(A)[RK(B)] := RK(C) {"NEWTABLE", kill(A), use()}, --R(A) := {} (size = B,C) {"SELF", kill(A, offset(A, constant(1))), use(B, C)}, --R(A+1) := R(B); R(A) := R(B)[RK(C)] {"ADD", kill(A), use(B, C)}, --R(A) := RK(B) + RK(C) {"SUB", kill(A), use(B, C)}, --R(A) := RK(B) - RK(C) {"MUL", kill(A), use(B, C)}, --R(A) := RK(B) * RK(C) {"DIV", kill(A), use(B, C)}, --R(A) := RK(B) / RK(C) {"MOD", kill(A), use(B, C)}, --R(A) := RK(B) % RK(C) {"POW", kill(A), use(B, C)}, --R(A) := RK(B) ^ RK(C) {"UNM", kill(A), use(B)}, --R(A) := -R(B) {"NOT", kill(A), use(B)}, --R(A) := not R(B) {"LEN", kill(A), use(B)}, --R(A) := length of R(B) {"CONCAT", kill(A), use(range(B, offset(C, B, true)))}, --R(A) := R(B).. ... ..R(C) {"JMP", kill(), use()}, --pc+=sBx {"EQ", kill(), use(B, C)}, --if ((RK(B) == RK(C)) ~= A) then pc++ {"LT", kill(), use(B, C)}, --if ((RK(B) < RK(C)) ~= A) then pc++ {"LE", kill(), use(B, C)}, --if ((RK(B) <= RK(C)) ~= A) then pc++ {"TEST", kill(), use(A)}, --if not (R(A) <=> C) then pc++ {"TESTSET", kill(A), use(B)}, --if (R(B) <=> C) then R(A) := R(B) else pc++ {"CALL", kill(range(A, offset(top(C), constant(-2)))), use(range(A, offset(top(B), constant(-1))))}, --R(A), ... ,R(A+C-2) := R(A)(R(A+1), ... ,R(A+B-1)) {"TAILCALL", kill(), use(range(A, offset(top(B), constant(-1))))}, --return R(A)(R(A+1), ... ,R(A+B-1)) {"RETURN", kill(), use(range(A, offset(top(B), constant(-2))))}, --return R(A), ... ,R(A+B-2)(see note) {"FORLOOP", kill(A, offset(A, constant(1)), offset(A, constant(2)), offset(A, constant(3))), use()}, --R(A)+=R(A+2); --if R(A) ', origin_print(solution:after(pc))) --end inlineable.solve = solve return inlineable