Пример #1
0
        public static void ForwardCopyPropagation(List <CodeBasicBlock> blocks, bool hasReturn, short stackRegisterBegin)
        {
            foreach (var b in blocks)
            {
                var           lst        = b.FinalInstructions;
                HashSet <int> canRemove  = b.CanRemove;
                HashSet <int> pendingFCP = b.PendingCP;
                bool          isInline   = false;
                for (int i = 0; i < lst.Count; i++)
                {
                    if (canRemove.Contains(i))
                    {
                        continue;
                    }
                    OpCodeR X = lst[i];
                    if (X.Code == OpCodeREnum.InlineStart)
                    {
                        isInline = true;
                        continue;
                    }
                    if (X.Code == OpCodeREnum.InlineEnd)
                    {
                        isInline = false;
                        continue;
                    }
                    //if (isInline)
                    //    continue;
                    if (X.Code == OpCodeREnum.Nop || X.Code == OpCodeREnum.Castclass || X.Code == OpCodeREnum.Readonly || X.Code == OpCodeREnum.Volatile)
                    {
                        canRemove.Add(i);
                        continue;
                    }
                    if (X.Code == OpCodeREnum.Move)
                    {
                        short xSrc, xSrc2, xSrc3, xDst;
                        GetOpcodeSourceRegister(ref X, hasReturn, out xSrc, out xSrc2, out xSrc3);
                        GetOpcodeDestRegister(ref X, out xDst);
                        if (xDst == xSrc)
                        {
                            canRemove.Add(i);
                            continue;
                        }
                        //Only deal with local->stack, local->local, stack->stack
                        if (xSrc >= stackRegisterBegin && xDst < stackRegisterBegin || isInline)
                        {
                            continue;
                        }
                        bool postPropagation   = false;
                        bool ended             = false;
                        bool propagationInline = false;
                        for (int j = i + 1; j < lst.Count; j++)
                        {
                            OpCodeR Y = lst[j];
                            if (Y.Code == OpCodeREnum.InlineStart)
                            {
                                propagationInline = true;
                            }
                            else if (Y.Code == OpCodeREnum.InlineEnd)
                            {
                                propagationInline = false;
                            }
                            short ySrc, ySrc2, ySrc3;
                            if (GetOpcodeSourceRegister(ref Y, hasReturn, out ySrc, out ySrc2, out ySrc3))
                            {
                                bool replaced = false;
                                if (ySrc >= 0 && ySrc == xDst)
                                {
                                    if (postPropagation)
                                    {
                                        postPropagation = false;
                                        ended           = true;
                                        break;
                                    }
                                    if (propagationInline)
                                    {
                                        ended = true;
                                        break;
                                    }
                                    ReplaceOpcodeSource(ref Y, 0, xSrc);
                                    replaced = true;
                                }
                                if (ySrc2 >= 0 && ySrc2 == xDst)
                                {
                                    if (postPropagation)
                                    {
                                        postPropagation = false;
                                        ended           = true;
                                        break;
                                    }
                                    if (propagationInline)
                                    {
                                        ended = true;
                                        break;
                                    }
                                    ReplaceOpcodeSource(ref Y, 1, xSrc);
                                    replaced = true;
                                }
                                if (ySrc3 >= 0 && ySrc3 == xDst)
                                {
                                    if (postPropagation)
                                    {
                                        postPropagation = false;
                                        ended           = true;
                                        break;
                                    }
                                    if (propagationInline)
                                    {
                                        ended = true;
                                        break;
                                    }
                                    ReplaceOpcodeSource(ref Y, 2, xSrc);
                                    replaced = true;
                                }

                                if (replaced)
                                {
                                    lst[j] = Y;
                                }
                            }
                            short yDst;
                            if (GetOpcodeDestRegister(ref Y, out yDst))
                            {
                                if (xSrc == yDst)
                                {
                                    postPropagation = true;
                                }
                                if (xDst == yDst)
                                {
                                    postPropagation = false;
                                    ended           = true;
                                    if (!propagationInline)
                                    {
                                        canRemove.Add(i);
                                    }
                                    break;
                                }
                            }

                            if (Y.Code == OpCodeREnum.Ret && !propagationInline)
                            {
                                postPropagation = false;
                                canRemove.Add(i);
                                ended = true;
                                break;
                            }
                        }

                        if (postPropagation || !ended)
                        {
                            if (xDst >= stackRegisterBegin)
                            {
                                pendingFCP.Add(i);
                            }
                        }
                    }
                }
            }

            foreach (var b in blocks)
            {
                var pendingFCP = b.PendingCP;

                if (pendingFCP.Count > 0)
                {
                    var originBlock = b;
                    HashSet <CodeBasicBlock> processedBlocks = new HashSet <CodeBasicBlock>();
                    Queue <CodeBasicBlock>   pendingBlocks   = new Queue <CodeBasicBlock>();

                    foreach (var idx in pendingFCP)
                    {
                        var   X = originBlock.FinalInstructions[idx];
                        short xDst, xSrc, xSrc2, xSrc3;
                        GetOpcodeDestRegister(ref X, out xDst);
                        GetOpcodeSourceRegister(ref X, hasReturn, out xSrc, out xSrc2, out xSrc3);
                        pendingBlocks.Clear();
                        bool cannotRemove = false;
                        bool isAbort      = false;
                        processedBlocks.Clear();
                        foreach (var nb in originBlock.NextBlocks)
                        {
                            pendingBlocks.Enqueue(nb);
                        }
                        processedBlocks.Add(originBlock);
                        while (pendingBlocks.Count > 0)
                        {
                            var cur = pendingBlocks.Dequeue();

                            var  ins = cur.FinalInstructions;
                            bool propagationInline = false;

                            for (int j = 0; j < ins.Count; j++)
                            {
                                if (cur == originBlock && j == idx)
                                {
                                    isAbort = true;
                                    break;
                                }
                                var Y = ins[j];
                                if (Y.Code == OpCodeREnum.InlineStart)
                                {
                                    propagationInline = true;
                                }
                                else if (Y.Code == OpCodeREnum.InlineEnd)
                                {
                                    propagationInline = false;
                                }
                                short ySrc, ySrc2, ySrc3, yDst;
                                if (GetOpcodeSourceRegister(ref Y, hasReturn, out ySrc, out ySrc2, out ySrc3))
                                {
                                    bool replaced = false;
                                    if (ySrc == xDst)
                                    {
                                        if (propagationInline || cur.PreviousBlocks.Count > 1)
                                        {
                                            cannotRemove = true;
                                            break;
                                        }
                                        replaced = true;
                                        ReplaceOpcodeSource(ref Y, 0, xSrc);
                                    }
                                    if (ySrc2 == xDst)
                                    {
                                        if (propagationInline || cur.PreviousBlocks.Count > 1)
                                        {
                                            cannotRemove = true;
                                            break;
                                        }
                                        replaced = true;
                                        ReplaceOpcodeSource(ref Y, 1, xSrc);
                                    }
                                    if (ySrc3 == xDst)
                                    {
                                        if (propagationInline || cur.PreviousBlocks.Count > 1)
                                        {
                                            cannotRemove = true;
                                            break;
                                        }
                                        replaced = true;
                                        ReplaceOpcodeSource(ref Y, 2, xSrc);
                                    }

                                    if (replaced)
                                    {
                                        ins[j] = Y;
                                    }
                                }
                                if (GetOpcodeDestRegister(ref Y, out yDst))
                                {
                                    if (yDst == xDst)
                                    {
                                        isAbort = true;
                                        break;
                                    }
                                }
                                if (Y.Code == OpCodeREnum.Ret && !propagationInline)
                                {
                                    isAbort = true;
                                    break;
                                }
                            }

                            if (cannotRemove)
                            {
                                break;
                            }

                            processedBlocks.Add(cur);
                            if (!isAbort)
                            {
                                foreach (var nb in cur.NextBlocks)
                                {
                                    if (!processedBlocks.Contains(nb))
                                    {
                                        pendingBlocks.Enqueue(nb);
                                    }
                                }
                            }
                        }
                        if (!cannotRemove)
                        {
                            originBlock.CanRemove.Add(idx);
                        }
                    }
                    pendingFCP.Clear();
                }
            }
        }
