Esempio n. 1
0
 private static Expression RKIR(ILuaFunction fun, uint val)
 {
     if (val < 250)
     {
         return(new IR.IdentifierReference(SymbolTable.GetRegister(val)));
     }
     else
     {
         return(ToConstantIR(fun.Constants[(int)(val - 250)]));
     }
 }
Esempio n. 2
0
 private static Expression RKIRHKS(ILuaFunction fun, uint val, bool szero)
 {
     if (val >= 0 && !szero)
     {
         return(new IR.IdentifierReference(SymbolTable.GetRegister((uint)val)));
     }
     else if (szero)
     {
         return(ToConstantIR(fun.Constants[(int)val]));
     }
     else
     {
         return(ToConstantIR(fun.Constants[(int)-val]));
     }
 }
Esempio n. 3
0
        public void DecompileFunction(Function function, ILuaFunction luaFunction)
        {
            function.Id = luaFunction.LuaFile.FunctionIdCounter++;
            // First register closures for all the children
            for (uint i = 0; i < luaFunction.ChildFunctions.Count; i++)
            {
                var func = new Function(function, function.SymbolTable, luaFunction.LuaFile);
                luaFunction.ChildFunctions[(int)i].IRFunction = func;
                function.Closures.Add(func);
            }
            // Start a new scope for the function's variables
            function.SymbolTable.BeginScope();
            // Register the parameters of the function
            for (uint i = 0; i < luaFunction.Header.ParameterCount; i++)
            {
                function.Parameters.Add(function.SymbolTable.GetRegister(i));
            }
            // Convert lua instructions to IR instructions
            var converter = luaFunction.LuaFile.InstructionConverter;

            converter.Convert(function, luaFunction);
            // Pass analysis
            var analyzers = luaFunction.LuaFile.AnalyzerList.GetAnalyzers();

            for (int i = 0; i < analyzers.Count; i++)
            {
                analyzers[i].Analyze(function);
            }
            // Decompile all child functions
            for (int i = 0; i < luaFunction.ChildFunctions.Count; i++)
            {
                DecompileFunction(function.Closures[i], luaFunction.ChildFunctions[i]);
            }
            // File analysis on main function
            if (function.Parent == null && function.IsAST)
            {
                var fileAnalyzers = luaFunction.LuaFile.FileAnalyzerList.GetAnalyzers();
                for (int i = 0; i < fileAnalyzers.Count; i++)
                {
                    fileAnalyzers[i].Analyze(function);
                }
            }
            // Close the scope of this function
            function.SymbolTable.EndScope();
        }
Esempio n. 4
0
        protected override ILuaFunction ReadFunctions()
        {
            // Continue reading functions untill we are at the end
            ILuaFunction mainFunc = null;
            var          i        = 0;

            while (true)
            {
                var function = ReadFunction();

                if (function.FunctionPos == -1)
                {
                    break;
                }
                i++;

                Functions.Push(function);
                mainFunc = function;
            }

            return(mainFunc);
        }
