public static void GenerateIRHKS(IR.Function irfun, Function 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.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, Function fun, int index)
 {
     a.LocalAssignments = fun.LocalsAt(index + 1);
 }