Пример #2
0
        public static bool GetOpcodeSourceRegister(ref OpCodeR op, bool hasReturn, out short r1, out short r2, out short r3)
        {
            r1 = -1;
            r2 = -1;
            r3 = -1;
            switch (op.Code)
            {
            case OpCodeREnum.Move:
            case OpCodeREnum.Conv_I:
            case OpCodeREnum.Conv_I1:
            case OpCodeREnum.Conv_I2:
            case OpCodeREnum.Conv_I4:
            case OpCodeREnum.Conv_I8:
            case OpCodeREnum.Conv_Ovf_I:
            case OpCodeREnum.Conv_Ovf_I1:
            case OpCodeREnum.Conv_Ovf_I1_Un:
            case OpCodeREnum.Conv_Ovf_I2:
            case OpCodeREnum.Conv_Ovf_I2_Un:
            case OpCodeREnum.Conv_Ovf_I4:
            case OpCodeREnum.Conv_Ovf_I4_Un:
            case OpCodeREnum.Conv_Ovf_I8:
            case OpCodeREnum.Conv_Ovf_I8_Un:
            case OpCodeREnum.Conv_Ovf_I_Un:
            case OpCodeREnum.Conv_Ovf_U:
            case OpCodeREnum.Conv_Ovf_U1:
            case OpCodeREnum.Conv_Ovf_U1_Un:
            case OpCodeREnum.Conv_Ovf_U2:
            case OpCodeREnum.Conv_Ovf_U2_Un:
            case OpCodeREnum.Conv_Ovf_U4:
            case OpCodeREnum.Conv_Ovf_U4_Un:
            case OpCodeREnum.Conv_Ovf_U8:
            case OpCodeREnum.Conv_Ovf_U8_Un:
            case OpCodeREnum.Conv_Ovf_U_Un:
            case OpCodeREnum.Conv_R4:
            case OpCodeREnum.Conv_R8:
            case OpCodeREnum.Conv_R_Un:
            case OpCodeREnum.Conv_U:
            case OpCodeREnum.Conv_U1:
            case OpCodeREnum.Conv_U2:
            case OpCodeREnum.Conv_U4:
            case OpCodeREnum.Conv_U8:
            case OpCodeREnum.Not:
            case OpCodeREnum.Neg:
            case OpCodeREnum.Box:
            case OpCodeREnum.Unbox:
            case OpCodeREnum.Unbox_Any:
            case OpCodeREnum.Ldind_I:
            case OpCodeREnum.Ldind_I1:
            case OpCodeREnum.Ldind_I2:
            case OpCodeREnum.Ldind_I4:
            case OpCodeREnum.Ldind_I8:
            case OpCodeREnum.Ldind_R4:
            case OpCodeREnum.Ldind_R8:
            case OpCodeREnum.Ldind_U1:
            case OpCodeREnum.Ldind_U2:
            case OpCodeREnum.Ldind_U4:
            case OpCodeREnum.Ldind_Ref:
            case OpCodeREnum.Ldobj:
            case OpCodeREnum.Ldloca:
            case OpCodeREnum.Ldloca_S:
            case OpCodeREnum.Ldarg_S:
            case OpCodeREnum.Ldarga:
            case OpCodeREnum.Ldarga_S:
            case OpCodeREnum.Ldlen:
            case OpCodeREnum.Newarr:
            case OpCodeREnum.Ldfld:
            case OpCodeREnum.Ldflda:
            case OpCodeREnum.Ldvirtftn:
            case OpCodeREnum.Isinst:
                r1 = op.Register2;
                return(true);

            case OpCodeREnum.Stind_I:
            case OpCodeREnum.Stind_I1:
            case OpCodeREnum.Stind_I2:
            case OpCodeREnum.Stind_I4:
            case OpCodeREnum.Stind_I8:
            case OpCodeREnum.Stind_R4:
            case OpCodeREnum.Stind_R8:
            case OpCodeREnum.Stind_Ref:
            case OpCodeREnum.Stobj:
            case OpCodeREnum.Stfld:
                r1 = op.Register1;
                r2 = op.Register2;
                return(true);

            case OpCodeREnum.Ldc_I4_0:
            case OpCodeREnum.Ldc_I4_1:
            case OpCodeREnum.Ldc_I4_2:
            case OpCodeREnum.Ldc_I4_3:
            case OpCodeREnum.Ldc_I4_4:
            case OpCodeREnum.Ldc_I4_5:
            case OpCodeREnum.Ldc_I4_6:
            case OpCodeREnum.Ldc_I4_7:
            case OpCodeREnum.Ldc_I4_8:
            case OpCodeREnum.Ldc_I4_M1:
            case OpCodeREnum.Ldnull:
            case OpCodeREnum.Ldc_I4:
            case OpCodeREnum.Ldc_I4_S:
            case OpCodeREnum.Ldc_I8:
            case OpCodeREnum.Ldc_R4:
            case OpCodeREnum.Ldc_R8:
            case OpCodeREnum.Ldstr:
            case OpCodeREnum.Ldtoken:
            case OpCodeREnum.Ldftn:
            case OpCodeREnum.Ldsfld:
            case OpCodeREnum.Ldsflda:
            case OpCodeREnum.Constrained:
                return(false);

            case OpCodeREnum.Callvirt:
            case OpCodeREnum.Call:
            case OpCodeREnum.Newobj:
                r1 = op.Register2;
                r2 = op.Register3;
                r3 = op.Register4;
                return(true);

            case OpCodeREnum.Br_S:
            case OpCodeREnum.Br:
            case OpCodeREnum.Nop:
            case OpCodeREnum.InlineStart:
            case OpCodeREnum.InlineEnd:
            case OpCodeREnum.Castclass:
            case OpCodeREnum.Readonly:
            case OpCodeREnum.Leave:
            case OpCodeREnum.Leave_S:
            case OpCodeREnum.Endfinally:
            case OpCodeREnum.Volatile:
                return(false);

            case OpCodeREnum.Brtrue:
            case OpCodeREnum.Brtrue_S:
            case OpCodeREnum.Brfalse:
            case OpCodeREnum.Brfalse_S:
            case OpCodeREnum.Push:
            case OpCodeREnum.Initobj:
            case OpCodeREnum.Throw:
            case OpCodeREnum.Stsfld:
            case OpCodeREnum.Switch:
                r1 = op.Register1;
                return(true);

            case OpCodeREnum.Blt:
            case OpCodeREnum.Blt_S:
            case OpCodeREnum.Blt_Un:
            case OpCodeREnum.Blt_Un_S:
            case OpCodeREnum.Ble:
            case OpCodeREnum.Ble_S:
            case OpCodeREnum.Ble_Un:
            case OpCodeREnum.Ble_Un_S:
            case OpCodeREnum.Bgt:
            case OpCodeREnum.Bgt_S:
            case OpCodeREnum.Bgt_Un:
            case OpCodeREnum.Bgt_Un_S:
            case OpCodeREnum.Bge:
            case OpCodeREnum.Bge_S:
            case OpCodeREnum.Bge_Un:
            case OpCodeREnum.Bge_Un_S:
            case OpCodeREnum.Beq:
            case OpCodeREnum.Beq_S:
            case OpCodeREnum.Bne_Un:
            case OpCodeREnum.Bne_Un_S:
                r1 = op.Register1;
                r2 = op.Register2;
                return(true);

            case OpCodeREnum.Add:
            case OpCodeREnum.Add_Ovf:
            case OpCodeREnum.Add_Ovf_Un:
            case OpCodeREnum.Sub:
            case OpCodeREnum.Sub_Ovf:
            case OpCodeREnum.Sub_Ovf_Un:
            case OpCodeREnum.Mul:
            case OpCodeREnum.Mul_Ovf:
            case OpCodeREnum.Mul_Ovf_Un:
            case OpCodeREnum.Div:
            case OpCodeREnum.Div_Un:
            case OpCodeREnum.Rem:
            case OpCodeREnum.Rem_Un:
            case OpCodeREnum.Xor:
            case OpCodeREnum.And:
            case OpCodeREnum.Or:
            case OpCodeREnum.Shl:
            case OpCodeREnum.Shr:
            case OpCodeREnum.Shr_Un:
            case OpCodeREnum.Clt:
            case OpCodeREnum.Clt_Un:
            case OpCodeREnum.Cgt:
            case OpCodeREnum.Cgt_Un:
            case OpCodeREnum.Ceq:
            case OpCodeREnum.Ldelem_I1:
            case OpCodeREnum.Ldelem_U1:
            case OpCodeREnum.Ldelem_I2:
            case OpCodeREnum.Ldelem_U2:
            case OpCodeREnum.Ldelem_I4:
            case OpCodeREnum.Ldelem_U4:
            case OpCodeREnum.Ldelem_I8:
            case OpCodeREnum.Ldelem_R4:
            case OpCodeREnum.Ldelem_R8:
            case OpCodeREnum.Ldelem_Any:
            case OpCodeREnum.Ldelem_Ref:
            case OpCodeREnum.Ldelema:
                r1 = op.Register2;
                r2 = op.Register3;
                return(true);

            case OpCodeREnum.Stelem_I:
            case OpCodeREnum.Stelem_I1:
            case OpCodeREnum.Stelem_I2:
            case OpCodeREnum.Stelem_I4:
            case OpCodeREnum.Stelem_I8:
            case OpCodeREnum.Stelem_R4:
            case OpCodeREnum.Stelem_R8:
            case OpCodeREnum.Stelem_Ref:
            case OpCodeREnum.Stelem_Any:
                r1 = op.Register1;
                r2 = op.Register2;
                r3 = op.Register3;
                return(true);

            case OpCodeREnum.Ret:
                if (hasReturn)
                {
                    r1 = op.Register1;
                    return(true);
                }
                else
                {
                    return(false);
                }

            default:
                throw new NotImplementedException();
            }
        }