Esempio n. 5
0
        public static void GenerateIRHKS(IR.Function irfun, ILuaFunction fun)
        {
            // First register closures for all the children
            for (int i = 0; i < fun.ChildFunctions.Count; i++)
            {
                var cfun = new IR.Function();
                // Upval count needs to be set for child functions for analysis to be correct
                cfun.UpvalCount = fun.ChildFunctions[i].Upvalues.Count;
                irfun.AddClosure(cfun);
            }

            SymbolTable.BeginScope();
            var parameters = new List <IR.Identifier>();

            for (uint i = 0; i < fun.Header.ParameterCount; i++)
            {
                parameters.Add(SymbolTable.GetRegister(i));
            }
            irfun.SetParameters(parameters);

            for (int i = 0; i < fun.Instructions.Count * 4; i += 4)
            {
                var instruction = fun.Instructions[i / 4];
                //uint opcode = instruction & 0x3F;
                // Uhhh thanks again hork
                var opcode = instruction.OpCode;
                var a      = instruction.A;
                var c      = instruction.C;
                var b      = instruction.B;
                var szero  = instruction.ExtraCBit;

                var  bx  = instruction.Bx;
                var  sbx = instruction.SBx;
                uint addr;
                var  pc = i / 4;

                List <IR.Expression>          args         = null;
                List <IR.IdentifierReference> rets         = null;
                List <IR.IInstruction>        instructions = new List <IR.IInstruction>();
                IR.Assignment assn;
                switch (opcode)
                {
                case LuaOpCode.HKS_OPCODE_MOVE:
                    assn = new IR.Assignment(SymbolTable.GetRegister(a), Register((uint)b));
                    CheckLocal(assn, fun, pc);
                    instructions.Add(assn);
                    break;

                case LuaOpCode.HKS_OPCODE_LOADK:
                    assn = new IR.Assignment(SymbolTable.GetRegister(a), ToConstantIR(fun.Constants[(int)bx]));
                    CheckLocal(assn, fun, pc);
                    instructions.Add(assn);
                    break;

                case LuaOpCode.HKS_OPCODE_LOADBOOL:
                    assn = new IR.Assignment(SymbolTable.GetRegister(a), new IR.Constant(b == 1));
                    assn.NilAssignmentReg = a;
                    CheckLocal(assn, fun, pc);
                    instructions.Add(assn);
                    if (c > 0)
                    {
                        instructions.Add(new IR.Jump(irfun.GetLabel((uint)((i / 4) + 2))));
                    }
                    break;

                case LuaOpCode.HKS_OPCODE_LOADNIL:
                    var nlist = new List <IR.IdentifierReference>();
                    for (int arg = (int)a; arg <= b; arg++)
                    {
                        nlist.Add(new IR.IdentifierReference(SymbolTable.GetRegister((uint)arg)));
                    }
                    assn = new IR.Assignment(nlist, new IR.Constant(IR.Constant.ConstantType.ConstNil));
                    assn.NilAssignmentReg = a;
                    CheckLocal(assn, fun, pc);
                    instructions.Add(assn);
                    break;

                case LuaOpCode.HKS_OPCODE_GETUPVAL:
                    if (b >= irfun.UpvalueBindings.Count)
                    {
                        //throw new Exception("Reference to unbound upvalue");
                    }

                    Identifier up = irfun.UpvalueBindings[(int)b];
                    up.IsClosureBound = true;
                    instructions.Add(new IR.Assignment(SymbolTable.GetRegister(a), new IR.IdentifierReference(up)));
                    break;

                case LuaOpCode.HKS_OPCODE_SETUPVAL:
                case LuaOpCode.HKS_OPCODE_SETUPVAL_R1:
                    up = SymbolTable.GetUpvalue((uint)b);
                    if (fun.Upvalues.Any() && !up.UpvalueResolved)
                    {
                        up.Name            = fun.Upvalues[(int)b].Name;
                        up.UpvalueResolved = true;
                    }
                    instructions.Add(new IR.Assignment(up, new IR.IdentifierReference(SymbolTable.GetRegister(a))));
                    break;

                case LuaOpCode.HKS_OPCODE_GETGLOBAL_MEM:
                case LuaOpCode.HKS_OPCODE_GETGLOBAL:
                    assn = new IR.Assignment(SymbolTable.GetRegister(a), new IR.IdentifierReference(SymbolTable.GetGlobal(fun.Constants[(int)bx].ToString())));
                    CheckLocal(assn, fun, pc);
                    instructions.Add(assn);
                    break;

                case LuaOpCode.HKS_OPCODE_GETTABLE_S:
                case LuaOpCode.HKS_OPCODE_GETTABLE:
                    assn = new IR.Assignment(SymbolTable.GetRegister(a), new IR.IdentifierReference(SymbolTable.GetRegister((uint)b), RKIRHKS(fun, c, szero)));
                    CheckLocal(assn, fun, pc);
                    instructions.Add(assn);
                    break;

                case LuaOpCode.HKS_OPCODE_SETGLOBAL:
                    instructions.Add(new IR.Assignment(SymbolTable.GetGlobal(fun.Constants[(int)bx].ToString()), new IR.IdentifierReference(SymbolTable.GetRegister(a))));
                    break;

                case LuaOpCode.HKS_OPCODE_NEWTABLE:
                    assn = new IR.Assignment(SymbolTable.GetRegister(a), new IR.InitializerList(new List <IR.Expression>()));
                    assn.VarargAssignmentReg = a;
                    CheckLocal(assn, fun, pc);
                    instructions.Add(assn);
                    break;

                case LuaOpCode.HKS_OPCODE_SELF:
                    instructions.Add(new IR.Assignment(SymbolTable.GetRegister(a + 1), Register((uint)b)));
                    instructions.Add(new IR.Assignment(SymbolTable.GetRegister(a), new IR.IdentifierReference(SymbolTable.GetRegister((uint)b), RKIRHKS(fun, c, szero))));
                    break;

                case LuaOpCode.HKS_OPCODE_ADD:
                    assn = new IR.Assignment(SymbolTable.GetRegister(a), new IR.BinOp(Register((uint)b), RKIRHKS(fun, c, szero), IR.BinOp.OperationType.OpAdd));
                    CheckLocal(assn, fun, pc);
                    instructions.Add(assn);
                    break;

                case LuaOpCode.HKS_OPCODE_ADD_BK:
                    assn = new IR.Assignment(SymbolTable.GetRegister(a), new IR.BinOp(ToConstantIR(fun.Constants[(int)b]), Register((uint)c), IR.BinOp.OperationType.OpAdd));
                    CheckLocal(assn, fun, pc);
                    instructions.Add(assn);
                    break;

                case LuaOpCode.HKS_OPCODE_SUB:
                    assn = new IR.Assignment(SymbolTable.GetRegister(a), new IR.BinOp(Register((uint)b), RKIRHKS(fun, c, szero), IR.BinOp.OperationType.OpSub));
                    CheckLocal(assn, fun, pc);
                    instructions.Add(assn);
                    break;

                case LuaOpCode.HKS_OPCODE_SUB_BK:
                    assn = new IR.Assignment(SymbolTable.GetRegister(a), new IR.BinOp(ToConstantIR(fun.Constants[(int)b]), Register((uint)c), IR.BinOp.OperationType.OpSub));
                    CheckLocal(assn, fun, pc);
                    instructions.Add(assn);
                    break;

                case LuaOpCode.HKS_OPCODE_MUL:
                    assn = new IR.Assignment(SymbolTable.GetRegister(a), new IR.BinOp(Register((uint)b), RKIRHKS(fun, c, szero), IR.BinOp.OperationType.OpMul));
                    CheckLocal(assn, fun, pc);
                    instructions.Add(assn);
                    break;

                case LuaOpCode.HKS_OPCODE_MUL_BK:
                    assn = new IR.Assignment(SymbolTable.GetRegister(a), new IR.BinOp(ToConstantIR(fun.Constants[(int)b]), Register((uint)c), IR.BinOp.OperationType.OpMul));
                    CheckLocal(assn, fun, pc);
                    instructions.Add(assn);
                    break;

                case LuaOpCode.HKS_OPCODE_DIV:
                    assn = new IR.Assignment(SymbolTable.GetRegister(a), new IR.BinOp(Register((uint)b), RKIRHKS(fun, c, szero), IR.BinOp.OperationType.OpDiv));
                    CheckLocal(assn, fun, pc);
                    instructions.Add(assn);
                    break;

                case LuaOpCode.HKS_OPCODE_DIV_BK:
                    assn = new IR.Assignment(SymbolTable.GetRegister(a), new IR.BinOp(ToConstantIR(fun.Constants[(int)b]), Register((uint)c), IR.BinOp.OperationType.OpDiv));
                    CheckLocal(assn, fun, pc);
                    instructions.Add(assn);
                    break;

                case LuaOpCode.HKS_OPCODE_MOD:
                    assn = new IR.Assignment(SymbolTable.GetRegister(a), new IR.BinOp(Register((uint)b), RKIRHKS(fun, c, szero), IR.BinOp.OperationType.OpMod));
                    CheckLocal(assn, fun, pc);
                    instructions.Add(assn);
                    break;

                case LuaOpCode.HKS_OPCODE_MOD_BK:
                    assn = new IR.Assignment(SymbolTable.GetRegister(a), new IR.BinOp(ToConstantIR(fun.Constants[(int)b]), Register((uint)c), IR.BinOp.OperationType.OpMod));
                    CheckLocal(assn, fun, pc);
                    instructions.Add(assn);
                    break;

                case LuaOpCode.HKS_OPCODE_POW:
                    assn = new IR.Assignment(SymbolTable.GetRegister(a), new IR.BinOp(Register((uint)b), RKIRHKS(fun, c, szero), IR.BinOp.OperationType.OpPow));
                    CheckLocal(assn, fun, pc);
                    instructions.Add(assn);
                    break;

                case LuaOpCode.HKS_OPCODE_POW_BK:
                    assn = new IR.Assignment(SymbolTable.GetRegister(a), new IR.BinOp(ToConstantIR(fun.Constants[(int)b]), Register((uint)c), IR.BinOp.OperationType.OpPow));
                    CheckLocal(assn, fun, pc);
                    instructions.Add(assn);
                    break;

                case LuaOpCode.HKS_OPCODE_UNM:
                    assn = new IR.Assignment(SymbolTable.GetRegister(a),
                                             new IR.UnaryOp(new IR.IdentifierReference(SymbolTable.GetRegister((uint)b)), IR.UnaryOp.OperationType.OpNegate));
                    CheckLocal(assn, fun, pc);
                    instructions.Add(assn);
                    break;

                case LuaOpCode.HKS_OPCODE_NOT:
                case LuaOpCode.HKS_OPCODE_NOT_R1:
                    assn = new IR.Assignment(SymbolTable.GetRegister(a),
                                             new IR.UnaryOp(new IR.IdentifierReference(SymbolTable.GetRegister((uint)b)), IR.UnaryOp.OperationType.OpNot));
                    CheckLocal(assn, fun, pc);
                    instructions.Add(assn);
                    break;

                case LuaOpCode.HKS_OPCODE_LEN:
                    assn = new IR.Assignment(SymbolTable.GetRegister(a),
                                             new IR.UnaryOp(new IR.IdentifierReference(SymbolTable.GetRegister((uint)b)), IR.UnaryOp.OperationType.OpLength));
                    CheckLocal(assn, fun, pc);
                    instructions.Add(assn);
                    break;

                case LuaOpCode.HKS_OPCODE_SHIFT_LEFT:
                    assn = new IR.Assignment(SymbolTable.GetRegister(a), new IR.BinOp(Register((uint)b), RKIRHKS(fun, c, szero), IR.BinOp.OperationType.OpShiftLeft));
                    CheckLocal(assn, fun, pc);
                    instructions.Add(assn);
                    break;

                case LuaOpCode.HKS_OPCODE_SHIFT_LEFT_BK:
                    assn = new IR.Assignment(SymbolTable.GetRegister(a), new IR.BinOp(ToConstantIR(fun.Constants[(int)b]), Register((uint)c), IR.BinOp.OperationType.OpShiftLeft));
                    CheckLocal(assn, fun, pc);
                    instructions.Add(assn);
                    break;

                case LuaOpCode.HKS_OPCODE_SHIFT_RIGHT:
                    assn = new IR.Assignment(SymbolTable.GetRegister(a), new IR.BinOp(Register((uint)b), RKIRHKS(fun, c, szero), IR.BinOp.OperationType.OpShiftRight));
                    CheckLocal(assn, fun, pc);
                    instructions.Add(assn);
                    break;

                case LuaOpCode.HKS_OPCODE_SHIFT_RIGHT_BK:
                    assn = new IR.Assignment(SymbolTable.GetRegister(a), new IR.BinOp(ToConstantIR(fun.Constants[(int)b]), Register((uint)c), IR.BinOp.OperationType.OpShiftRight));
                    CheckLocal(assn, fun, pc);
                    instructions.Add(assn);
                    break;

                case LuaOpCode.HKS_OPCODE_BITWISE_AND:
                    assn = new IR.Assignment(SymbolTable.GetRegister(a), new IR.BinOp(Register((uint)b), RKIRHKS(fun, c, szero), IR.BinOp.OperationType.OpBAnd));
                    CheckLocal(assn, fun, pc);
                    instructions.Add(assn);
                    break;

                case LuaOpCode.HKS_OPCODE_BITWISE_AND_BK:
                    assn = new IR.Assignment(SymbolTable.GetRegister(a), new IR.BinOp(ToConstantIR(fun.Constants[(int)b]), Register((uint)c), IR.BinOp.OperationType.OpBAnd));
                    CheckLocal(assn, fun, pc);
                    instructions.Add(assn);
                    break;

                case LuaOpCode.HKS_OPCODE_BITWISE_OR:
                    assn = new IR.Assignment(SymbolTable.GetRegister(a), new IR.BinOp(Register((uint)b), RKIRHKS(fun, c, szero), IR.BinOp.OperationType.OpBOr));
                    CheckLocal(assn, fun, pc);
                    instructions.Add(assn);
                    break;

                case LuaOpCode.HKS_OPCODE_BITWISE_OR_BK:
                    assn = new IR.Assignment(SymbolTable.GetRegister(a), new IR.BinOp(ToConstantIR(fun.Constants[(int)b]), Register((uint)c), IR.BinOp.OperationType.OpBOr));
                    CheckLocal(assn, fun, pc);
                    instructions.Add(assn);
                    break;

                case LuaOpCode.HKS_OPCODE_CONCAT:
                    args = new List <IR.Expression>();
                    for (int arg = (int)b; arg <= c; arg++)
                    {
                        args.Add(new IR.IdentifierReference(SymbolTable.GetRegister((uint)arg)));
                    }
                    assn = new IR.Assignment(SymbolTable.GetRegister(a), new IR.Concat(args));
                    CheckLocal(assn, fun, pc);
                    instructions.Add(assn);
                    break;

                case LuaOpCode.HKS_OPCODE_JMP:
                    instructions.Add(new IR.Jump(irfun.GetLabel((uint)(pc + 1 + sbx))));
                    break;

                case LuaOpCode.HKS_OPCODE_EQ:
                    var operation = IR.BinOp.OperationType.OpEqual;
                    if (a == 1)
                    {
                        operation = IR.BinOp.OperationType.OpNotEqual;
                    }
                    instructions.Add(new IR.Jump(irfun.GetLabel((uint)(pc + 2)), new IR.BinOp(Register((uint)b), RKIRHKS(fun, c, szero), operation)));
                    break;

                case LuaOpCode.HKS_OPCODE_EQ_BK:
                    operation = IR.BinOp.OperationType.OpEqual;
                    if (a == 1)
                    {
                        operation = IR.BinOp.OperationType.OpNotEqual;
                    }
                    instructions.Add(new IR.Jump(irfun.GetLabel((uint)(pc + 2)), new IR.BinOp(ToConstantIR(fun.Constants[(int)b]), Register((uint)c), operation)));
                    break;

                case LuaOpCode.HKS_OPCODE_LT:
                    operation = IR.BinOp.OperationType.OpLessThan;
                    if (a == 1)
                    {
                        operation = IR.BinOp.OperationType.OpGreaterEqual;
                    }
                    instructions.Add(new IR.Jump(irfun.GetLabel((uint)(pc + 2)), new IR.BinOp(Register((uint)b), RKIRHKS(fun, c, szero), operation)));
                    break;

                case LuaOpCode.HKS_OPCODE_LT_BK:
                    operation = IR.BinOp.OperationType.OpLessThan;
                    if (a == 1)
                    {
                        operation = IR.BinOp.OperationType.OpGreaterEqual;
                    }
                    instructions.Add(new IR.Jump(irfun.GetLabel((uint)(pc + 2)), new IR.BinOp(ToConstantIR(fun.Constants[(int)b]), Register((uint)c), operation)));
                    break;

                case LuaOpCode.HKS_OPCODE_LE:
                    operation = IR.BinOp.OperationType.OpLessEqual;
                    if (a == 1)
                    {
                        operation = IR.BinOp.OperationType.OpGreaterThan;
                    }
                    instructions.Add(new IR.Jump(irfun.GetLabel((uint)(pc + 2)), new IR.BinOp(Register((uint)b), RKIRHKS(fun, c, szero), operation)));
                    break;

                case LuaOpCode.HKS_OPCODE_LE_BK:
                    operation = IR.BinOp.OperationType.OpLessEqual;
                    if (a == 1)
                    {
                        operation = IR.BinOp.OperationType.OpGreaterThan;
                    }
                    instructions.Add(new IR.Jump(irfun.GetLabel((uint)(pc + 2)), new IR.BinOp(ToConstantIR(fun.Constants[(int)b]), Register((uint)c), operation)));
                    break;

                case LuaOpCode.HKS_OPCODE_TEST:
                case LuaOpCode.HKS_OPCODE_TEST_R1:
                    // This op is weird
                    if (c == 0)
                    {
                        instructions.Add(new IR.Jump(irfun.GetLabel((uint)((i / 4) + 2)), Register((uint)a)));
                    }
                    else
                    {
                        instructions.Add(new IR.Jump(irfun.GetLabel((uint)((i / 4) + 2)), new IR.UnaryOp(Register((uint)a), IR.UnaryOp.OperationType.OpNot)));
                    }
                    break;

                case LuaOpCode.HKS_OPCODE_TESTSET:
                    // This op is weird
                    if (c == 0)
                    {
                        instructions.Add(new IR.Jump(irfun.GetLabel((uint)((i / 4) + 2)), new IR.BinOp(RKIR(fun, b), new IR.Constant(0.0), IR.BinOp.OperationType.OpNotEqual)));
                    }
                    else
                    {
                        instructions.Add(new IR.Jump(irfun.GetLabel((uint)((i / 4) + 2)), new IR.BinOp(RKIR(fun, b), new IR.Constant(0.0), IR.BinOp.OperationType.OpEqual)));
                    }
                    instructions.Add(new IR.Assignment(SymbolTable.GetRegister(a), new IR.IdentifierReference(SymbolTable.GetRegister(b))));
                    break;

                case LuaOpCode.HKS_OPCODE_SETTABLE:
                case LuaOpCode.HKS_OPCODE_SETTABLE_S:
                    instructions.Add(new IR.Assignment(new IR.IdentifierReference(SymbolTable.GetRegister(a), Register(b)), RKIRHKS(fun, c, szero)));
                    break;

                case LuaOpCode.HKS_OPCODE_TAILCALL:
                case LuaOpCode.HKS_OPCODE_TAILCALL_I:
                case LuaOpCode.HKS_OPCODE_TAILCALL_I_R1:
                    args = new List <IR.Expression>();
                    for (int arg = (int)a + 1; arg < a + b; arg++)
                    {
                        args.Add(new IR.IdentifierReference(SymbolTable.GetRegister((uint)arg)));
                    }
                    var funCall = new IR.FunctionCall(new IR.IdentifierReference(SymbolTable.GetRegister(a)), args);
                    funCall.IsIndeterminantArgumentCount = (b == 0);
                    funCall.BeginArg = a + 1;
                    instructions.Add(new IR.Return(funCall));
                    break;

                case LuaOpCode.HKS_OPCODE_SETTABLE_S_BK:
                    instructions.Add(new IR.Assignment(new IR.IdentifierReference(SymbolTable.GetRegister(a), ToConstantIR(fun.Constants[(int)b])), RKIRHKS(fun, c, szero)));
                    break;

                case LuaOpCode.HKS_OPCODE_CALL_I:
                case LuaOpCode.HKS_OPCODE_CALL_I_R1:
                case LuaOpCode.HKS_OPCODE_CALL:
                    args = new List <IR.Expression>();
                    rets = new List <IR.IdentifierReference>();
                    for (int arg = (int)a + 1; arg < a + b; arg++)
                    {
                        args.Add(new IR.IdentifierReference(SymbolTable.GetRegister((uint)arg)));
                    }
                    for (int r = (int)a + 1; r < a + c; r++)
                    {
                        rets.Add(new IR.IdentifierReference(SymbolTable.GetRegister((uint)r - 1)));
                    }
                    if (c == 0)
                    {
                        rets.Add(new IR.IdentifierReference(SymbolTable.GetRegister((uint)a)));
                    }
                    funCall = new IR.FunctionCall(new IR.IdentifierReference(SymbolTable.GetRegister(a)), args);
                    funCall.IsIndeterminantArgumentCount = (b == 0);
                    funCall.IsIndeterminantReturnCount   = (c == 0);
                    funCall.BeginArg = a + 1;
                    assn             = new IR.Assignment(rets, funCall);
                    CheckLocal(assn, fun, pc);
                    instructions.Add(assn);
                    break;

                case LuaOpCode.HKS_OPCODE_RETURN:
                    args = new List <IR.Expression>();
                    if (b != 0)
                    {
                        for (int arg = (int)a; arg < a + b - 1; arg++)
                        {
                            args.Add(new IR.IdentifierReference(SymbolTable.GetRegister((uint)arg)));
                        }
                    }
                    var ret = new IR.Return(args);
                    if (b == 0)
                    {
                        ret.BeginRet = a;
                        ret.IsIndeterminantReturnCount = true;
                    }
                    instructions.Add(ret);
                    break;

                case LuaOpCode.HKS_OPCODE_FORLOOP:
                    instructions.Add(new IR.Assignment(new IR.IdentifierReference(SymbolTable.GetRegister(a)), new IR.BinOp(new IR.IdentifierReference(SymbolTable.GetRegister(a)),
                                                                                                                            new IR.IdentifierReference(SymbolTable.GetRegister(a + 2)), IR.BinOp.OperationType.OpAdd)));
                    var jmp = new IR.Jump(irfun.GetLabel((uint)(pc + 1 + sbx)), new IR.BinOp(new IR.IdentifierReference(SymbolTable.GetRegister(a)),
                                                                                             new IR.IdentifierReference(SymbolTable.GetRegister(a + 1)), IR.BinOp.OperationType.OpLoopCompare));
                    var pta = new IR.Assignment(SymbolTable.GetRegister(a + 3), Register((uint)a));
                    pta.PropogateAlways     = true;
                    jmp.PostTakenAssignment = pta;
                    instructions.Add(jmp);
                    break;

                case LuaOpCode.HKS_OPCODE_TFORLOOP:
                    args = new List <IR.Expression>();
                    rets = new List <IR.IdentifierReference>();
                    args.Add(new IR.IdentifierReference(SymbolTable.GetRegister((uint)a + 1)));
                    args.Add(new IR.IdentifierReference(SymbolTable.GetRegister((uint)a + 2)));
                    if (c == 0)
                    {
                        rets.Add(new IR.IdentifierReference(SymbolTable.GetRegister((uint)a + 3)));
                    }
                    else
                    {
                        for (int r = (int)a + 3; r <= a + c + 2; r++)
                        {
                            rets.Add(new IR.IdentifierReference(SymbolTable.GetRegister((uint)r)));
                        }
                    }
                    var fcall = new IR.FunctionCall(new IR.IdentifierReference(SymbolTable.GetRegister(a)), args);
                    fcall.IsIndeterminantReturnCount = (c == 0);
                    assn = new IR.Assignment(rets, fcall);
                    CheckLocal(assn, fun, pc);
                    instructions.Add(assn);
                    instructions.Add(new IR.Jump(irfun.GetLabel((uint)((i / 4) + 2)), new IR.BinOp(Register((uint)a + 3), new IR.Constant(IR.Constant.ConstantType.ConstNil), IR.BinOp.OperationType.OpEqual)));
                    instructions.Add(new IR.Assignment(SymbolTable.GetRegister(a + 2), new IR.IdentifierReference(SymbolTable.GetRegister(a + 3))));
                    break;

                case LuaOpCode.HKS_OPCODE_FORPREP:
                    // The VM technically does a subtract, but we don't actually emit it since it simplifies things to map better to the high level Lua
                    //instructions.Add(new IR.Assignment(new IR.IdentifierReference(SymbolTable.GetRegister(a)), new IR.BinOp(new IR.IdentifierReference(SymbolTable.GetRegister(a)),
                    //    new IR.IdentifierReference(SymbolTable.GetRegister(a + 2)), IR.BinOp.OperationType.OpSub)));
                    instructions.Add(new IR.Jump(irfun.GetLabel((uint)(pc + 1 + sbx))));
                    break;

                case LuaOpCode.HKS_OPCODE_SETLIST:
                    if (b == 0)
                    {
                        if (c == 1)
                        {
                            assn = new IR.Assignment(SymbolTable.GetRegister(a), Register(a + 1));
                            assn.VarargAssignmentReg   = a;
                            assn.IsIndeterminantVararg = true;
                            CheckLocal(assn, fun, pc);
                            instructions.Add(assn);
                        }
                    }
                    else
                    {
                        for (int j = 1; j <= b; j++)
                        {
                            assn = new IR.Assignment(new IR.IdentifierReference(SymbolTable.GetRegister(a), new IR.Constant((double)(c - 1) * 32 + j)),
                                                     new IR.IdentifierReference(SymbolTable.GetRegister(a + (uint)j)));
                            CheckLocal(assn, fun, pc);
                            instructions.Add(assn);
                        }
                    }
                    break;

                case LuaOpCode.HKS_OPCODE_CLOSURE:
                    instructions.Add(new IR.Assignment(SymbolTable.GetRegister(a), new IR.Closure(irfun.LookupClosure(bx))));
                    break;

                case LuaOpCode.HKS_OPCODE_GETFIELD:
                case LuaOpCode.HKS_OPCODE_GETFIELD_R1:
                    assn = new IR.Assignment(Register((uint)a), new IR.IdentifierReference(SymbolTable.GetRegister((uint)b), new IR.Constant(fun.Constants[(int)c].ToString())));
                    CheckLocal(assn, fun, pc);
                    instructions.Add(assn);
                    break;

                case LuaOpCode.HKS_OPCODE_DATA:
                    if (a != 0)
                    {
                        IR.Function closureFunc = null;
                        int         index       = pc;

                        while (index >= 0)
                        {
                            if (fun.Instructions[index].OpCode == LuaOpCode.HKS_OPCODE_CLOSURE)
                            {
                                closureFunc = irfun.LookupClosure(fun.Instructions[index].Bx);
                                break;
                            }
                            index--;
                        }

                        if (closureFunc == null)
                        {
                            continue;
                        }

                        if (a == 1)
                        {
                            closureFunc.UpvalueBindings.Add(SymbolTable.GetRegister(c));
                        }
                        else if (a == 2)
                        {
                            closureFunc.UpvalueBindings.Add(irfun.UpvalueBindings[(int)c]);
                        }
                    }
                    else
                    {
                        instructions.Add(new Data());
                    }
                    break;

                case LuaOpCode.HKS_OPCODE_SETFIELD:
                case LuaOpCode.HKS_OPCODE_SETFIELD_R1:
                    assn = new IR.Assignment(new IR.IdentifierReference(SymbolTable.GetRegister(a), new IR.Constant(fun.Constants[(int)b].ToString())), RKIRHKS(fun, c, szero));
                    CheckLocal(assn, fun, pc);
                    instructions.Add(assn);
                    break;

                case LuaOpCode.HKS_OPCODE_VARARG:
                    var vargs = new List <IR.IdentifierReference>();
                    for (int arg = (int)a; arg <= a + b - 1; arg++)
                    {
                        vargs.Add(new IR.IdentifierReference(SymbolTable.GetRegister((uint)arg)));
                    }
                    if (b != 0)
                    {
                        assn = new IR.Assignment(vargs, new IR.IdentifierReference(SymbolTable.GetVarargs()));
                    }
                    else
                    {
                        assn = new IR.Assignment(SymbolTable.GetRegister(a), new IR.IdentifierReference(SymbolTable.GetVarargs()));
                        assn.IsIndeterminantVararg = true;
                        assn.VarargAssignmentReg   = a;
                    }
                    CheckLocal(assn, fun, pc);
                    instructions.Add(assn);
                    irfun.IsVarargs = true;
                    break;

                case LuaOpCode.HKS_OPCODE_CLOSE:
                    // LUA source : close all variables in the stack up to (>=) R(A)
                    // Let's ignore this for now, doesn't print anything and don't know if it affects SSA
                    instructions.Add(new Close());
                    break;

                default:
                    Console.WriteLine($@"Missing op: {opcode} {a} {b} {c}");
                    instructions.Add(new IR.PlaceholderInstruction(($@"{opcode} {a} {b} {c}")));
                    break;
                }
                foreach (var inst in instructions)
                {
                    inst.OpLocation = i / 4;
                    irfun.AddInstruction(inst);
                }
            }
            irfun.ApplyLabels();

            // Simple post-ir and idiom recognition analysis passes
            irfun.ResolveVarargListAssignment(SymbolTable);
            irfun.MergeMultiBoolAssignment();
            irfun.EliminateRedundantAssignments();
            irfun.MergeConditionalJumps();
            irfun.MergeConditionalAssignments();
            //irfun.PeepholeOptimize();
            irfun.CheckControlFlowIntegrity();
            irfun.RemoveUnusedLabels();
            irfun.ClearDataInstructions();

            // Control flow graph construction and SSA conversion
            irfun.ConstructControlFlowGraph();
            irfun.ResolveIndeterminantArguments(SymbolTable);
            irfun.CompleteLua51Loops();

            // Upval resolution
            irfun.RegisterClosureUpvalues53(SymbolTable.GetAllRegistersInScope());

            irfun.ConvertToSSA(SymbolTable.GetAllRegistersInScope());

            // Data flow passes
            irfun.EliminateDeadAssignments(true);
            irfun.PerformExpressionPropogation();
            irfun.DetectListInitializers();

            // CFG passes
            irfun.StructureCompoundConditionals();
            irfun.DetectLoops();
            irfun.DetectLoopConditionals();
            irfun.DetectTwoWayConditionals();
            irfun.SimplifyIfElseFollowChain();

            irfun.EliminateDeadAssignments(true);
            irfun.PerformExpressionPropogation();
            irfun.VerifyLivenessNoInterference();

            // Convert out of SSA and rename variables
            irfun.DropSSADropSubscripts();
            irfun.AnnotateLocalDeclarations();

            irfun.RenameVariables();
            irfun.Parenthesize();
            irfun.AddEmptyLines();
            irfun.SearchInlineClosures();

            irfun.RemoveUnnecessaryReturns();

            // Convert to AST
            irfun.ConvertToAST(true);

            // Now generate IR for all the child closures
            for (int i = 0; i < fun.ChildFunctions.Count; i++)
            {
                GenerateIRHKS(irfun.LookupClosure((uint)i), fun.ChildFunctions[i]);
            }
            SymbolTable.EndScope();
        }
