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)])); } }
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])); } }
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(); }
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); }
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(); }
private static void CheckLocal(IR.Assignment a, ILuaFunction fun, int index) { a.LocalAssignments = fun.LocalsAt(index + 1); }
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); }); } }
private void Parse() { Header = ReadHeader(); Constants = ReadConstants(); MainFunction = ReadFunctions(); }
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); } } }