Пример #3
0
        public static void BackwardsCopyPropagation(List <CodeBasicBlock> blocks, bool hasReturn, short stackRegisterBegin)
        {
            foreach (var b in blocks)
            {
                var           lst       = b.FinalInstructions;
                HashSet <int> canRemove = b.CanRemove;
                //HashSet<int> pendingBCP = b.PendingCP;
                bool isInline = false;

                for (int i = lst.Count - 1; i >= 0; i--)
                {
                    if (canRemove.Contains(i))
                    {
                        continue;
                    }
                    OpCodeR X = lst[i];
                    if (X.Code == OpCodeREnum.InlineStart)
                    {
                        isInline = false;
                        continue;
                    }
                    if (X.Code == OpCodeREnum.InlineEnd)
                    {
                        isInline = true;
                        continue;
                    }
                    //if (isInline)
                    //    continue;
                    if (X.Code == OpCodeREnum.Nop)
                    {
                        canRemove.Add(i);
                        continue;
                    }
                    if (X.Code == OpCodeREnum.Move)
                    {
                        short xSrc, xSrc2, xSrc3, xDst;
                        GetOpcodeSourceRegister(ref X, hasReturn, out xSrc, out xSrc2, out xSrc3);
                        GetOpcodeDestRegister(ref X, out xDst);
                        if (xDst == xSrc)
                        {
                            canRemove.Add(i);
                            continue;
                        }
                        //Only deal with stack->local
                        if (xSrc < stackRegisterBegin || xDst >= stackRegisterBegin || isInline)
                        {
                            continue;
                        }
                        bool ended             = false;
                        bool propagationInline = false;
                        for (int j = i - 1; j >= 0; j--)
                        {
                            OpCodeR Y = lst[j];
                            if (Y.Code == OpCodeREnum.InlineStart)
                            {
                                propagationInline = false;
                            }
                            else if (Y.Code == OpCodeREnum.InlineEnd)
                            {
                                propagationInline = true;
                            }

                            short ySrc, ySrc2, ySrc3;
                            if (GetOpcodeSourceRegister(ref Y, hasReturn, out ySrc, out ySrc2, out ySrc3))
                            {
                                if (ySrc >= 0 && ySrc == xDst)
                                {
                                    break;
                                }
                                if (ySrc2 >= 0 && ySrc2 == xDst)
                                {
                                    break;
                                }
                                if (ySrc3 >= 0 && ySrc3 == xDst)
                                {
                                    break;
                                }
                            }
                            short yDst;
                            if (GetOpcodeDestRegister(ref Y, out yDst))
                            {
                                if (xDst == yDst && !propagationInline)
                                {
                                    ended = true;
                                    break;
                                }
                                if (xSrc == yDst)
                                {
                                    if (propagationInline)
                                    {
                                        ended = true;
                                        break;
                                    }
                                    ReplaceOpcodeDest(ref Y, xDst);
                                    for (int k = j + 1; k < lst.Count; k++)
                                    {
                                        OpCodeR Z = lst[k];
                                        bool    replaced = false;
                                        short   zSrc, zSrc2, zSrc3;
                                        short   zDst;
                                        GetOpcodeDestRegister(ref Z, out zDst);
                                        if (GetOpcodeSourceRegister(ref Z, hasReturn, out zSrc, out zSrc2, out zSrc3))
                                        {
                                            if (zSrc == yDst)
                                            {
                                                replaced = true;
                                                ReplaceOpcodeSource(ref Z, 0, xDst);
                                            }
                                            if (zSrc2 == yDst)
                                            {
                                                replaced = true;
                                                ReplaceOpcodeSource(ref Z, 1, xDst);
                                            }
                                            if (zSrc3 == yDst)
                                            {
                                                replaced = true;
                                                ReplaceOpcodeSource(ref Z, 2, xDst);
                                            }
                                        }
                                        if (replaced)
                                        {
                                            lst[k] = Z;
                                        }
                                        if (zDst >= 0)
                                        {
                                            if (zDst == yDst)
                                            {
                                                break;
                                            }
                                        }
                                    }
                                    canRemove.Add(i);
                                    ended  = true;
                                    lst[j] = Y;
                                    break;
                                }
                            }
                        }

                        /*if (!ended)
                         * {
                         *  if (xDst < stackRegisterBegin)
                         *  {
                         *      pendingBCP.Add(i);
                         *      throw new NotImplementedException();
                         *  }
                         * }*/
                    }
                }
            }
        }