Esempio n. 6
0
 private static void CheckLocal(IR.Assignment a, ILuaFunction fun, int index)
 {
     a.LocalAssignments = fun.LocalsAt(index + 1);
 }
Esempio n. 7
0
        public void Convert(Function function, ILuaFunction luaFunc)
        {
            _symbolTable = function.SymbolTable;
            var luaFunction = (LuaJitFunction)luaFunc;

            // Loop over all instructions
            for (int pos = 0; pos < luaFunction.Instructions.Count; pos++)
            {
                var i = (LuaJitInstruction)luaFunction.Instructions[pos];

                List <IInstruction> instrs = new List <IInstruction>();
                switch (i.OpCode.Name)
                {
                // Comparison ops
                case "ISLT":
                    instrs.Add(new Jump(
                                   function.GetLabel((uint)(pos + 2)),
                                   new BinOp(RegisterReference(i.A), RegisterReference(i.CD), BinOperationType.OpLessThan)
                                   ));
                    break;

                case "ISGE":
                    instrs.Add(new Jump(
                                   function.GetLabel((uint)(pos + 2)),
                                   new BinOp(RegisterReference(i.A), RegisterReference(i.CD), BinOperationType.OpGreaterEqual)
                                   ));
                    break;

                case "ISLE":
                    instrs.Add(new Jump(
                                   function.GetLabel((uint)(pos + 2)),
                                   new BinOp(RegisterReference(i.A), RegisterReference(i.CD), BinOperationType.OpLessEqual)
                                   ));
                    break;

                case "ISGT":
                    instrs.Add(new Jump(
                                   function.GetLabel((uint)(pos + 2)),
                                   new BinOp(RegisterReference(i.A), RegisterReference(i.CD), BinOperationType.OpGreaterThan)
                                   ));
                    break;

                case "ISEQV":
                    instrs.Add(new Jump(
                                   function.GetLabel((uint)(pos + 2)),
                                   new BinOp(RegisterReference(i.A), RegisterReference(i.CD), BinOperationType.OpEqual)
                                   ));
                    break;

                case "ISNEV":
                    instrs.Add(new Jump(
                                   function.GetLabel((uint)(pos + 2)),
                                   new BinOp(RegisterReference(i.A), RegisterReference(i.CD), BinOperationType.OpNotEqual)
                                   ));
                    break;

                case "ISEQS":
                    instrs.Add(new Jump(
                                   function.GetLabel((uint)(pos + 2)),
                                   new BinOp(RegisterReference(i.A), ConvertLuaJitConstant(luaFunction.Constants[(int)i.CD], (int)i.CD), BinOperationType.OpEqual)
                                   ));
                    break;

                case "ISNES":
                    instrs.Add(new Jump(
                                   function.GetLabel((uint)(pos + 2)),
                                   new BinOp(RegisterReference(i.A), ConvertLuaJitConstant(luaFunction.Constants[(int)i.CD], (int)i.CD), BinOperationType.OpNotEqual)
                                   ));
                    break;

                case "ISEQN":
                    instrs.Add(new Jump(
                                   function.GetLabel((uint)(pos + 2)),
                                   new BinOp(RegisterReference(i.A), ConvertLuaJitConstant(GetNumConstant(luaFunction, (ulong)i.CD), -1), BinOperationType.OpEqual)
                                   ));
                    break;

                case "ISNEN":
                    instrs.Add(new Jump(
                                   function.GetLabel((uint)(pos + 2)),
                                   new BinOp(RegisterReference(i.A), ConvertLuaJitConstant(GetNumConstant(luaFunction, (ulong)i.CD), -1), BinOperationType.OpNotEqual)
                                   ));
                    break;

                case "ISEQP":
                    instrs.Add(new Jump(
                                   function.GetLabel((uint)(pos + 2)),
                                   new BinOp(RegisterReference(i.A), GetPrimitiveConstant(i.CD), BinOperationType.OpEqual)
                                   ));
                    break;

                case "ISNEP":
                    instrs.Add(new Jump(
                                   function.GetLabel((uint)(pos + 2)),
                                   new BinOp(RegisterReference(i.A), GetPrimitiveConstant(i.CD), BinOperationType.OpNotEqual)
                                   ));
                    break;

                // Unary test and copy ops
                case "ISTC":
                    instrs.Add(new Jump(
                                   function.GetLabel((uint)(pos + 2)),
                                   new UnaryOp(RegisterReference((uint)i.CD), UnOperationType.OpNot)));
                    instrs.Add(new Assignment(_symbolTable.GetRegister(i.A), new IdentifierReference(_symbolTable.GetRegister((uint)i.CD))));
                    break;

                case "ISFC":
                    instrs.Add(new Jump(
                                   function.GetLabel((uint)(pos + 2)),
                                   RegisterReference((uint)i.CD)));
                    instrs.Add(new Assignment(_symbolTable.GetRegister(i.A), new IdentifierReference(_symbolTable.GetRegister((uint)i.CD))));
                    break;

                case "IST":
                    instrs.Add(new Jump(function.GetLabel((uint)(pos + 2)),
                                        RegisterReference(i.CD)));
                    break;

                case "ISF":
                    instrs.Add(new Jump(function.GetLabel((uint)(pos + 2)),
                                        new UnaryOp(RegisterReference(i.CD), UnOperationType.OpNot)));
                    break;

                // Unary ops
                case "MOV":
                    instrs.Add(new Assignment(
                                   _symbolTable.GetRegister(i.A),
                                   RegisterReference(i.CD)));
                    break;

                case "NOT":
                    instrs.Add(new Assignment(
                                   _symbolTable.GetRegister(i.A),
                                   new UnaryOp(new IdentifierReference(_symbolTable.GetRegister((uint)i.CD)), UnOperationType.OpNot)
                                   ));
                    break;

                case "UNM":
                    instrs.Add(new Assignment(
                                   _symbolTable.GetRegister(i.A),
                                   new UnaryOp(new IdentifierReference(_symbolTable.GetRegister((uint)i.CD)), UnOperationType.OpNegate)
                                   ));
                    break;

                case "LEN":
                    instrs.Add(new Assignment(
                                   _symbolTable.GetRegister(i.A),
                                   new UnaryOp(new IdentifierReference(_symbolTable.GetRegister((uint)i.CD)), UnOperationType.OpLength)
                                   ));
                    break;

                // Binary ops
                case "ADDVN":
                    instrs.Add(new Assignment(
                                   _symbolTable.GetRegister(i.A),
                                   new BinOp(RegisterReference(i.B), ConvertLuaJitConstant(GetNumConstant(luaFunction, (ulong)i.CD), -1), BinOperationType.OpAdd)));
                    break;

                case "SUBVN":
                    instrs.Add(new Assignment(
                                   _symbolTable.GetRegister(i.A),
                                   new BinOp(RegisterReference(i.B), ConvertLuaJitConstant(GetNumConstant(luaFunction, (ulong)i.CD), -1), BinOperationType.OpSub)));
                    break;

                case "MULVN":
                    instrs.Add(new Assignment(
                                   _symbolTable.GetRegister(i.A),
                                   new BinOp(RegisterReference(i.B), ConvertLuaJitConstant(GetNumConstant(luaFunction, (ulong)i.CD), -1), BinOperationType.OpMul)));
                    break;

                case "DIVVN":
                    instrs.Add(new Assignment(
                                   _symbolTable.GetRegister(i.A),
                                   new BinOp(RegisterReference(i.B), ConvertLuaJitConstant(GetNumConstant(luaFunction, (ulong)i.CD), -1), BinOperationType.OpDiv)));
                    break;

                case "MODVN":
                    instrs.Add(new Assignment(
                                   _symbolTable.GetRegister(i.A),
                                   new BinOp(RegisterReference(i.B), ConvertLuaJitConstant(GetNumConstant(luaFunction, (ulong)i.CD), -1), BinOperationType.OpMod)));
                    break;

                case "ADDNV":
                    instrs.Add(new Assignment(
                                   _symbolTable.GetRegister(i.A),
                                   new BinOp(ConvertLuaJitConstant(GetNumConstant(luaFunction, (ulong)i.CD), -1), RegisterReference(i.B), BinOperationType.OpAdd)));
                    break;

                case "SUBNV":
                    instrs.Add(new Assignment(
                                   _symbolTable.GetRegister(i.A),
                                   new BinOp(ConvertLuaJitConstant(GetNumConstant(luaFunction, (ulong)i.CD), -1), RegisterReference(i.B), BinOperationType.OpSub)));
                    break;

                case "MULNV":
                    instrs.Add(new Assignment(
                                   _symbolTable.GetRegister(i.A),
                                   new BinOp(ConvertLuaJitConstant(GetNumConstant(luaFunction, (ulong)i.CD), -1), RegisterReference(i.B), BinOperationType.OpMul)));
                    break;

                case "DIVNV":
                    instrs.Add(new Assignment(
                                   _symbolTable.GetRegister(i.A),
                                   new BinOp(ConvertLuaJitConstant(GetNumConstant(luaFunction, (ulong)i.CD), -1), RegisterReference(i.B), BinOperationType.OpDiv)));
                    break;

                case "MODNV":
                    instrs.Add(new Assignment(
                                   _symbolTable.GetRegister(i.A),
                                   new BinOp(ConvertLuaJitConstant(GetNumConstant(luaFunction, (ulong)i.CD), -1), RegisterReference(i.B), BinOperationType.OpMod)));
                    break;

                case "ADDVV":
                    instrs.Add(new Assignment(
                                   _symbolTable.GetRegister(i.A),
                                   new BinOp(RegisterReference(i.B), RegisterReference(i.CD), BinOperationType.OpAdd)));
                    break;

                case "SUBVV":
                    instrs.Add(new Assignment(
                                   _symbolTable.GetRegister(i.A),
                                   new BinOp(RegisterReference(i.B), RegisterReference(i.CD), BinOperationType.OpSub)));
                    break;

                case "MULVV":
                    instrs.Add(new Assignment(
                                   _symbolTable.GetRegister(i.A),
                                   new BinOp(RegisterReference(i.B), RegisterReference(i.CD), BinOperationType.OpMul)));
                    break;

                case "DIVVV":
                    instrs.Add(new Assignment(
                                   _symbolTable.GetRegister(i.A),
                                   new BinOp(RegisterReference(i.B), RegisterReference(i.CD), BinOperationType.OpDiv)));
                    break;

                case "MODVV":
                    instrs.Add(new Assignment(
                                   _symbolTable.GetRegister(i.A),
                                   new BinOp(RegisterReference(i.B), RegisterReference(i.CD), BinOperationType.OpMod)));
                    break;

                case "POW":
                    instrs.Add(new Assignment(
                                   _symbolTable.GetRegister(i.A),
                                   new BinOp(RegisterReference(i.B), RegisterReference(i.CD), BinOperationType.OpPow)));
                    break;

                case "CAT":
                    var args = new List <IExpression>();
                    for (int arg = (int)i.B; arg <= i.CD; arg++)
                    {
                        args.Add(new IdentifierReference(_symbolTable.GetRegister((uint)arg)));
                    }
                    instrs.Add(new Assignment(
                                   _symbolTable.GetRegister(i.A),
                                   new Concat(args)));
                    break;

                // Constant ops
                case "KSTR":
                    instrs.Add(new Assignment(
                                   _symbolTable.GetRegister(i.A),
                                   ConvertLuaJitConstant(luaFunction.Constants[(int)i.CD], (int)i.CD)));
                    break;

                case "KHASH":
                    instrs.Add(new Assignment(
                                   _symbolTable.GetRegister(i.A),
                                   ConvertLuaJitConstant(luaFunction.Constants[(int)i.CD], (int)i.CD)));
                    break;

                case "KSHORT":
                    instrs.Add(new Assignment(
                                   _symbolTable.GetRegister(i.A),
                                   new Constant((int)i.CD, -1)));
                    break;

                case "KNUM":
                    instrs.Add(new Assignment(
                                   _symbolTable.GetRegister(i.A),
                                   ConvertLuaJitConstant(GetNumConstant(luaFunction, (ulong)i.CD), -1)));
                    break;

                case "KPRI":
                    instrs.Add(new Assignment(
                                   _symbolTable.GetRegister(i.A),
                                   GetPrimitiveConstant(i.CD)
                                   ));
                    break;

                case "KNIL":
                    var nlist = new List <IdentifierReference>();
                    for (int arg = (int)i.A; arg <= i.CD; arg++)
                    {
                        nlist.Add(new IdentifierReference(_symbolTable.GetRegister((uint)arg)));
                    }
                    instrs.Add(new Assignment(nlist, new Constant(ValueType.Nil, -1)));
                    break;

                // Upvalue and function ops
                case "UGET":
                    Identifier up = function.UpvalueBindings[(int)i.CD];
                    up.IsClosureBound = true;
                    instrs.Add(new Assignment(
                                   _symbolTable.GetRegister(i.A),
                                   new IdentifierReference(up)));
                    break;

                case "USETV":
                    instrs.Add(new Assignment(
                                   _symbolTable.GetUpValue(i.A, function.UpvalueBindings[(int)i.A].Name),
                                   new IdentifierReference(_symbolTable.GetRegister((uint)i.CD))));
                    break;

                case "USETS":
                    instrs.Add(new Assignment(
                                   _symbolTable.GetUpValue(i.A, function.UpvalueBindings[(int)i.A].Name),
                                   ConvertLuaJitConstant(luaFunction.Constants[(int)i.CD], (int)i.CD)));
                    break;

                case "USETN":
                    instrs.Add(new Assignment(
                                   _symbolTable.GetUpValue(i.A, function.UpvalueBindings[(int)i.A].Name),
                                   ConvertLuaJitConstant(GetNumConstant(luaFunction, (ulong)i.CD), -1)));
                    break;

                case "USETP":
                    instrs.Add(new Assignment(
                                   _symbolTable.GetUpValue(i.A, function.UpvalueBindings[(int)i.A].Name),
                                   GetPrimitiveConstant(i.CD)));
                    break;

                case "UCLO":
                    // This doesn't seem to do anything
                    instrs.Add(new Data(i));
                    break;

                case "FNEW":
                    instrs.Add(new Assignment(
                                   _symbolTable.GetRegister(i.A),
                                   ConvertLuaJitConstant(luaFunction.Constants[(int)i.CD], (int)i.CD)
                                   ));
                    break;

                // Table ops
                case "TNEW":
                    instrs.Add(new Assignment(
                                   _symbolTable.GetRegister(i.A),
                                   new InitializerList()
                                   ));
                    break;

                case "TDUP":
                    instrs.Add(new Assignment(
                                   _symbolTable.GetRegister(i.A),
                                   ConvertLuaJitConstant(luaFunction.Constants[(int)i.CD], (int)i.CD)
                                   ));
                    break;

                case "GGET":
                    instrs.Add(new Assignment(
                                   _symbolTable.GetRegister(i.A),
                                   new IdentifierReference(_symbolTable.GetGlobal(luaFunction.Constants[(int)i.CD].ToString(), (int)i.A))
                                   ));
                    break;

                case "GSET":
                    instrs.Add(new Assignment(
                                   _symbolTable.GetGlobal(luaFunction.Constants[(int)i.CD].ToString(), (int)i.CD),
                                   new IdentifierReference(_symbolTable.GetRegister(i.A))));
                    break;

                case "TGETV":
                    instrs.Add(new Assignment(
                                   RegisterReference(i.A),
                                   new IdentifierReference(_symbolTable.GetRegister(i.B), RegisterReference(i.CD))
                                   ));
                    break;

                case "TGETS":
                    instrs.Add(new Assignment(
                                   RegisterReference(i.A),
                                   new IdentifierReference(_symbolTable.GetRegister(i.B), ConvertLuaJitConstant(luaFunction.Constants[(int)i.CD], (int)i.CD))
                                   ));
                    break;

                case "TGETB":
                    instrs.Add(new Assignment(
                                   RegisterReference(i.A),
                                   new IdentifierReference(_symbolTable.GetRegister(i.B), new Constant((int)i.CD, -1))
                                   ));
                    break;

                case "TSETV":
                    instrs.Add(new Assignment(
                                   new IdentifierReference(_symbolTable.GetRegister(i.B), RegisterReference(i.CD)),
                                   new IdentifierReference(_symbolTable.GetRegister(i.A))));
                    break;

                case "TSETS":
                    instrs.Add(new Assignment(
                                   new IdentifierReference(_symbolTable.GetRegister(i.B), ConvertLuaJitConstant(luaFunction.Constants[(int)i.CD], -1)),
                                   new IdentifierReference(_symbolTable.GetRegister(i.A))));
                    break;

                case "TSETB":
                    instrs.Add(new Assignment(
                                   new IdentifierReference(_symbolTable.GetRegister(i.B), new Constant(i.CD, -1)),
                                   new IdentifierReference(_symbolTable.GetRegister(i.A))));
                    break;

                case "TSETM":
                    instrs.Add(new SetTableMultres(_symbolTable.GetRegister(i.A - 1), (int)i.CD + 1));
                    break;

                // Calls and vararg handling. T = tail call
                case "CALLM":
                    args = new List <IExpression>();
                    var rets = new List <IdentifierReference>();
                    // Create references for a .. a + b - 2
                    if (i.B >= 2)
                    {
                        for (uint j = i.A; j <= i.A + i.B - 2; j++)
                        {
                            rets.Add(new IdentifierReference(_symbolTable.GetRegister(j)));
                        }
                    }
                    // Get references for a + 2 .. a + c
                    for (uint j = i.A + 2; j <= i.A + i.CD + 1; j++)
                    {
                        args.Add(new IdentifierReference(_symbolTable.GetRegister(j)));
                    }

                    var funcCall = new FunctionCall(new IdentifierReference(_symbolTable.GetRegister(i.A)), args);
                    funcCall.IsIndeterminateArgumentCount = (i.B == 0);
                    instrs.Add(new Assignment(rets, funcCall));
                    break;

                case "CALL":
                    args = new List <IExpression>();
                    rets = new List <IdentifierReference>();
                    // Create references for a .. a + b - 2
                    if (i.B >= 2)
                    {
                        for (uint j = i.A; j <= i.A + i.B - 2; j++)
                        {
                            rets.Add(new IdentifierReference(_symbolTable.GetRegister(j)));
                        }
                    }
                    // Get references for a + 2 .. a + c
                    for (uint j = i.A + 2; j <= i.A + i.CD; j++)
                    {
                        args.Add(new IdentifierReference(_symbolTable.GetRegister(j)));
                    }

                    funcCall = new FunctionCall(new IdentifierReference(_symbolTable.GetRegister(i.A)), args);
                    funcCall.IsIndeterminateArgumentCount = (i.B == 0);
                    instrs.Add(new Assignment(rets, funcCall));
                    break;

                case "CALLMT":
                    args = new List <IExpression>();
                    for (uint j = i.A + 2; j <= i.A + i.CD; j++)
                    {
                        args.Add(new IdentifierReference(_symbolTable.GetRegister(j)));
                    }

                    funcCall = new FunctionCall(new IdentifierReference(_symbolTable.GetRegister(i.A)), args);
                    funcCall.IsIndeterminateArgumentCount = (i.B == 0);
                    instrs.Add(new Return(funcCall));
                    break;

                case "CALLT":
                    args = new List <IExpression>();
                    for (uint j = i.A + 2; j <= i.A + i.CD; j++)
                    {
                        args.Add(new IdentifierReference(_symbolTable.GetRegister(j)));
                    }

                    funcCall = new FunctionCall(new IdentifierReference(_symbolTable.GetRegister(i.A)), args);
                    instrs.Add(new Return(funcCall));
                    break;

                case "ITERC":
                case "ITERN":
                    args = new List <IExpression>();
                    rets = new List <IdentifierReference>();
                    // Create references for a .. a + b - 2
                    if (i.B >= 2)
                    {
                        for (uint j = i.A; j <= i.A + i.B - 2; j++)
                        {
                            rets.Add(new IdentifierReference(_symbolTable.GetRegister(j)));
                        }
                    }
                    // Get references for a + 2 .. a + c
                    for (uint j = i.A - 2; j <= i.A - 1; j++)
                    {
                        args.Add(new IdentifierReference(_symbolTable.GetRegister(j)));
                    }

                    funcCall = new FunctionCall(new IdentifierReference(_symbolTable.GetRegister(i.A - 3)), args);
                    funcCall.IsIndeterminateArgumentCount = (i.B == 0);
                    instrs.Add(new Assignment(rets, funcCall));
                    instrs.Add(new Jump(function.GetLabel((uint)(pos + 2)), new BinOp(RegisterReference(i.A), new Constant(ValueType.Nil, -1), BinOperationType.OpEqual)));
                    instrs.Add(new Assignment(_symbolTable.GetRegister(i.A - 1), new IdentifierReference(_symbolTable.GetRegister(i.A))));
                    break;

                case "VARG":
                    rets = new List <IdentifierReference>();

                    for (uint j = i.A; j < i.A + i.B - 1; j++)
                    {
                        rets.Add(new IdentifierReference(_symbolTable.GetRegister(j)));
                    }

                    instrs.Add(new Assignment(
                                   rets,
                                   new IdentifierReference(_symbolTable.GetVarargs())));
                    break;

                case "ISNEXT":
                    instrs.Add(new Jump(function.GetLabel((uint)((uint)pos + i.CD + 1))));
                    break;

                // Returns
                case "RETM":
                    args = new List <IExpression>();
                    for (uint j = i.A; j < i.A + i.CD; j++)
                    {
                        args.Add(new IdentifierReference(_symbolTable.GetRegister(j)));
                    }
                    var rtrn = new Return(args)
                    {
                        IsIndeterminateReturnCount = i.B == 0
                    };
                    instrs.Add(rtrn);
                    break;

                case "RET":
                    args = new List <IExpression>();
                    for (uint j = i.A; j < i.A + i.CD - 1; j++)
                    {
                        args.Add(new IdentifierReference(_symbolTable.GetRegister(j)));
                    }
                    instrs.Add(new Return(args));
                    break;

                case "RET0":
                    instrs.Add(new Return());
                    break;

                case "RET1":
                    instrs.Add(new Return(new IdentifierReference(_symbolTable.GetRegister(i.A))));
                    break;

                // Loops and branches. I/J = interp/JIT, I/C/L = init/call/loop
                case "FORI":
                    instrs.Add(new Jump(function.GetLabel((uint)(pos + i.CD))));
                    break;

                case "FORL":
                    instrs.Add(new Assignment(new IdentifierReference(_symbolTable.GetRegister(i.A)), new BinOp(new IdentifierReference(_symbolTable.GetRegister(i.A)),
                                                                                                                new IdentifierReference(_symbolTable.GetRegister(i.A + 2)), BinOperationType.OpAdd)));
                    var jmp = new Jump(function.GetLabel((uint)(pos + 1 + i.CD)), new BinOp(new IdentifierReference(_symbolTable.GetRegister(i.A)),
                                                                                            new IdentifierReference(_symbolTable.GetRegister(i.A + 1)), BinOperationType.OpLoopCompare));
                    var pta = new Assignment(_symbolTable.GetRegister(i.A + 3), RegisterReference(i.A));
                    pta.PropagateAlways     = true;
                    jmp.PostTakenAssignment = pta;
                    instrs.Add(jmp);
                    break;

                case "LOOP":
                case "ITERL":
                    instrs.Add(new Jump(function.GetLabel((uint)(pos + i.CD + 1))));
                    break;

                case "JMP":
                    instrs.Add(new Jump(function.GetLabel((uint)((uint)pos + i.CD + 1))));
                    break;

                default:
                    Console.WriteLine($@"Missing op: {i.OpCode.Name} {i.A} {i.B} {i.CD}");
                    instrs.Add(new PlaceholderInstruction($@"{i.OpCode.Name} {i.A} {i.B} {i.CD}"));
                    break;
                }
                instrs.ForEach(instr =>
                {
                    instr.OpLocation = pos;
                    function.Instructions.Add(instr);
                });
            }
        }