Пример #4
0
        public static void InlineMethod(CodeBasicBlock block, ILMethod method, RegisterVMSymbolLink symbolLink, ref Dictionary <int, int[]> jumpTables, short baseRegIdx, bool hasReturn)
        {
            var     ins   = block.FinalInstructions;
            var     body  = method.BodyRegister;
            OpCodeR start = new OpCodeR();

            start.Code = OpCodeREnum.InlineStart;
            ins.Add(start);
            int        branchStart  = ins.Count;
            int        branchOffset = 0;
            List <int> reloc        = new List <int>();

            if (body != null)
            {
                for (int i = 0; i < body.Length; i++)
                {
                    var   opcode = body[i];
                    short r1     = 0;
                    short r2     = 0;
                    short r3     = 0;
                    if (GetOpcodeSourceRegister(ref opcode, hasReturn, out r1, out r2, out r3))
                    {
                        if (r1 >= 0)
                        {
                            ReplaceOpcodeSource(ref opcode, 0, (short)(r1 + baseRegIdx));
                        }
                        if (r2 >= 0)
                        {
                            ReplaceOpcodeSource(ref opcode, 1, (short)(r2 + baseRegIdx));
                        }
                        if (r3 >= 0)
                        {
                            ReplaceOpcodeSource(ref opcode, 2, (short)(r3 + baseRegIdx));
                        }
                    }
                    if (GetOpcodeDestRegister(ref opcode, out r1))
                    {
                        if (r1 >= 0)
                        {
                            ReplaceOpcodeDest(ref opcode, (short)(r1 + baseRegIdx));
                        }
                    }

                    if (opcode.Code == OpCodeREnum.Ret)
                    {
                        bool needMove = hasReturn && opcode.Register1 != baseRegIdx;
                        if (needMove)
                        {
                            opcode.Code      = OpCodeREnum.Move;
                            opcode.Register2 = opcode.Register1;
                            opcode.Register1 = baseRegIdx;
                            ins.Add(opcode);
                            branchOffset++;
                        }
                        if (i < body.Length - 1)
                        {
                            if (needMove)
                            {
                                for (int j = branchStart; j < ins.Count; j++)
                                {
                                    var op2 = ins[j];
                                    if (IsBranching(op2.Code))
                                    {
                                        if (op2.Operand > i)
                                        {
                                            op2.Operand++;
                                            ins[j] = op2;
                                        }
                                    }
                                    else if (IsIntermediateBranching(op2.Code))
                                    {
                                        if (op2.Operand4 > i)
                                        {
                                            op2.Operand4++;
                                            ins[j] = op2;
                                        }
                                    }
                                    else if (op2.Code == OpCodeREnum.Switch)
                                    {
                                        var targets = jumpTables[op2.Operand];
                                        for (int k = 0; k < targets.Length; k++)
                                        {
                                            if (targets[k] > i)
                                            {
                                                targets[k]++;
                                            }
                                        }
                                    }
                                }
                            }
                            reloc.Add(ins.Count);
                            opcode.Code = OpCodeREnum.Br;
                            ins.Add(opcode);
                        }
                        continue;
                    }

                    if (IsBranching(opcode.Code))
                    {
                        opcode.Operand += branchOffset;
                    }
                    if (opcode.Code == OpCodeREnum.Switch)
                    {
                        int[] targets    = method.JumpTablesRegister[opcode.Operand];
                        int[] newTargets = new int[targets.Length];
                        for (int j = 0; j < targets.Length; j++)
                        {
                            newTargets[j] = targets[j] + branchOffset;
                        }
                        if (jumpTables == null)
                        {
                            jumpTables = new Dictionary <int, int[]>();
                        }
                        opcode.Operand = newTargets.GetHashCode();
                        jumpTables.Add(opcode.Operand, newTargets);
                    }
#if DEBUG && !DISABLE_ILRUNTIME_DEBUG
                    RegisterVMSymbol oriIns;
                    if (method.RegisterVMSymbols.TryGetValue(i, out oriIns))
                    {
                        oriIns.ParentSymbol = symbolLink;
                        block.InstructionMapping.Add(ins.Count, oriIns);
                    }
#endif
                    ins.Add(opcode);
                }
            }

            foreach (var i in reloc)
            {
                var opcode = ins[i];
                opcode.Operand = ins.Count - branchStart;
                ins[i]         = opcode;
            }
            start.Code = OpCodeREnum.InlineEnd;
            ins.Add(start);
        }
Пример #5
0
        void Translate(CodeBasicBlock block, Instruction ins, short locVarRegStart, ref short baseRegIdx)
        {
            List <OpCodeR> lst   = block.FinalInstructions;
            OpCodeR        op    = new OpCodeR();
            var            code  = ins.OpCode;
            var            token = ins.Operand;

            op.Code = (OpCodeREnum)code.Code;
            bool hasRet;

            switch (code.Code)
            {
            case Code.Br_S:
            case Code.Br:
                op.Operand = entryMapping[(Mono.Cecil.Cil.Instruction)token];
                break;

            case Code.Brtrue:
            case Code.Brtrue_S:
            case Code.Brfalse:
            case Code.Brfalse_S:
                op.Register1 = --baseRegIdx;
                op.Operand   = entryMapping[(Mono.Cecil.Cil.Instruction)token];
                break;

            case Code.Switch:
                op.Register1 = --baseRegIdx;
                PrepareJumpTable(token);
                op.Operand = token.GetHashCode();
                break;

            case Code.Blt:
            case Code.Blt_S:
            case Code.Blt_Un:
            case Code.Blt_Un_S:
            case Code.Ble:
            case Code.Ble_S:
            case Code.Ble_Un:
            case Code.Ble_Un_S:
            case Code.Bgt:
            case Code.Bgt_S:
            case Code.Bgt_Un:
            case Code.Bgt_Un_S:
            case Code.Bge:
            case Code.Bge_S:
            case Code.Bge_Un:
            case Code.Bge_Un_S:
            case Code.Beq:
            case Code.Beq_S:
            case Code.Bne_Un:
            case Code.Bne_Un_S:
                op.Register1 = (short)(baseRegIdx - 2);
                op.Register2 = (short)(baseRegIdx - 1);
                baseRegIdx  -= 2;
                op.Operand   = entryMapping[(Mono.Cecil.Cil.Instruction)token];
                break;

            case Code.Ldc_I4_0:
            case Code.Ldc_I4_1:
            case Code.Ldc_I4_2:
            case Code.Ldc_I4_3:
            case Code.Ldc_I4_4:
            case Code.Ldc_I4_5:
            case Code.Ldc_I4_6:
            case Code.Ldc_I4_7:
            case Code.Ldc_I4_8:
            case Code.Ldc_I4_M1:
            case Code.Ldnull:
                op.Register1 = baseRegIdx++;
                break;

            case Code.Ldc_I4:
                op.Register1 = baseRegIdx++;
                op.Operand   = (int)token;
                break;

            case Code.Ldc_I4_S:
                op.Register1 = baseRegIdx++;
                op.Operand   = (sbyte)token;
                break;

            case Code.Ldc_I8:
                op.Register1   = baseRegIdx++;
                op.OperandLong = (long)token;
                break;

            case Code.Ldc_R4:
                op.Register1    = baseRegIdx++;
                op.OperandFloat = (float)token;
                break;

            case Code.Ldc_R8:
                op.Register1     = baseRegIdx++;
                op.OperandDouble = (double)token;
                break;

            case Code.Ldstr:
                op.Register1   = baseRegIdx++;
                op.OperandLong = appdomain.CacheString(token);
                break;

            case Code.Newobj:
            {
                bool     canInline, isILMethod;
                ILMethod toInline;
                IMethod  m;
                var      pCnt    = InitializeFunctionParam(ref op, token, out hasRet, out canInline, out m, out toInline, out isILMethod);
                int      pushCnt = Math.Max(pCnt - CallRegisterParamCount, 0);
                for (int i = pCnt; i > pCnt - pushCnt; i--)
                {
                    OpCodes.OpCodeR op2 = new OpCodes.OpCodeR();
                    op2.Code      = OpCodes.OpCodeREnum.Push;
                    op2.Register1 = (short)(baseRegIdx - i);
                    lst.Add(op2);
                }
                if (pushCnt < pCnt)
                {
                    switch (pCnt - pushCnt)
                    {
                    case 1:
                        op.Register2 = (short)(baseRegIdx - 1);
                        break;

                    case 2:
                        op.Register3 = (short)(baseRegIdx - 1);
                        op.Register2 = (short)(baseRegIdx - 2);
                        break;

                    case 3:
                        op.Register4 = (short)(baseRegIdx - 1);
                        op.Register3 = (short)(baseRegIdx - 2);
                        op.Register2 = (short)(baseRegIdx - 3);
                        break;
                    }
                }
                baseRegIdx  -= (short)pCnt;
                op.Register1 = baseRegIdx++;
            }
            break;

            case Code.Call:
            case Code.Callvirt:
            {
                bool     canInline, isILMethod;
                ILMethod toInline;
                IMethod  m;
                var      pCnt           = InitializeFunctionParam(ref op, token, out hasRet, out canInline, out m, out toInline, out isILMethod);
                bool     hasConstrained = false;
                int      constrainIdx   = -1;
                if (lst.Count > 0)
                {
                    constrainIdx   = lst.Count - 1;
                    hasConstrained = lst[constrainIdx].Code == OpCodeREnum.Constrained;
                }
                bool needInline = canInline && !hasConstrained;
                if (needInline)
                {
                    if (toInline.BodyRegister.Length > Optimizer.MaximalInlineInstructionCount / 2)
                    {
                        needInline = false;
                    }
                }
                if (!needInline)
                {
                    if (code.Code == Code.Callvirt && m is ILMethod)
                    {
                        ILMethod ilm = (ILMethod)m;
                        if (!ilm.Definition.IsAbstract && !ilm.Definition.IsVirtual && !ilm.DeclearingType.IsInterface)
                        {
                            op.Code = OpCodeREnum.Call;
                        }
                    }
                    int pushCnt = hasConstrained ? pCnt : Math.Max(pCnt - CallRegisterParamCount, 0);
                    for (int i = pCnt; i > pCnt - pushCnt; i--)
                    {
                        OpCodes.OpCodeR op2 = new OpCodes.OpCodeR();
                        op2.Code      = OpCodes.OpCodeREnum.Push;
                        op2.Operand   = isILMethod ? 1 : 0;
                        op2.Register1 = (short)(baseRegIdx - i);
                        lst.Add(op2);
                    }
                    if (pushCnt < pCnt)
                    {
                        switch (pCnt - pushCnt)
                        {
                        case 1:
                            op.Register2 = (short)(baseRegIdx - 1);
                            break;

                        case 2:
                            op.Register3 = (short)(baseRegIdx - 1);
                            op.Register2 = (short)(baseRegIdx - 2);
                            break;

                        case 3:
                            op.Register4 = (short)(baseRegIdx - 1);
                            op.Register3 = (short)(baseRegIdx - 2);
                            op.Register2 = (short)(baseRegIdx - 3);
                            break;
                        }
                    }
                    if (hasConstrained)
                    {
                        op.Operand4 = 1;
                        var old = lst[constrainIdx];
                        lst.RemoveAt(constrainIdx);
                        old.Operand2 = op.Operand2;
                        var symbol = block.InstructionMapping[constrainIdx];
                        block.InstructionMapping.Remove(constrainIdx);
                        block.InstructionMapping.Add(lst.Count, symbol);
                        lst.Add(old);
                    }
                    baseRegIdx -= (short)pCnt;

                    if (hasRet)
                    {
                        op.Register1 = baseRegIdx++;
                    }
                    else
                    {
                        op.Register1 = -1;
                    }
                }
                else
                {
                    baseRegIdx -= (short)pCnt;
                    RegisterVMSymbolLink link = null;
#if DEBUG && !DISABLE_ILRUNTIME_DEBUG
                    link = new RegisterVMSymbolLink();
                    link.BaseRegisterIndex = baseRegIdx;
                    link.Value.Instruction = ins;
                    link.Value.Method      = method;
#endif
#if DEBUG && !NO_PROFILER
                    if (System.Threading.Thread.CurrentThread.ManagedThreadId == method.AppDomain.UnityMainThreadID)

#if UNITY_5_5_OR_NEWER
                    { UnityEngine.Profiling.Profiler.BeginSample("JITCompiler.InlineMethod"); }
#else
                    { UnityEngine.Profiler.BeginSample("JITCompiler.InlineMethod"); }
#endif
#endif
                    Optimizer.InlineMethod(block, toInline, link, ref jumptables, baseRegIdx, hasRet);
#if DEBUG && !NO_PROFILER
                    if (System.Threading.Thread.CurrentThread.ManagedThreadId == method.AppDomain.UnityMainThreadID)
#if UNITY_5_5_OR_NEWER
                    { UnityEngine.Profiling.Profiler.EndSample(); }
#else
                    { UnityEngine.Profiler.EndSample(); }
#endif
#endif
                    if (hasRet)
                    {
                        baseRegIdx++;
                    }
                    return;
                }
            }
            break;

            case Code.Ldsfld:
            case Code.Ldsflda:
                op.Register1   = baseRegIdx++;
                op.OperandLong = appdomain.GetStaticFieldIndex(token, declaringType, method);
                break;

            case Code.Stsfld:
                op.Register1   = --baseRegIdx;
                op.OperandLong = appdomain.GetStaticFieldIndex(token, declaringType, method);
                break;

            case Code.Initobj:
                op.Register1 = --baseRegIdx;
                op.Operand   = method.GetTypeTokenHashCode(token);
                break;

            case Code.Ret:
                if (hasReturn)
                {
                    op.Register1 = --baseRegIdx;
                }
                break;

            case Code.Throw:
                op.Register1 = --baseRegIdx;
                break;

            case Code.Add:
            case Code.Add_Ovf:
            case Code.Add_Ovf_Un:
            case Code.Sub:
            case Code.Sub_Ovf:
            case Code.Sub_Ovf_Un:
            case Code.Mul:
            case Code.Mul_Ovf:
            case Code.Mul_Ovf_Un:
            case Code.Div:
            case Code.Div_Un:
            case Code.Rem:
            case Code.Rem_Un:
            case Code.Shr:
            case Code.Shr_Un:
            case Code.Shl:
            case Code.Xor:
            case Code.Or:
            case Code.And:
            case Code.Clt:
            case Code.Clt_Un:
            case Code.Cgt:
            case Code.Cgt_Un:
            case Code.Ceq:
            case Code.Ldelema:
            case Code.Ldelem_I1:
            case Code.Ldelem_U1:
            case Code.Ldelem_I2:
            case Code.Ldelem_U2:
            case Code.Ldelem_I4:
            case Code.Ldelem_U4:
            case Code.Ldelem_I8:
            case Code.Ldelem_R4:
            case Code.Ldelem_R8:
            case Code.Ldelem_Any:
            case Code.Ldelem_Ref:
                op.Register1 = (short)(baseRegIdx - 2);     //explicit use dest register for optimization
                op.Register2 = (short)(baseRegIdx - 2);
                op.Register3 = (short)(baseRegIdx - 1);
                baseRegIdx--;
                break;

            case Code.Nop:
            case Code.Castclass:
            case Code.Readonly:
            case Code.Volatile:
            case Code.Endfinally:
                break;

            case Code.Leave:
            case Code.Leave_S:
                break;

            case Code.Stloc_0:
                op.Code      = OpCodes.OpCodeREnum.Move;
                op.Register1 = locVarRegStart;
                op.Register2 = --baseRegIdx;
                break;

            case Code.Stloc_1:
                op.Code      = OpCodes.OpCodeREnum.Move;
                op.Register1 = (short)(locVarRegStart + 1);
                op.Register2 = --baseRegIdx;
                break;

            case Code.Stloc_2:
                op.Code      = OpCodes.OpCodeREnum.Move;
                op.Register1 = (short)(locVarRegStart + 2);
                op.Register2 = --baseRegIdx;
                break;

            case Code.Stloc_3:
                op.Code      = OpCodes.OpCodeREnum.Move;
                op.Register1 = (short)(locVarRegStart + 3);
                op.Register2 = --baseRegIdx;
                break;

            case Code.Stloc_S:
                op.Code      = OpCodes.OpCodeREnum.Move;
                op.Register1 = (short)(locVarRegStart + ((VariableDefinition)ins.Operand).Index);
                op.Register2 = --baseRegIdx;
                break;

            case Code.Ldloc_0:
                op.Code      = OpCodes.OpCodeREnum.Move;
                op.Register1 = baseRegIdx++;
                op.Register2 = locVarRegStart;
                break;

            case Code.Ldloc_1:
                op.Code      = OpCodes.OpCodeREnum.Move;
                op.Register1 = baseRegIdx++;
                op.Register2 = (short)(locVarRegStart + 1);
                break;

            case Code.Ldloc_2:
                op.Code      = OpCodes.OpCodeREnum.Move;
                op.Register1 = baseRegIdx++;
                op.Register2 = (short)(locVarRegStart + 2);
                break;

            case Code.Ldloc_3:
                op.Code      = OpCodes.OpCodeREnum.Move;
                op.Register1 = baseRegIdx++;
                op.Register2 = (short)(locVarRegStart + 3);
                break;

            case Code.Ldloc:
            case Code.Ldloc_S:
                op.Code      = OpCodes.OpCodeREnum.Move;
                op.Register1 = baseRegIdx++;
                op.Register2 = (short)(locVarRegStart + ((VariableDefinition)ins.Operand).Index);
                break;

            case Code.Ldloca:
            case Code.Ldloca_S:
                op.Register1 = baseRegIdx++;
                op.Register2 = (short)(locVarRegStart + ((VariableDefinition)ins.Operand).Index);
                break;

            case Code.Ldarg_0:
            case Code.Ldarg_1:
            case Code.Ldarg_2:
            case Code.Ldarg_3:
                op.Code      = OpCodes.OpCodeREnum.Move;
                op.Register1 = baseRegIdx++;
                op.Register2 = (short)(code.Code - (Code.Ldarg_0));
                break;

            case Code.Ldarg_S:
                op.Code      = OpCodes.OpCodeREnum.Move;
                op.Register1 = baseRegIdx++;
                op.Register2 = (short)((ParameterDefinition)ins.Operand).Index;
                if (def.HasThis)
                {
                    op.Register2++;
                }
                break;

            case Code.Ldarga:
            case Code.Ldarga_S:
                op.Register1 = baseRegIdx++;
                op.Register2 = (short)((ParameterDefinition)ins.Operand).Index;
                if (def.HasThis)
                {
                    op.Register2++;
                }
                break;

            case Code.Starg:
            case Code.Starg_S:
                op.Code      = OpCodes.OpCodeREnum.Move;
                op.Register2 = --baseRegIdx;
                op.Register1 = (short)((ParameterDefinition)ins.Operand).Index;
                if (def.HasThis)
                {
                    op.Register1++;
                }
                break;

            case Code.Newarr:
                op.Register1 = (short)(baseRegIdx - 1);
                op.Register2 = (short)(baseRegIdx - 1);
                op.Operand   = method.GetTypeTokenHashCode(token);
                break;

            case Code.Dup:
                op.Code      = OpCodes.OpCodeREnum.Move;
                op.Register2 = (short)(baseRegIdx - 1);
                op.Register1 = baseRegIdx++;
                break;

            case Code.Stelem_I:
            case Code.Stelem_I1:
            case Code.Stelem_I2:
            case Code.Stelem_I4:
            case Code.Stelem_I8:
            case Code.Stelem_R4:
            case Code.Stelem_R8:
            case Code.Stelem_Ref:
            case Code.Stelem_Any:
                op.Register1 = (short)(baseRegIdx - 3);
                op.Register2 = (short)(baseRegIdx - 2);
                op.Register3 = (short)(baseRegIdx - 1);
                baseRegIdx  -= 3;
                break;

            case Code.Stind_I:
            case Code.Stind_I1:
            case Code.Stind_I2:
            case Code.Stind_I4:
            case Code.Stind_I8:
            case Code.Stind_R4:
            case Code.Stind_R8:
            case Code.Stind_Ref:
                op.Register1 = (short)(baseRegIdx - 2);
                op.Register2 = (short)(baseRegIdx - 1);
                baseRegIdx  -= 2;
                break;

            case Code.Stobj:
                op.Register1 = (short)(baseRegIdx - 2);
                op.Register2 = (short)(baseRegIdx - 1);
                op.Operand   = method.GetTypeTokenHashCode(token);
                baseRegIdx  -= 2;
                break;

            case Code.Conv_I:
            case Code.Conv_I1:
            case Code.Conv_I2:
            case Code.Conv_I4:
            case Code.Conv_I8:
            case Code.Conv_Ovf_I:
            case Code.Conv_Ovf_I1:
            case Code.Conv_Ovf_I1_Un:
            case Code.Conv_Ovf_I2:
            case Code.Conv_Ovf_I2_Un:
            case Code.Conv_Ovf_I4:
            case Code.Conv_Ovf_I4_Un:
            case Code.Conv_Ovf_I8:
            case Code.Conv_Ovf_I8_Un:
            case Code.Conv_Ovf_I_Un:
            case Code.Conv_Ovf_U:
            case Code.Conv_Ovf_U1:
            case Code.Conv_Ovf_U1_Un:
            case Code.Conv_Ovf_U2:
            case Code.Conv_Ovf_U2_Un:
            case Code.Conv_Ovf_U4:
            case Code.Conv_Ovf_U4_Un:
            case Code.Conv_Ovf_U8:
            case Code.Conv_Ovf_U8_Un:
            case Code.Conv_Ovf_U_Un:
            case Code.Conv_R4:
            case Code.Conv_R8:
            case Code.Conv_R_Un:
            case Code.Conv_U:
            case Code.Conv_U1:
            case Code.Conv_U2:
            case Code.Conv_U4:
            case Code.Conv_U8:
            case Code.Ldlen:
            case Code.Ldind_I:
            case Code.Ldind_I2:
            case Code.Ldind_I4:
            case Code.Ldind_I8:
            case Code.Ldind_R4:
            case Code.Ldind_R8:
            case Code.Ldind_U1:
            case Code.Ldind_U2:
            case Code.Ldind_U4:
            case Code.Ldind_Ref:
            case Code.Neg:
            case Code.Not:
                op.Register1 = (short)(baseRegIdx - 1);
                op.Register2 = (short)(baseRegIdx - 1);
                break;

            case Code.Ldobj:
                op.Register1 = (short)(baseRegIdx - 1);
                op.Register2 = (short)(baseRegIdx - 1);
                op.Operand   = method.GetTypeTokenHashCode(token);
                break;

            case Code.Ldfld:
            case Code.Ldflda:
                op.Register1   = (short)(baseRegIdx - 1);
                op.Register2   = (short)(baseRegIdx - 1);
                op.OperandLong = appdomain.GetStaticFieldIndex(token, declaringType, method);
                break;

            case Code.Stfld:
                op.Register1   = (short)(baseRegIdx - 2);
                op.Register2   = (short)(baseRegIdx - 1);
                op.OperandLong = appdomain.GetStaticFieldIndex(token, declaringType, method);
                baseRegIdx    -= 2;
                break;

            case Code.Box:
            case Code.Unbox:
            case Code.Unbox_Any:
            case Code.Isinst:
                op.Register1 = (short)(baseRegIdx - 1);
                op.Register2 = (short)(baseRegIdx - 1);
                op.Operand   = method.GetTypeTokenHashCode(token);
                break;

            case Code.Constrained:
                op.Operand = method.GetTypeTokenHashCode(token);
                break;

            case Code.Ldtoken:
                op.Register1 = baseRegIdx++;
                if (token is FieldReference)
                {
                    op.Operand     = 0;
                    op.OperandLong = appdomain.GetStaticFieldIndex(token, declaringType, method);
                }
                else if (token is TypeReference)
                {
                    op.Operand     = 1;
                    op.OperandLong = method.GetTypeTokenHashCode(token);
                }
                else
                {
                    throw new NotImplementedException();
                }
                break;

            case Code.Ldftn:
            {
                op.Register1 = baseRegIdx++;
                bool     hasReturn, canInline, isILMethod;
                ILMethod toInline;
                IMethod  m;
                InitializeFunctionParam(ref op, token, out hasReturn, out canInline, out m, out toInline, out isILMethod);
            }
            break;

            case Code.Ldvirtftn:
            {
                bool     hasReturn, canInline, isILMethod;
                ILMethod toInline;
                IMethod  m;
                InitializeFunctionParam(ref op, token, out hasReturn, out canInline, out m, out toInline, out isILMethod);
                op.Register1 = (short)(baseRegIdx - 1);
                op.Register2 = (short)(baseRegIdx - 1);
            }
            break;

            case Code.Pop:
                baseRegIdx--;
                op.Code = OpCodeREnum.Nop;
                break;

            default:
                throw new NotImplementedException(string.Format("Unknown Opcode:{0}", code.Code));
            }
            RegisterVMSymbol s = new RegisterVMSymbol()
            {
                Instruction = ins,
                Method      = method
            };
            block.InstructionMapping.Add(lst.Count, s);
            lst.Add(op);
        }