Esempio n. 8
0
 private void Parse()
 {
     Header       = ReadHeader();
     Constants    = ReadConstants();
     MainFunction = ReadFunctions();
 }
Esempio n. 9
0
        public void Convert(Function function, ILuaFunction luaFunc)
        {
            _symbolTable = function.SymbolTable;
            var luaFunction = (HavokLuaFunction)luaFunc;

            FunctionDebugInfo debugFunc = null;

            if (luaFunction.LuaFile is HavokLuaFileT7 ht7 && ht7.DebugFile != null)
            {
                var debugInfo = ht7.DebugFile.DebugInfo;
                debugFunc = debugInfo.Find(d => d.Id == function.Id);
                function.FunctionDebugInfo = debugFunc;
                function.ArgumentNames     = debugFunc.VariableNames.Where(v => v.Start == 0).Select(l => new Local()
                {
                    Name = l.Name, End = l.End, Start = l.Start
                }).ToList();
            }

            // Loop over all instructions
            for (int pos = 0; pos < luaFunction.Instructions.Count; pos++)
            {
                var i = (HavokInstruction)luaFunction.Instructions[pos];

                List <IInstruction> instrs = new List <IInstruction>();
                switch (i.HavokOpCode)
                {
                case LuaHavokOpCode.HKS_OPCODE_MOVE:
                    instrs.Add(new Assignment(
                                   _symbolTable.GetRegister(i.A),
                                   RegisterReference(i.B)
                                   ));
                    break;

                case LuaHavokOpCode.HKS_OPCODE_LOADK:
                    instrs.Add(new Assignment(
                                   _symbolTable.GetRegister(i.A),
                                   ConvertLuaConstant(luaFunction.Constants[(int)i.Bx], (int)i.Bx)
                                   ));
                    break;

                case LuaHavokOpCode.HKS_OPCODE_LOADBOOL:
                    var assn = new Assignment(_symbolTable.GetRegister(i.A), new Constant(i.B == 1, -1));
                    instrs.Add(assn);
                    if (i.C > 0)
                    {
                        instrs.Add(new Jump(function.GetLabel((uint)(pos + 2))));
                    }
                    break;

                case LuaHavokOpCode.HKS_OPCODE_LOADNIL:
                    var nlist = new List <IdentifierReference>();
                    for (int arg = (int)i.A; arg <= i.B; arg++)
                    {
                        nlist.Add(new IdentifierReference(_symbolTable.GetRegister((uint)arg)));
                    }
                    assn = new Assignment(nlist, new Constant(ValueType.Nil, -1));
                    instrs.Add(assn);
                    break;

                case LuaHavokOpCode.HKS_OPCODE_GETUPVAL:
                    Identifier up = function.UpvalueBindings[(int)i.B];
                    up.IsClosureBound = true;
                    instrs.Add(new Assignment(
                                   _symbolTable.GetRegister(i.A),
                                   new IdentifierReference(up)));
                    break;

                case LuaHavokOpCode.HKS_OPCODE_SETUPVAL:
                case LuaHavokOpCode.HKS_OPCODE_SETUPVAL_R1:
                    up = _symbolTable.GetUpValue(i.B, function.UpvalueBindings[(int)i.B].Name);
                    if (luaFunction.Upvalues.Any() && !up.UpValueResolved)
                    {
                        up.Name            = luaFunction.Upvalues[(int)i.B].Name;
                        up.UpValueResolved = true;
                    }
                    instrs.Add(new Assignment(up, new IdentifierReference(_symbolTable.GetRegister(i.A))));
                    break;

                case LuaHavokOpCode.HKS_OPCODE_GETGLOBAL_MEM:
                case LuaHavokOpCode.HKS_OPCODE_GETGLOBAL:
                    instrs.Add(new Assignment(
                                   _symbolTable.GetRegister(i.A),
                                   new IdentifierReference(_symbolTable.GetGlobal(luaFunction.Constants[(int)i.Bx].ToString(), (int)i.Bx))
                                   ));
                    break;

                case LuaHavokOpCode.HKS_OPCODE_SETGLOBAL:
                    instrs.Add(new Assignment(
                                   _symbolTable.GetGlobal(luaFunction.Constants[(int)i.Bx].ToString(), (int)i.Bx),
                                   new IdentifierReference(_symbolTable.GetRegister(i.A))));
                    break;

                case LuaHavokOpCode.HKS_OPCODE_GETTABLE_S:
                case LuaHavokOpCode.HKS_OPCODE_GETTABLE:
                    instrs.Add(new Assignment(
                                   _symbolTable.GetRegister(i.A),
                                   new IdentifierReference(_symbolTable.GetRegister(i.B), GetConstantBitFix(luaFunction, i.C, i.ExtraCBit))
                                   ));
                    break;

                case LuaHavokOpCode.HKS_OPCODE_NEWTABLE:
                    instrs.Add(new Assignment(
                                   _symbolTable.GetRegister(i.A),
                                   new InitializerList()
                                   ));
                    break;

                case LuaHavokOpCode.HKS_OPCODE_SELF:
                    var op = new Assignment(_symbolTable.GetRegister(i.A + 1), new IdentifierReference(_symbolTable.GetRegister(i.B)));
                    op.IsSelfAssignment = true;
                    instrs.Add(op);
                    op = new Assignment(_symbolTable.GetRegister(i.A), new IdentifierReference(_symbolTable.GetRegister(i.B), GetConstantBitFix(luaFunction, i.C, i.ExtraCBit)));
                    op.IsSelfAssignment = true;
                    instrs.Add(op);
                    break;

                case LuaHavokOpCode.HKS_OPCODE_ADD:
                    instrs.Add(new Assignment(
                                   _symbolTable.GetRegister(i.A),
                                   new BinOp(RegisterReference(i.B), GetConstantBitFix(luaFunction, i.C, i.ExtraCBit), BinOperationType.OpAdd)
                                   ));
                    break;

                case LuaHavokOpCode.HKS_OPCODE_ADD_BK:
                    instrs.Add(new Assignment(
                                   _symbolTable.GetRegister(i.A),
                                   new BinOp(ConvertLuaConstant(luaFunction.Constants[(int)i.B], (int)i.B), RegisterReference(i.C), BinOperationType.OpAdd)
                                   ));
                    break;

                case LuaHavokOpCode.HKS_OPCODE_SUB:
                    instrs.Add(new Assignment(
                                   _symbolTable.GetRegister(i.A),
                                   new BinOp(RegisterReference(i.B), GetConstantBitFix(luaFunction, i.C, i.ExtraCBit), BinOperationType.OpSub)
                                   ));
                    break;

                case LuaHavokOpCode.HKS_OPCODE_SUB_BK:
                    instrs.Add(new Assignment(
                                   _symbolTable.GetRegister(i.A),
                                   new BinOp(ConvertLuaConstant(luaFunction.Constants[(int)i.B], (int)i.B), RegisterReference(i.C), BinOperationType.OpSub)
                                   ));
                    break;

                case LuaHavokOpCode.HKS_OPCODE_MUL:
                    instrs.Add(new Assignment(
                                   _symbolTable.GetRegister(i.A),
                                   new BinOp(RegisterReference(i.B), GetConstantBitFix(luaFunction, i.C, i.ExtraCBit), BinOperationType.OpMul)
                                   ));
                    break;

                case LuaHavokOpCode.HKS_OPCODE_MUL_BK:
                    instrs.Add(new Assignment(
                                   _symbolTable.GetRegister(i.A),
                                   new BinOp(ConvertLuaConstant(luaFunction.Constants[(int)i.B], (int)i.B), RegisterReference(i.C), BinOperationType.OpMul)
                                   ));
                    break;

                case LuaHavokOpCode.HKS_OPCODE_DIV:
                    instrs.Add(new Assignment(
                                   _symbolTable.GetRegister(i.A),
                                   new BinOp(RegisterReference(i.B), GetConstantBitFix(luaFunction, i.C, i.ExtraCBit), BinOperationType.OpDiv)
                                   ));
                    break;

                case LuaHavokOpCode.HKS_OPCODE_DIV_BK:
                    instrs.Add(new Assignment(
                                   _symbolTable.GetRegister(i.A),
                                   new BinOp(ConvertLuaConstant(luaFunction.Constants[(int)i.B], (int)i.B), RegisterReference(i.C), BinOperationType.OpDiv)
                                   ));
                    break;

                case LuaHavokOpCode.HKS_OPCODE_MOD:
                    instrs.Add(new Assignment(
                                   _symbolTable.GetRegister(i.A),
                                   new BinOp(RegisterReference(i.B), GetConstantBitFix(luaFunction, i.C, i.ExtraCBit), BinOperationType.OpMod)
                                   ));
                    break;

                case LuaHavokOpCode.HKS_OPCODE_MOD_BK:
                    instrs.Add(new Assignment(
                                   _symbolTable.GetRegister(i.A),
                                   new BinOp(ConvertLuaConstant(luaFunction.Constants[(int)i.B], (int)i.B), RegisterReference(i.C), BinOperationType.OpMod)
                                   ));
                    break;

                case LuaHavokOpCode.HKS_OPCODE_POW:
                    instrs.Add(new Assignment(
                                   _symbolTable.GetRegister(i.A),
                                   new BinOp(RegisterReference(i.B), GetConstantBitFix(luaFunction, i.C, i.ExtraCBit), BinOperationType.OpPow)
                                   ));
                    break;

                case LuaHavokOpCode.HKS_OPCODE_POW_BK:
                    instrs.Add(new Assignment(
                                   _symbolTable.GetRegister(i.A),
                                   new BinOp(ConvertLuaConstant(luaFunction.Constants[(int)i.B], (int)i.B), RegisterReference(i.C), BinOperationType.OpPow)
                                   ));
                    break;

                case LuaHavokOpCode.HKS_OPCODE_UNM:
                    instrs.Add(new Assignment(
                                   _symbolTable.GetRegister(i.A),
                                   new UnaryOp(new IdentifierReference(_symbolTable.GetRegister(i.B)), UnOperationType.OpNegate)
                                   ));
                    break;

                case LuaHavokOpCode.HKS_OPCODE_NOT:
                case LuaHavokOpCode.HKS_OPCODE_NOT_R1:
                    instrs.Add(new Assignment(
                                   _symbolTable.GetRegister(i.A),
                                   new UnaryOp(new IdentifierReference(_symbolTable.GetRegister(i.B)), UnOperationType.OpNot)
                                   ));
                    break;

                case LuaHavokOpCode.HKS_OPCODE_LEN:
                    instrs.Add(new Assignment(
                                   _symbolTable.GetRegister(i.A),
                                   new UnaryOp(new IdentifierReference(_symbolTable.GetRegister(i.B)), UnOperationType.OpLength)
                                   ));
                    break;

                case LuaHavokOpCode.HKS_OPCODE_SHIFT_LEFT:
                    instrs.Add(new Assignment(
                                   _symbolTable.GetRegister(i.A),
                                   new BinOp(RegisterReference(i.B), GetConstantBitFix(luaFunction, i.C, i.ExtraCBit), BinOperationType.OpShiftLeft)
                                   ));
                    break;

                case LuaHavokOpCode.HKS_OPCODE_SHIFT_LEFT_BK:
                    instrs.Add(new Assignment(
                                   _symbolTable.GetRegister(i.A),
                                   new BinOp(ConvertLuaConstant(luaFunction.Constants[(int)i.B], (int)i.B), RegisterReference(i.C), BinOperationType.OpShiftLeft)
                                   ));
                    break;

                case LuaHavokOpCode.HKS_OPCODE_SHIFT_RIGHT:
                    instrs.Add(new Assignment(
                                   _symbolTable.GetRegister(i.A),
                                   new BinOp(RegisterReference(i.B), GetConstantBitFix(luaFunction, i.C, i.ExtraCBit), BinOperationType.OpShiftRight)
                                   ));
                    break;

                case LuaHavokOpCode.HKS_OPCODE_SHIFT_RIGHT_BK:
                    instrs.Add(new Assignment(
                                   _symbolTable.GetRegister(i.A),
                                   new BinOp(ConvertLuaConstant(luaFunction.Constants[(int)i.B], (int)i.B), RegisterReference(i.C), BinOperationType.OpShiftRight)
                                   ));
                    break;

                case LuaHavokOpCode.HKS_OPCODE_BITWISE_AND:
                    instrs.Add(new Assignment(
                                   _symbolTable.GetRegister(i.A),
                                   new BinOp(RegisterReference(i.B), GetConstantBitFix(luaFunction, i.C, i.ExtraCBit), BinOperationType.OpBAnd)
                                   ));
                    break;

                case LuaHavokOpCode.HKS_OPCODE_BITWISE_AND_BK:
                    instrs.Add(new Assignment(
                                   _symbolTable.GetRegister(i.A),
                                   new BinOp(ConvertLuaConstant(luaFunction.Constants[(int)i.B], (int)i.B), RegisterReference(i.C), BinOperationType.OpBAnd)
                                   ));
                    break;

                case LuaHavokOpCode.HKS_OPCODE_BITWISE_OR:
                    instrs.Add(new Assignment(
                                   _symbolTable.GetRegister(i.A),
                                   new BinOp(RegisterReference(i.B), GetConstantBitFix(luaFunction, i.C, i.ExtraCBit), BinOperationType.OpBOr)
                                   ));
                    break;

                case LuaHavokOpCode.HKS_OPCODE_BITWISE_OR_BK:
                    instrs.Add(new Assignment(
                                   _symbolTable.GetRegister(i.A),
                                   new BinOp(ConvertLuaConstant(luaFunction.Constants[(int)i.B], (int)i.B), RegisterReference(i.C), BinOperationType.OpBOr)
                                   ));
                    break;

                case LuaHavokOpCode.HKS_OPCODE_CONCAT:
                    var args = new List <IExpression>();
                    for (int arg = (int)i.B; arg <= i.C; arg++)
                    {
                        args.Add(new IdentifierReference(_symbolTable.GetRegister((uint)arg)));
                    }
                    instrs.Add(new Assignment(
                                   _symbolTable.GetRegister(i.A),
                                   new Concat(args)
                                   ));
                    break;

                case LuaHavokOpCode.HKS_OPCODE_JMP:
                    instrs.Add(new Jump(function.GetLabel((uint)(pos + 1 + i.SBx))));
                    break;

                case LuaHavokOpCode.HKS_OPCODE_EQ:
                    var operation = BinOperationType.OpEqual;
                    if (i.A == 1)
                    {
                        operation = BinOperationType.OpNotEqual;
                    }
                    instrs.Add(new Jump(function.GetLabel((uint)(pos + 2)), new BinOp(RegisterReference(i.B), GetConstantBitFix(luaFunction, i.C, i.ExtraCBit), operation)));
                    break;

                case LuaHavokOpCode.HKS_OPCODE_EQ_BK:
                    operation = BinOperationType.OpEqual;
                    if (i.A == 1)
                    {
                        operation = BinOperationType.OpNotEqual;
                    }
                    instrs.Add(new Jump(function.GetLabel((uint)(pos + 2)), new BinOp(ConvertLuaConstant(luaFunction.Constants[(int)i.B], (int)i.B), RegisterReference(i.C), operation)));
                    break;

                case LuaHavokOpCode.HKS_OPCODE_LT:
                    operation = BinOperationType.OpLessThan;
                    if (i.A == 1)
                    {
                        operation = BinOperationType.OpGreaterEqual;
                    }
                    instrs.Add(new Jump(function.GetLabel((uint)(pos + 2)), new BinOp(RegisterReference(i.B), GetConstantBitFix(luaFunction, i.C, i.ExtraCBit), operation)));
                    break;

                case LuaHavokOpCode.HKS_OPCODE_LT_BK:
                    operation = BinOperationType.OpLessThan;
                    if (i.A == 1)
                    {
                        operation = BinOperationType.OpGreaterEqual;
                    }
                    instrs.Add(new Jump(function.GetLabel((uint)(pos + 2)), new BinOp(ConvertLuaConstant(luaFunction.Constants[(int)i.B], (int)i.B), RegisterReference(i.C), operation)));
                    break;

                case LuaHavokOpCode.HKS_OPCODE_LE:
                    operation = BinOperationType.OpLessEqual;
                    if (i.A == 1)
                    {
                        operation = BinOperationType.OpGreaterThan;
                    }
                    instrs.Add(new Jump(function.GetLabel((uint)(pos + 2)), new BinOp(RegisterReference(i.B), GetConstantBitFix(luaFunction, i.C, i.ExtraCBit), operation)));
                    break;

                case LuaHavokOpCode.HKS_OPCODE_LE_BK:
                    operation = BinOperationType.OpLessEqual;
                    if (i.A == 1)
                    {
                        operation = BinOperationType.OpGreaterThan;
                    }
                    instrs.Add(new Jump(function.GetLabel((uint)(pos + 2)), new BinOp(ConvertLuaConstant(luaFunction.Constants[(int)i.B], (int)i.B), RegisterReference(i.C), operation)));
                    break;

                case LuaHavokOpCode.HKS_OPCODE_TEST:
                case LuaHavokOpCode.HKS_OPCODE_TEST_R1:
                    instrs.Add(i.C == 0
                            ? new Jump(function.GetLabel((uint)(pos + 2)), RegisterReference(i.A))
                            : new Jump(function.GetLabel((uint)(pos + 2)),
                                       new UnaryOp(RegisterReference(i.A), UnOperationType.OpNot)));
                    break;

                case LuaHavokOpCode.HKS_OPCODE_TESTSET:
                    instrs.Add(i.C == 0
                            ? new Jump(function.GetLabel((uint)(pos + 2)), RKIR(luaFunction, i.B))
                    {
                        TestsetType = BinOperationType.OpAnd, TestsetLocation = _symbolTable.GetRegister(i.A)
                    }
                            : new Jump(function.GetLabel((uint)(pos + 2)), RKIR(luaFunction, i.B))
                    {
                        TestsetType = BinOperationType.OpOr, TestsetLocation = _symbolTable.GetRegister(i.A)
                    });
                    instrs.Add(new Assignment(_symbolTable.GetRegister(i.A), new IdentifierReference(_symbolTable.GetRegister(i.B))));
                    break;

                case LuaHavokOpCode.HKS_OPCODE_SETTABLE:
                case LuaHavokOpCode.HKS_OPCODE_SETTABLE_S:
                    instrs.Add(new Assignment(
                                   new IdentifierReference(_symbolTable.GetRegister(i.A), RegisterReference(i.B)),
                                   GetConstantBitFix(luaFunction, i.C, i.ExtraCBit)
                                   ));
                    break;

                case LuaHavokOpCode.HKS_OPCODE_TAILCALL:
                case LuaHavokOpCode.HKS_OPCODE_TAILCALL_I:
                case LuaHavokOpCode.HKS_OPCODE_TAILCALL_I_R1:
                    args = new List <IExpression>();
                    for (int arg = (int)i.A + 1; arg < i.A + i.B; arg++)
                    {
                        args.Add(new IdentifierReference(_symbolTable.GetRegister((uint)arg)));
                    }
                    var funCall = new FunctionCall(new IdentifierReference(_symbolTable.GetRegister(i.A)), args);
                    funCall.IsIndeterminateArgumentCount = (i.B == 0);
                    funCall.BeginArg = i.A + 1;
                    instrs.Add(new Return(funCall)
                    {
                        IsTailReturn = true
                    });
                    break;

                case LuaHavokOpCode.HKS_OPCODE_SETTABLE_S_BK:
                    instrs.Add(new Assignment(
                                   new IdentifierReference(_symbolTable.GetRegister(i.A), ConvertLuaConstant(luaFunction.Constants[(int)i.B], (int)i.B)),
                                   GetConstantBitFix(luaFunction, i.C, i.ExtraCBit)));
                    break;

                case LuaHavokOpCode.HKS_OPCODE_CALL_I:
                case LuaHavokOpCode.HKS_OPCODE_CALL_I_R1:
                case LuaHavokOpCode.HKS_OPCODE_CALL:
                    args = new List <IExpression>();
                    var rets = new List <IdentifierReference>();
                    for (int arg = (int)i.A + 1; arg < i.A + i.B; arg++)
                    {
                        args.Add(new IdentifierReference(_symbolTable.GetRegister((uint)arg)));
                    }
                    for (int r = (int)i.A + 1; r < i.A + i.C; r++)
                    {
                        rets.Add(new IdentifierReference(_symbolTable.GetRegister((uint)r - 1)));
                    }
                    if (i.C == 0)
                    {
                        rets.Add(new IdentifierReference(_symbolTable.GetRegister(i.A)));
                    }
                    funCall = new FunctionCall(new IdentifierReference(_symbolTable.GetRegister(i.A)), args);
                    funCall.IsIndeterminateArgumentCount = (i.B == 0);
                    funCall.IsIndeterminateReturnCount   = (i.C == 0);
                    funCall.BeginArg = i.A + 1;
                    assn             = new Assignment(rets, funCall);
                    instrs.Add(assn);
                    break;

                case LuaHavokOpCode.HKS_OPCODE_RETURN:
                    args = new List <IExpression>();
                    if (i.B != 0)
                    {
                        for (int arg = (int)i.A; arg < i.A + i.B - 1; arg++)
                        {
                            args.Add(new IdentifierReference(_symbolTable.GetRegister((uint)arg)));
                        }
                    }
                    var ret = new Return(args);
                    if (i.B == 0)
                    {
                        ret.BeginRet = i.A;
                        ret.IsIndeterminateReturnCount = true;
                    }
                    instrs.Add(ret);
                    break;

                case LuaHavokOpCode.HKS_OPCODE_FORLOOP:
                    instrs.Add(new Assignment(new IdentifierReference(_symbolTable.GetRegister(i.A)), new BinOp(new IdentifierReference(_symbolTable.GetRegister(i.A)),
                                                                                                                new IdentifierReference(_symbolTable.GetRegister(i.A + 2)), BinOperationType.OpAdd)));
                    var jmp = new Jump(function.GetLabel((uint)(pos + 1 + i.SBx)), new BinOp(new IdentifierReference(_symbolTable.GetRegister(i.A)),
                                                                                             new IdentifierReference(_symbolTable.GetRegister(i.A + 1)), BinOperationType.OpLoopCompare));
                    var pta = new Assignment(_symbolTable.GetRegister(i.A + 3), RegisterReference(i.A));
                    pta.PropagateAlways     = true;
                    jmp.PostTakenAssignment = pta;

                    if (debugFunc != null)
                    {
                        var indexVariable = debugFunc.VariableNames.Where(v => v.Start == pos + 1 + i.SBx).ToList();
                        if (indexVariable.Count == 1)
                        {
                            var forIndexIdentifier = _symbolTable.GetRegister(i.A);
                            for (int j = pos + i.SBx; j >= 0; j--)
                            {
                                var opCodeInstrs = function.Instructions.Where(ins => ins.OpLocation == j).ToList();
                                if (opCodeInstrs.Count == 1 && opCodeInstrs[0] is Assignment a && a.Left.Count == 1 && a.Left[0].Identifier == forIndexIdentifier)
                                {
                                    a.LocalAssignments = indexVariable;
                                    break;
                                }
                            }
                            var forStepIdentifier = _symbolTable.GetRegister(i.A + 2);
                            for (int j = pos + i.SBx; j >= 0; j--)
                            {
                                var opCodeInstrs = function.Instructions.Where(ins => ins.OpLocation == j).ToList();
                                if (opCodeInstrs.Count == 1 && opCodeInstrs[0] is Assignment a && a.Left.Count == 1 && a.Left[0].Identifier == forStepIdentifier && a.LocalAssignments.Count == 3)
                                {
                                    var forLimitIdentifier = _symbolTable.GetRegister(i.A + 1);
                                    for (int k = pos + i.SBx; k >= 0; k--)
                                    {
                                        var opLimitCodeInstrs = function.Instructions.Where(ins => ins.OpLocation == k).ToList();
                                        if (opLimitCodeInstrs.Count == 1 && opLimitCodeInstrs[0] is Assignment a2 && a2.Left.Count == 1 && a2.Left[0].Identifier == forLimitIdentifier)
                                        {
                                            a2.LocalAssignments = new List <Local>()
                                            {
                                                a.LocalAssignments[1]
                                            };
                                            break;
                                        }
                                    }
                                    a.LocalAssignments = new List <Local>()
                                    {
                                        a.LocalAssignments[2]
                                    };
                                    break;
                                }
                            }
                        }
                    }


                    instrs.Add(jmp);
                    break;

                case LuaHavokOpCode.HKS_OPCODE_TFORLOOP:
                    args = new List <IExpression>();
                    rets = new List <IdentifierReference>();
                    args.Add(new IdentifierReference(_symbolTable.GetRegister(i.A + 1)));
                    args.Add(new IdentifierReference(_symbolTable.GetRegister(i.A + 2)));
                    if (i.C == 0)
                    {
                        rets.Add(new IdentifierReference(_symbolTable.GetRegister(i.A + 3)));
                    }
                    else
                    {
                        for (int r = (int)i.A + 3; r <= i.A + i.C + 2; r++)
                        {
                            rets.Add(new IdentifierReference(_symbolTable.GetRegister((uint)r)));
                        }
                    }
                    var fCall = new FunctionCall(new IdentifierReference(_symbolTable.GetRegister(i.A)), args);
                    fCall.IsIndeterminateReturnCount = (i.C == 0);
                    assn = new Assignment(rets, fCall);

                    if (debugFunc != null)
                    {
                        var nextOp = ((HavokInstruction)luaFunction.Instructions[pos + 1]);
                        if (nextOp.HavokOpCode == LuaHavokOpCode.HKS_OPCODE_JMP)
                        {
                            assn.LocalAssignments = debugFunc.VariableNames
                                                    .Where(v => v.Start == pos + nextOp.SBx + 2).ToList();
                        }
                    }

                    instrs.Add(assn);
                    instrs.Add(new Jump(function.GetLabel((uint)(pos + 2)), new BinOp(RegisterReference(i.A + 3), new Constant(ValueType.Nil, -1), BinOperationType.OpEqual)));
                    instrs.Add(new Assignment(_symbolTable.GetRegister(i.A + 2), new IdentifierReference(_symbolTable.GetRegister(i.A + 3))));
                    break;

                case LuaHavokOpCode.HKS_OPCODE_FORPREP:
                    // The VM technically does a subtract, but we don't actually emit it since it simplifies things to map better to the high level Lua
                    //instructions.Add(new IR.Assignment(new IR.IdentifierReference(SymbolTable.GetRegister(a)), new IR.BinOp(new IR.IdentifierReference(SymbolTable.GetRegister(a)),
                    //    new IR.IdentifierReference(SymbolTable.GetRegister(a + 2)), IR.BinOp.OperationType.OpSub)));
                    instrs.Add(new Jump(function.GetLabel((uint)(pos + 1 + i.SBx))));
                    break;

                case LuaHavokOpCode.HKS_OPCODE_SETLIST:
                    if (i.B == 0)
                    {
                        if (i.C == 1)
                        {
                            assn = new Assignment(_symbolTable.GetRegister(i.A), RegisterReference(i.A + 1))
                            {
                                VarargAssignmentReg = i.A, IsIndeterminateVararg = true
                            };
                            instrs.Add(assn);
                        }
                    }
                    else
                    {
                        for (int j = 1; j <= i.B; j++)
                        {
                            assn = new Assignment(new IdentifierReference(_symbolTable.GetRegister(i.A), new Constant((double)(i.C - 1) * 32 + j, -1)),
                                                  new IdentifierReference(_symbolTable.GetRegister(i.A + (uint)j)));
                            instrs.Add(assn);
                        }
                    }
                    break;

                case LuaHavokOpCode.HKS_OPCODE_CLOSURE:
                    instrs.Add(new Assignment(_symbolTable.GetRegister(i.A), new Closure(function.Closures[(int)i.Bx])));
                    break;

                case LuaHavokOpCode.HKS_OPCODE_GETFIELD:
                case LuaHavokOpCode.HKS_OPCODE_GETFIELD_R1:
                    assn = new Assignment(RegisterReference(i.A), new IdentifierReference(_symbolTable.GetRegister(i.B), new Constant(luaFunction.Constants[(int)i.C].ToString(), -1)));
                    instrs.Add(assn);
                    break;

                case LuaHavokOpCode.HKS_OPCODE_DATA:
                    if (i.A != 0)
                    {
                        Function closureFunc = null;
                        int      index       = pos;

                        while (index >= 0)
                        {
                            var instru = (HavokInstruction)luaFunction.Instructions[index];
                            if (instru.HavokOpCode == LuaHavokOpCode.HKS_OPCODE_CLOSURE)
                            {
                                closureFunc = function.Closures[(int)instru.Bx];
                                break;
                            }
                            index--;
                        }

                        if (closureFunc == null)
                        {
                            continue;
                        }

                        if (debugFunc != null && function.Instructions.Any() && function.Instructions.Last() is Assignment a && a.Right is Closure)
                        {
                            if (a.LocalAssignments == null)
                            {
                                a.LocalAssignments = new List <Local>();
                            }
                            a.LocalAssignments.AddRange(debugFunc.VariableNames.Where(v => v.Start == pos + 1).ToList());
                        }

                        if (i.A == 1)
                        {
                            closureFunc.UpvalueBindings.Add(_symbolTable.GetRegister(i.C));
                        }
                        else if (i.A == 2)
                        {
                            closureFunc.UpvalueBindings.Add(function.UpvalueBindings[(int)i.C]);
                        }
                    }
                    else
                    {
                        var dat = new Data(i);
                        if (debugFunc != null)
                        {
                            dat.Locals = debugFunc.VariableNames.Where(v => v.Start == pos + 1).ToList();
                        }
                        instrs.Add(dat);
                    }
                    break;

                case LuaHavokOpCode.HKS_OPCODE_SETFIELD:
                case LuaHavokOpCode.HKS_OPCODE_SETFIELD_R1:
                    assn = new Assignment(new IdentifierReference(_symbolTable.GetRegister(i.A), new Constant(luaFunction.Constants[(int)i.B].ToString(), (int)i.B)), GetConstantBitFix(luaFunction, i.C, i.ExtraCBit));
                    instrs.Add(assn);
                    break;

                case LuaHavokOpCode.HKS_OPCODE_VARARG:
                    var varArgs = new List <IdentifierReference>();
                    for (int arg = (int)i.A; arg <= i.A + i.B - 1; arg++)
                    {
                        varArgs.Add(new IdentifierReference(_symbolTable.GetRegister((uint)arg)));
                    }
                    if (i.B != 0)
                    {
                        assn = new Assignment(varArgs, new IdentifierReference(_symbolTable.GetVarargs()));
                    }
                    else
                    {
                        assn = new Assignment(_symbolTable.GetRegister(i.A), new IdentifierReference(_symbolTable.GetVarargs()));
                        assn.IsIndeterminateVararg = true;
                        assn.VarargAssignmentReg   = i.A;
                    }
                    instrs.Add(assn);
                    function.IsVarArgs = true;
                    break;

                case LuaHavokOpCode.HKS_OPCODE_CLOSE:
                    // LUA source : close all variables in the stack up to (>=) R(A)
                    // Let's ignore this for now, doesn't print anything and don't know if it affects SSA
                    instrs.Add(new Close());
                    break;

                default:
                    Console.WriteLine($@"Missing op: {i.HavokOpCode} {i.A} {i.B} {i.C}");
                    instrs.Add(new PlaceholderInstruction($@"{i.HavokOpCode} {i.A} {i.B} {i.C}"));
                    break;
                }

                foreach (var instr in instrs)
                {
                    if (debugFunc != null)
                    {
                        if (instr is Assignment a && a.LocalAssignments == null)
                        {
                            a.LocalAssignments = debugFunc.VariableNames.Where(v => v.Start == pos + 1).ToList();
                        }
                        if (debugFunc.InstructionLocations.Count >= pos)
                        {
                            instr.LineLocation = debugFunc.InstructionLocations[pos];
                        }
                    }

                    instr.OpLocation = pos;
                    function.Instructions.Add(instr);
                }
            }
        }