Пример #6
0
        public                        OpCodeR[] Compile(out int stackRegisterCnt, out Dictionary <int, int[]> switchTargets, Dictionary <Instruction, int> addr, out Dictionary <int, RegisterVMSymbol> symbols)
        {
#if DEBUG && !NO_PROFILER
            if (System.Threading.Thread.CurrentThread.ManagedThreadId == method.AppDomain.UnityMainThreadID)

#if UNITY_5_5_OR_NEWER
            { UnityEngine.Profiling.Profiler.BeginSample("JITCompiler.Compile"); }
#else
            { UnityEngine.Profiler.BeginSample("JITCompiler.Compile"); }
#endif
#endif
            method.Compiling = true;
            symbols          = new Dictionary <int, RegisterVMSymbol>();

            var   body           = def.Body;
            short locVarRegStart = (short)def.Parameters.Count;
            if (!def.IsStatic)
            {
                locVarRegStart++;
            }
            short baseRegIdx   = (short)(locVarRegStart + body.Variables.Count);
            short baseRegStart = baseRegIdx;

            var blocks = CodeBasicBlock.BuildBasicBlocks(body, out entryMapping);

            foreach (var i in blocks)
            {
                baseRegIdx = baseRegStart;
                if (IsCatchHandler(i, body))
                {
                    baseRegIdx++;
                }
                else
                {
                    if (i.PreviousBlocks.Count > 0)
                    {
                        foreach (var j in i.PreviousBlocks)
                        {
                            if (j.EndRegister >= 0)
                            {
                                baseRegIdx = j.EndRegister;
                                break;
                            }
                        }
                    }
                }
                foreach (var ins in i.Instructions)
                {
                    Translate(i, ins, locVarRegStart, ref baseRegIdx);
                }
                i.EndRegister = baseRegIdx;
            }

            //Append init local
            var first     = blocks[0];
            int idx       = 0;
            int appendIdx = 0;
            HashSet <CodeBasicBlock> visitedBlocks = body.Variables.Count > 0 ? new HashSet <CodeBasicBlock>() : null;
            for (short r = locVarRegStart; r < locVarRegStart + body.Variables.Count; r++)
            {
                visitedBlocks.Clear();
                if (CheckNeedInitObj(first, r, method.ReturnType != method.AppDomain.VoidType, visitedBlocks))
                {
                    OpCodeR code = new OpCodeR();
                    code.Code      = OpCodeREnum.Initobj;
                    code.Register1 = r;
                    code.Operand   = method.GetTypeTokenHashCode(body.Variables[idx].VariableType);
                    code.Operand2  = 1;
                    first.FinalInstructions.Insert(appendIdx++, code);
                }
                idx++;
            }
            for (idx = first.FinalInstructions.Count - 1; idx >= 0; idx--)
            {
                if (idx >= appendIdx)
                {
                    RegisterVMSymbol symbol;

                    if (first.InstructionMapping.TryGetValue(idx - appendIdx, out symbol))
                    {
                        first.InstructionMapping[idx] = first.InstructionMapping[idx - appendIdx];
                    }
                }
                else
                {
                    first.InstructionMapping.Remove(idx);
                }
            }

#if OUTPUT_JIT_RESULT
            int cnt = 1;
            Console.WriteLine($"JIT Results for {method}:");
            foreach (var b in blocks)
            {
                Console.WriteLine($"Block {cnt++}, Instructions:{b.FinalInstructions.Count}");
                for (int i = 0; i < b.FinalInstructions.Count; i++)
                {
                    Console.WriteLine($"    {i}:{b.FinalInstructions[i].ToString(appdomain)}");
                }
            }
#endif

            Optimizer.ForwardCopyPropagation(blocks, hasReturn, baseRegStart);
            Optimizer.BackwardsCopyPropagation(blocks, hasReturn, baseRegStart);
            Optimizer.ForwardCopyPropagation(blocks, hasReturn, baseRegStart);

#if OUTPUT_JIT_RESULT
            cnt = 1;
            Console.WriteLine($"Optimizer Results for {method}:");
            foreach (var b in blocks)
            {
                Console.WriteLine($"Block {cnt++}, Instructions:{b.FinalInstructions.Count}");
                for (int i = 0; i < b.FinalInstructions.Count; i++)
                {
                    string canRemove = b.CanRemove.Contains(i) ? "(x)" : "";
                    Console.WriteLine($"    {i}:{canRemove}{b.FinalInstructions[i].ToString(appdomain)}");
                }
            }
#endif

            List <OpCodeR>        res         = new List <OpCodeR>();
            Dictionary <int, int> jumpTargets = new Dictionary <int, int>();
            int           bIdx            = 0;
            HashSet <int> inlinedBranches = new HashSet <int>();
            int           curIndex        = 0;
            foreach (var b in blocks)
            {
                jumpTargets[bIdx++] = res.Count;
                bool isInline         = false;
                int  inlineOffset     = 0;
                bool inlineAddressSet = false;
                for (idx = 0; idx < b.FinalInstructions.Count; idx++)
                {
                    RegisterVMSymbol oriIns;
                    bool             hasOri = b.InstructionMapping.TryGetValue(idx, out oriIns);
                    if (hasOri)
                    {
                        if (isInline)
                        {
                            if (!inlineAddressSet)
                            {
                                while (oriIns.ParentSymbol != null)
                                {
                                    oriIns = oriIns.ParentSymbol.Value;
                                }
                                addr[oriIns.Instruction] = curIndex;
                                inlineAddressSet         = true;
                            }
                        }
                        else
                        {
                            addr[oriIns.Instruction] = curIndex;
                        }
                    }
                    if (b.CanRemove.Contains(idx))
                    {
                        if (isInline)
                        {
                            inlineOffset--;
                        }
                        continue;
                    }
                    var ins = b.FinalInstructions[idx];
                    if (ins.Code == OpCodeREnum.InlineStart)
                    {
                        inlineAddressSet = false;
                        isInline         = true;
                        inlineOffset     = res.Count;
                    }
                    else if (ins.Code == OpCodeREnum.InlineEnd)
                    {
                        isInline = false;
                    }
                    else
                    {
                        if (isInline)
                        {
                            if (Optimizer.IsBranching(ins.Code))
                            {
                                ins.Operand += inlineOffset;
                                inlinedBranches.Add(res.Count);
                            }
                            else if (ins.Code == OpCodeREnum.Switch)
                            {
                                int[] targets = jumptables[ins.Operand];
                                for (int j = 0; j < targets.Length; j++)
                                {
                                    targets[j] = targets[j] + inlineOffset;
                                }
                                inlinedBranches.Add(res.Count);
                            }
                        }
                        if (hasOri)
                        {
                            symbols.Add(res.Count, oriIns);
                        }
                        curIndex++;
                        res.Add(ins);
                    }
                }
            }
            for (int i = 0; i < res.Count; i++)
            {
                var op = res[i];
                if (Optimizer.IsBranching(op.Code) && !inlinedBranches.Contains(i))
                {
                    op.Operand = jumpTargets[op.Operand];
                    res[i]     = op;
                }
                else if (op.Code == OpCodeREnum.Switch && !inlinedBranches.Contains(i))
                {
                    int[] targets = jumptables[op.Operand];
                    for (int j = 0; j < targets.Length; j++)
                    {
                        targets[j] = jumpTargets[targets[j]];
                    }
                }
                else if (op.Code == OpCodeREnum.Leave || op.Code == OpCodeREnum.Leave_S)
                {
                    var oriIns = symbols[i];
                    op.Operand = addr[(Instruction)oriIns.Instruction.Operand];
                    res[i]     = op;
                }
            }
#if DEBUG && !DISABLE_ILRUNTIME_DEBUG
            //FixSymbol(symbols);
#else
            symbols = null;
#endif
            switchTargets = jumptables;
            var totalRegCnt = Optimizer.CleanupRegister(res, locVarRegStart, hasReturn);
            stackRegisterCnt = totalRegCnt - baseRegStart;
#if OUTPUT_JIT_RESULT
            Console.WriteLine($"Final Results for {method}:");

            for (int i = 0; i < res.Count; i++)
            {
                Console.WriteLine($"    {i}:{res[i].ToString(appdomain)}");
            }
#endif
            method.Compiling = false;
            var arr = res.ToArray();
#if DEBUG && !NO_PROFILER
            if (System.Threading.Thread.CurrentThread.ManagedThreadId == method.AppDomain.UnityMainThreadID)
#if UNITY_5_5_OR_NEWER
            { UnityEngine.Profiling.Profiler.EndSample(); }
#else
            { UnityEngine.Profiler.EndSample(); }
#endif
#endif
            return(arr);
        }
Пример #7
0
        public static void EliminateConstantLoad(List <CodeBasicBlock> blocks, bool hasReturn)
        {
            foreach (var b in blocks)
            {
                if (!b.NeedLoadConstantElimination)
                {
                    continue;
                }
                var           lst       = b.FinalInstructions;
                HashSet <int> canRemove = b.CanRemove;
                //HashSet<int> pendingBCP = b.PendingCP;
                bool isInline = false;
                for (int i = 0; i < lst.Count; i++)
                {
                    OpCodeR X = lst[i];
                    if (X.Code == OpCodeREnum.InlineStart)
                    {
                        isInline = true;
                        continue;
                    }
                    if (X.Code == OpCodeREnum.InlineEnd)
                    {
                        isInline = false;
                        continue;
                    }
                    if (isInline)
                    {
                        continue;
                    }
                    if (IsLoadConstant(X.Code))
                    {
                        short xDst;
                        GetOpcodeDestRegister(ref X, out xDst);

                        bool propagationInline = false;
                        for (int j = i + 1; j < lst.Count; j++)
                        {
                            OpCodeR Y = lst[j];
                            if (Y.Code == OpCodeREnum.InlineStart)
                            {
                                propagationInline = true;
                            }
                            else if (Y.Code == OpCodeREnum.InlineEnd)
                            {
                                propagationInline = false;
                            }
                            short r1, r2, r3;
                            GetOpcodeSourceRegister(ref Y, hasReturn, out r1, out r2, out r3);
                            if (r1 == xDst || r2 == xDst || r3 == xDst)
                            {
                                if (SupportIntemediateValue(Y.Code))
                                {
                                    if (r2 == xDst)
                                    {
                                        if (!propagationInline)
                                        {
                                            Y.Code = GetIntemediateValueOpcode(Y.Code);
                                            ReplaceRegisterWithConstant(ref Y, ref X);
                                            lst[j] = Y;
                                            canRemove.Add(i);
                                        }
                                    }
                                    else if (r1 == xDst)
                                    {
                                        if (!propagationInline)
                                        {
                                            if (SupportOperandSwap(Y.Code))
                                            {
                                                ReplaceOpcodeSource(ref Y, 0, r2);
                                                Y.Code = GetIntemediateValueOpcode(Y.Code);
                                                ReplaceRegisterWithConstant(ref Y, ref X);
                                                lst[j] = Y;
                                                canRemove.Add(i);
                                            }
                                            else if (HasInverseOpcode(Y.Code))
                                            {
                                                ReplaceOpcodeSource(ref Y, 0, r2);
                                                Y.Code = GetIntemediateValueOpcode(GetInverseOpcode(Y.Code));
                                                ReplaceRegisterWithConstant(ref Y, ref X);
                                                lst[j] = Y;
                                                canRemove.Add(i);
                                            }
                                        }
                                    }
                                }
                                break;
                            }
                            short yDst;
                            GetOpcodeDestRegister(ref Y, out yDst);
                            if (yDst == xDst)
                            {
                                break;
                            }
                        }
                    }
                }
            }
        }