Exemplo n.º 1
0
        protected override void PrepareImpl(CompilerContext cc)
        {
            Offset = cc.CurrentOffset;

            InstructionDescription id = InstructionDescription.FromInstruction(_code);

            int i;
            int len = _operands.Length;
            int variablesCount = 0;

            for (i = 0; i < len; i++)
            {
                Operand o = _operands[i];

                BaseVar vo = o as BaseVar;
                if (vo != null)
                {
                    if (o.Id == InvalidValue)
                        throw new CompilerException();

                    CompilerVar vdata = Compiler.GetVarData(o.Id);
                    Contract.Assert(vdata != null);

                    if (vo.IsGPVar)
                    {
                        if (((GPVar)vo).IsGPBLo)
                        {
                            _isGPBLoUsed = true;
                            vdata.RegisterGPBLoCount++;
                        }

                        if (((GPVar)vo).IsGPBHi)
                        {
                            _isGPBHiUsed = true;
                            vdata.RegisterGPBHiCount++;
                        }
                    }

                    if (vdata.WorkOffset != Offset)
                    {
                        if (!cc.IsActive(vdata))
                            cc.AddActive(vdata);

                        vdata.WorkOffset = Offset;
                        variablesCount++;
                    }
                }
                else
                {
                    Mem mem = o as Mem;
                    if (mem != null)
                    {
                        if ((o.Id & Operand.OperandIdTypeMask) == Operand.OperandIdTypeVar)
                        {
                            CompilerVar vdata = Compiler.GetVarData(o.Id);
                            Contract.Assert(vdata != null);

                            cc.MarkMemoryUsed(vdata);
                            if (vdata.WorkOffset != Offset)
                            {
                                if (!cc.IsActive(vdata))
                                    cc.AddActive(vdata);

                                vdata.WorkOffset = Offset;
                                variablesCount++;
                            }
                        }
                        else if (((int)mem.Base & Operand.OperandIdTypeMask) == Operand.OperandIdTypeVar)
                        {
                            CompilerVar vdata = Compiler.GetVarData((int)mem.Base);
                            Contract.Assert(vdata != null);

                            if (vdata.WorkOffset != Offset)
                            {
                                if (!cc.IsActive(vdata))
                                    cc.AddActive(vdata);

                                vdata.WorkOffset = Offset;
                                variablesCount++;
                            }
                        }

                        if (((int)mem.Index & Operand.OperandIdTypeMask) == Operand.OperandIdTypeVar)
                        {
                            CompilerVar vdata = Compiler.GetVarData((int)mem.Index);
                            Contract.Assert(vdata != null);

                            if (vdata.WorkOffset != Offset)
                            {
                                if (!cc.IsActive(vdata))
                                    cc.AddActive(vdata);

                                vdata.WorkOffset = Offset;
                                variablesCount++;
                            }
                        }
                    }
                }
            }

            if (variablesCount == 0)
            {
                cc.CurrentOffset++;
                return;
            }

            _variables = new VarAllocRecord[variablesCount];
            for (int j = 0; j < variablesCount; j++)
                _variables[j] = new VarAllocRecord();

            int curIndex = 0;
            VarAllocRecord var = null;
            int varIndex = -1;

            Action<CompilerVar> __GET_VARIABLE =
                __vardata__ =>
                {
                    CompilerVar candidate = __vardata__;

                    for (varIndex = curIndex; ; )
                    {
                        if (varIndex == 0)
                        {
                            varIndex = curIndex++;
                            _variables[varIndex].VarData = candidate;
                            _variables[varIndex].VarFlags = 0;
                            _variables[varIndex].RegMask = RegisterMask.All;
                            break;
                        }

                        varIndex--;

                        if (_variables[varIndex].VarData == candidate)
                            break;
                    }

                    var = _variables[varIndex];
                    if (var == null)
                        throw new CompilerException();
                };

            bool _isGPBUsed = _isGPBLoUsed | _isGPBHiUsed;
            RegisterMask gpRestrictMask = RegisterMask.MaskToIndex(RegNum.GP);

            if (_isGPBHiUsed && Util.IsX64)
            {
                gpRestrictMask &= RegisterMask.FromIndex(RegIndex.Eax) |
                                  RegisterMask.FromIndex(RegIndex.Ebx) |
                                  RegisterMask.FromIndex(RegIndex.Ecx) |
                                  RegisterMask.FromIndex(RegIndex.Edx) |
                                  RegisterMask.FromIndex(RegIndex.Ebp) |
                                  RegisterMask.FromIndex(RegIndex.Esi) |
                                  RegisterMask.FromIndex(RegIndex.Edi);
            }

            for (i = 0; i < len; i++)
            {
                Operand o = _operands[i];

                if (o.IsVar)
                {
                    CompilerVar vdata = Compiler.GetVarData(o.Id);
                    Contract.Assert(vdata != null);

                    __GET_VARIABLE(vdata);
                    var.VarFlags |= VariableAlloc.Register;

                    if (_isGPBUsed)
                    {
                        if (Util.IsX64)
                        {
                            if (((GPVar)o).IsGPB)
                            {
                                var.RegMask &= RegisterMask.FromIndex(RegIndex.Eax) |
                                               RegisterMask.FromIndex(RegIndex.Ebx) |
                                               RegisterMask.FromIndex(RegIndex.Ecx) |
                                               RegisterMask.FromIndex(RegIndex.Edx);
                            }
                        }
                        else
                        {
                            // Restrict all BYTE registers to RAX/RBX/RCX/RDX if HI BYTE register
                            // is used (REX prefix makes HI BYTE addressing unencodable).
                            if (_isGPBHiUsed)
                            {
                                if (((GPVar)o).IsGPB)
                                {
                                    var.RegMask &= RegisterMask.FromIndex(RegIndex.Eax) |
                                                   RegisterMask.FromIndex(RegIndex.Ebx) |
                                                   RegisterMask.FromIndex(RegIndex.Ecx) |
                                                   RegisterMask.FromIndex(RegIndex.Edx);
                                }
                            }
                        }
                    }

                    if (IsSpecial)
                    {
                        // ${SPECIAL_INSTRUCTION_HANDLING_BEGIN}
                        switch (_code)
                        {
                        case InstructionCode.Cpuid:
                            switch (i)
                            {
                            case 0:
                                vdata.RegisterRWCount++;
                                var.VarFlags |= VariableAlloc.ReadWrite | VariableAlloc.Special;
                                var.RegMask = RegisterMask.FromIndex(RegIndex.Eax);
                                gpRestrictMask &= ~var.RegMask;
                                break;

                            case 1:
                                vdata.RegisterWriteCount++;
                                var.VarFlags |= VariableAlloc.Write | VariableAlloc.Special;
                                var.RegMask = RegisterMask.FromIndex(RegIndex.Ebx);
                                gpRestrictMask &= ~var.RegMask;
                                break;

                            case 2:
                                vdata.RegisterWriteCount++;
                                var.VarFlags |= VariableAlloc.Write | VariableAlloc.Special;
                                var.RegMask = RegisterMask.FromIndex(RegIndex.Ecx);
                                gpRestrictMask &= ~var.RegMask;
                                break;

                            case 3:
                                vdata.RegisterWriteCount++;
                                var.VarFlags |= VariableAlloc.Write | VariableAlloc.Special;
                                var.RegMask = RegisterMask.FromIndex(RegIndex.Edx);
                                gpRestrictMask &= ~var.RegMask;
                                break;

                            default:
                                throw new NotSupportedException(string.Format("The {0} instruction does not support {1} arguments.", InstructionDescription.FromInstruction(_code).Name, i));
                            }
                            break;

                        case InstructionCode.Cbw:
                        case InstructionCode.Cdqe:
                        case InstructionCode.Cwde:
                            switch (i)
                            {
                            case 0:
                                vdata.RegisterRWCount++;
                                var.VarFlags |= VariableAlloc.ReadWrite | VariableAlloc.Special;
                                var.RegMask = RegisterMask.FromIndex(RegIndex.Eax);
                                gpRestrictMask &= ~var.RegMask;
                                break;

                            default:
                                throw new NotSupportedException(string.Format("The {0} instruction does not support {1} arguments.", InstructionDescription.FromInstruction(_code).Name, i));
                            }
                            break;

                        case InstructionCode.Cdq:
                        case InstructionCode.Cqo:
                        case InstructionCode.Cwd:
                            switch (i)
                            {
                            case 0:
                                vdata.RegisterReadCount++;
                                var.VarFlags |= VariableAlloc.Read | VariableAlloc.Special;
                                var.RegMask = RegisterMask.FromIndex(RegIndex.Eax);
                                gpRestrictMask &= ~var.RegMask;
                                break;

                            case 1:
                                vdata.RegisterWriteCount++;
                                var.VarFlags |= VariableAlloc.Write | VariableAlloc.Special;
                                var.RegMask = RegisterMask.FromIndex(RegIndex.Edx);
                                gpRestrictMask &= ~var.RegMask;
                                break;

                            default:
                                throw new NotSupportedException(string.Format("The {0} instruction does not support {1} arguments.", InstructionDescription.FromInstruction(_code).Name, i));
                            }
                            break;

                        case InstructionCode.Cmpxchg:
                            switch (i)
                            {
                            case 0:
                                vdata.RegisterRWCount++;
                                var.VarFlags |= VariableAlloc.ReadWrite | VariableAlloc.Special;
                                var.RegMask = RegisterMask.FromIndex(RegIndex.Eax);
                                gpRestrictMask &= ~var.RegMask;
                                break;
                            case 1:
                                vdata.RegisterRWCount++;
                                var.VarFlags |= VariableAlloc.ReadWrite;
                                break;
                            case 2:
                                vdata.RegisterReadCount++;
                                var.VarFlags |= VariableAlloc.Read;
                                break;

                            default:
                                throw new NotSupportedException(string.Format("The {0} instruction does not support {1} arguments.", InstructionDescription.FromInstruction(_code).Name, i));
                            }
                            break;

                        case InstructionCode.Cmpxchg8b:
                        case InstructionCode.Cmpxchg16b:
                            if (_code == InstructionCode.Cmpxchg16b && !Util.IsX64)
                                throw new NotSupportedException(string.Format("The '{0}' instruction is only supported on X64.", _code));

                            switch (i)
                            {
                            case 0:
                                vdata.RegisterRWCount++;
                                var.VarFlags |= VariableAlloc.ReadWrite | VariableAlloc.Special;
                                var.RegMask = RegisterMask.FromIndex(RegIndex.Edx);
                                gpRestrictMask &= ~var.RegMask;
                                break;

                            case 1:
                                vdata.RegisterRWCount++;
                                var.VarFlags |= VariableAlloc.ReadWrite | VariableAlloc.Special;
                                var.RegMask = RegisterMask.FromIndex(RegIndex.Eax);
                                gpRestrictMask &= ~var.RegMask;
                                break;

                            case 2:
                                vdata.RegisterReadCount++;
                                var.VarFlags |= VariableAlloc.Read | VariableAlloc.Special;
                                var.RegMask = RegisterMask.FromIndex(RegIndex.Ecx);
                                gpRestrictMask &= ~var.RegMask;
                                break;

                            case 3:
                                vdata.RegisterReadCount++;
                                var.VarFlags |= VariableAlloc.Read | VariableAlloc.Special;
                                var.RegMask = RegisterMask.FromIndex(RegIndex.Ebx);
                                gpRestrictMask &= ~var.RegMask;
                                break;

                            default:
                                throw new NotSupportedException(string.Format("The {0} instruction does not support {1} arguments.", InstructionDescription.FromInstruction(_code).Name, i));
                            }
                            break;

                        case InstructionCode.Daa:
                        case InstructionCode.Das:
                            if (!Util.IsX86)
                                throw new NotSupportedException(string.Format("The '{0}' instruction is only supported on X86.", _code));

                            if (i != 0)
                                throw new NotSupportedException(string.Format("The {0} instruction does not support {1} arguments.", InstructionDescription.FromInstruction(_code).Name, i));

                            vdata.RegisterRWCount++;
                            var.VarFlags |= VariableAlloc.ReadWrite | VariableAlloc.Special;
                            var.RegMask = RegisterMask.FromIndex(RegIndex.Eax);
                            gpRestrictMask &= ~var.RegMask;
                            break;

                        case InstructionCode.Imul:
                        case InstructionCode.Mul:
                        case InstructionCode.Idiv:
                        case InstructionCode.Div:
                            switch (i)
                            {
                            case 0:
                                vdata.RegisterWriteCount++;
                                var.VarFlags |= VariableAlloc.Write | VariableAlloc.Special;
                                var.RegMask = RegisterMask.FromIndex(RegIndex.Edx);
                                gpRestrictMask &= ~var.RegMask;
                                break;
                            case 1:
                                vdata.RegisterRWCount++;
                                var.VarFlags |= VariableAlloc.ReadWrite | VariableAlloc.Special;
                                var.RegMask = RegisterMask.FromIndex(RegIndex.Eax);
                                gpRestrictMask &= ~var.RegMask;
                                break;
                            case 2:
                                vdata.RegisterReadCount++;
                                var.VarFlags |= VariableAlloc.Read;
                                break;

                            default:
                                throw new NotSupportedException(string.Format("The {0} instruction does not support {1} arguments.", InstructionDescription.FromInstruction(_code).Name, i));
                            }
                            break;

                        case InstructionCode.MovPtr:
                            switch (i)
                            {
                            case 0:
                                vdata.RegisterWriteCount++;
                                var.VarFlags |= VariableAlloc.Write | VariableAlloc.Special;
                                var.RegMask = RegisterMask.FromIndex(RegIndex.Eax);
                                gpRestrictMask &= ~var.RegMask;
                                break;
                            case 1:
                                vdata.RegisterReadCount++;
                                var.VarFlags |= VariableAlloc.Read | VariableAlloc.Special;
                                var.RegMask = RegisterMask.FromIndex(RegIndex.Eax);
                                gpRestrictMask &= ~var.RegMask;
                                break;
                            default:
                                throw new NotSupportedException(string.Format("The {0} instruction does not support {1} arguments.", InstructionDescription.FromInstruction(_code).Name, i));
                            }
                            break;

                        case InstructionCode.Lahf:
                            if (i != 0)
                                throw new NotSupportedException(string.Format("The {0} instruction does not support {1} arguments.", InstructionDescription.FromInstruction(_code).Name, i));

                            vdata.RegisterWriteCount++;
                            var.VarFlags |= VariableAlloc.Write | VariableAlloc.Special;
                            var.RegMask = RegisterMask.FromIndex(RegIndex.Eax);
                            gpRestrictMask &= ~var.RegMask;
                            break;

                        case InstructionCode.Sahf:
                            if (i != 0)
                                throw new NotSupportedException(string.Format("The {0} instruction does not support {1} arguments.", InstructionDescription.FromInstruction(_code).Name, i));

                            vdata.RegisterReadCount++;
                            var.VarFlags |= VariableAlloc.Read | VariableAlloc.Special;
                            var.RegMask = RegisterMask.FromIndex(RegIndex.Eax);
                            gpRestrictMask &= ~var.RegMask;
                            break;

                        case InstructionCode.Maskmovdqu:
                        case InstructionCode.Maskmovq:
                            switch (i)
                            {
                            case 0:
                                vdata.MemoryReadCount++;
                                var.VarFlags |= VariableAlloc.Read | VariableAlloc.Special;
                                var.RegMask = RegisterMask.FromIndex(RegIndex.Edi);
                                gpRestrictMask &= ~var.RegMask;
                                break;

                            case 1:
                            case 2:
                                vdata.MemoryReadCount++;
                                var.VarFlags |= VariableAlloc.Read;
                                break;

                            default:
                                throw new NotSupportedException(string.Format("The {0} instruction does not support {1} arguments.", InstructionDescription.FromInstruction(_code).Name, i));
                            }
                            break;

                        case InstructionCode.Enter:
                        case InstructionCode.Leave:
                            // TODO: SPECIAL INSTRUCTION.
                            throw new NotImplementedException();

                        case InstructionCode.Ret:
                            // TODO: SPECIAL INSTRUCTION.
                            throw new NotImplementedException();

                        case InstructionCode.Monitor:
                        case InstructionCode.Mwait:
                            // TODO: MONITOR/MWAIT (COMPILER).
                            throw new NotImplementedException();

                        case InstructionCode.Pop:
                            // TODO: SPECIAL INSTRUCTION.
                            throw new NotImplementedException();

                        case InstructionCode.Popad:
                        case InstructionCode.Popfd:
                        case InstructionCode.Popfq:
                            // TODO: SPECIAL INSTRUCTION.
                            throw new NotImplementedException();

                        case InstructionCode.Push:
                            // TODO: SPECIAL INSTRUCTION.
                            throw new NotImplementedException();

                        case InstructionCode.Pushad:
                        case InstructionCode.Pushfd:
                        case InstructionCode.Pushfq:
                            // TODO: SPECIAL INSTRUCTION.
                            throw new NotImplementedException();

                        case InstructionCode.Rcl:
                        case InstructionCode.Rcr:
                        case InstructionCode.Rol:
                        case InstructionCode.Ror:
                        case InstructionCode.Sal:
                        case InstructionCode.Sar:
                        case InstructionCode.Shl:
                        case InstructionCode.Shr:
                            switch (i)
                            {
                            case 0:
                                vdata.RegisterRWCount++;
                                var.VarFlags |= VariableAlloc.ReadWrite;
                                break;
                            case 1:
                                vdata.RegisterReadCount++;
                                var.VarFlags |= VariableAlloc.Read | VariableAlloc.Special;
                                var.RegMask = RegisterMask.FromIndex(RegIndex.Ecx);
                                gpRestrictMask &= ~var.RegMask;
                                break;

                            default:
                                throw new NotSupportedException(string.Format("The {0} instruction does not support {1} arguments.", InstructionDescription.FromInstruction(_code).Name, i));
                            }
                            break;

                        case InstructionCode.Shld:
                        case InstructionCode.Shrd:
                            switch (i)
                            {
                            case 0:
                                vdata.RegisterRWCount++;
                                var.VarFlags |= VariableAlloc.ReadWrite;
                                break;
                            case 1:
                                vdata.RegisterReadCount++;
                                var.VarFlags |= VariableAlloc.Read;
                                break;
                            case 2:
                                vdata.RegisterReadCount++;
                                var.VarFlags |= VariableAlloc.Read | VariableAlloc.Special;
                                var.RegMask = RegisterMask.FromIndex(RegIndex.Ecx);
                                gpRestrictMask &= ~var.RegMask;
                                break;

                            default:
                                throw new NotSupportedException(string.Format("The {0} instruction does not support {1} arguments.", InstructionDescription.FromInstruction(_code).Name, i));
                            }
                            break;

                        case InstructionCode.Rdtsc:
                        case InstructionCode.Rdtscp:
                            switch (i)
                            {
                            case 0:
                                vdata.RegisterWriteCount++;
                                var.VarFlags |= VariableAlloc.Write | VariableAlloc.Special;
                                var.RegMask = RegisterMask.FromIndex(RegIndex.Edx);
                                gpRestrictMask &= ~var.RegMask;
                                break;

                            case 1:
                                vdata.RegisterWriteCount++;
                                var.VarFlags |= VariableAlloc.Write | VariableAlloc.Special;
                                var.RegMask = RegisterMask.FromIndex(RegIndex.Eax);
                                gpRestrictMask &= ~var.RegMask;
                                break;

                            case 2:
                                if (_code != InstructionCode.Rdtscp)
                                    throw new CompilerException();

                                vdata.RegisterWriteCount++;
                                var.VarFlags |= VariableAlloc.Write | VariableAlloc.Special;
                                var.RegMask = RegisterMask.FromIndex(RegIndex.Ecx);
                                gpRestrictMask &= ~var.RegMask;
                                break;

                            default:
                                throw new NotSupportedException(string.Format("The {0} instruction does not support {1} arguments.", InstructionDescription.FromInstruction(_code).Name, i));
                            }
                            break;

                        case InstructionCode.RepLodsb:
                        case InstructionCode.RepLodsd:
                        case InstructionCode.RepLodsq:
                        case InstructionCode.RepLodsw:
                            switch (i)
                            {
                            case 0:
                                vdata.RegisterWriteCount++;
                                var.VarFlags |= VariableAlloc.Write | VariableAlloc.Special;
                                var.RegMask = RegisterMask.FromIndex(RegIndex.Eax);
                                gpRestrictMask &= ~var.RegMask;
                                break;
                            case 1:
                                vdata.RegisterReadCount++;
                                var.VarFlags |= VariableAlloc.Read | VariableAlloc.Special;
                                var.RegMask = RegisterMask.FromIndex(RegIndex.Esi);
                                gpRestrictMask &= ~var.RegMask;
                                break;
                            case 2:
                                vdata.RegisterRWCount++;
                                var.VarFlags |= VariableAlloc.ReadWrite | VariableAlloc.Special;
                                var.RegMask = RegisterMask.FromIndex(RegIndex.Ecx);
                                gpRestrictMask &= ~var.RegMask;
                                break;
                            default:
                                throw new NotSupportedException(string.Format("The {0} instruction does not support {1} arguments.", InstructionDescription.FromInstruction(_code).Name, i));
                            }
                            break;

                        case InstructionCode.RepMovsb:
                        case InstructionCode.RepMovsd:
                        case InstructionCode.RepMovsq:
                        case InstructionCode.RepMovsw:
                        case InstructionCode.RepeCmpsb:
                        case InstructionCode.RepeCmpsd:
                        case InstructionCode.RepeCmpsq:
                        case InstructionCode.RepeCmpsw:
                        case InstructionCode.RepneCmpsb:
                        case InstructionCode.RepneCmpsd:
                        case InstructionCode.RepneCmpsq:
                        case InstructionCode.RepneCmpsw:
                            switch (i)
                            {
                            case 0:
                                vdata.RegisterReadCount++;
                                var.VarFlags |= VariableAlloc.Read | VariableAlloc.Special;
                                var.RegMask = RegisterMask.FromIndex(RegIndex.Edi);
                                gpRestrictMask &= ~var.RegMask;
                                break;
                            case 1:
                                vdata.RegisterReadCount++;
                                var.VarFlags |= VariableAlloc.Read | VariableAlloc.Special;
                                var.RegMask = RegisterMask.FromIndex(RegIndex.Esi);
                                gpRestrictMask &= ~var.RegMask;
                                break;
                            case 2:
                                vdata.RegisterRWCount++;
                                var.VarFlags |= VariableAlloc.ReadWrite | VariableAlloc.Special;
                                var.RegMask = RegisterMask.FromIndex(RegIndex.Ecx);
                                gpRestrictMask &= ~var.RegMask;
                                break;
                            default:
                                throw new NotSupportedException(string.Format("The {0} instruction does not support {1} arguments.", InstructionDescription.FromInstruction(_code).Name, i));
                            }
                            break;

                        case InstructionCode.RepStosb:
                        case InstructionCode.RepStosd:
                        case InstructionCode.RepStosq:
                        case InstructionCode.RepStosw:
                            switch (i)
                            {
                            case 0:
                                vdata.RegisterReadCount++;
                                var.VarFlags |= VariableAlloc.Read | VariableAlloc.Special;
                                var.RegMask = RegisterMask.FromIndex(RegIndex.Edi);
                                gpRestrictMask &= ~var.RegMask;
                                break;
                            case 1:
                                vdata.RegisterReadCount++;
                                var.VarFlags |= VariableAlloc.Read | VariableAlloc.Special;
                                var.RegMask = RegisterMask.FromIndex(RegIndex.Eax);
                                gpRestrictMask &= ~var.RegMask;
                                break;
                            case 2:
                                vdata.RegisterRWCount++;
                                var.VarFlags |= VariableAlloc.ReadWrite | VariableAlloc.Special;
                                var.RegMask = RegisterMask.FromIndex(RegIndex.Ecx);
                                gpRestrictMask &= ~var.RegMask;
                                break;
                            default:
                                throw new NotSupportedException(string.Format("The {0} instruction does not support {1} arguments.", InstructionDescription.FromInstruction(_code).Name, i));
                            }
                            break;

                        case InstructionCode.RepeScasb:
                        case InstructionCode.RepeScasd:
                        case InstructionCode.RepeScasq:
                        case InstructionCode.RepeScasw:
                        case InstructionCode.RepneScasb:
                        case InstructionCode.RepneScasd:
                        case InstructionCode.RepneScasq:
                        case InstructionCode.RepneScasw:
                            switch (i)
                            {
                            case 0:
                                vdata.RegisterReadCount++;
                                var.VarFlags |= VariableAlloc.Read | VariableAlloc.Special;
                                var.RegMask = RegisterMask.FromIndex(RegIndex.Edi);
                                gpRestrictMask &= ~var.RegMask;
                                break;
                            case 1:
                                vdata.RegisterReadCount++;
                                var.VarFlags |= VariableAlloc.Read | VariableAlloc.Special;
                                var.RegMask = RegisterMask.FromIndex(RegIndex.Eax);
                                gpRestrictMask &= ~var.RegMask;
                                break;
                            case 2:
                                vdata.RegisterRWCount++;
                                var.VarFlags |= VariableAlloc.ReadWrite | VariableAlloc.Special;
                                var.RegMask = RegisterMask.FromIndex(RegIndex.Ecx);
                                gpRestrictMask &= ~var.RegMask;
                                break;
                            default:
                                throw new NotSupportedException(string.Format("The {0} instruction does not support {1} arguments.", InstructionDescription.FromInstruction(_code).Name, i));
                            }
                            break;

                        default:
                            throw new NotImplementedException(string.Format("Handling for special instruction {0} is not yet implemented.", InstructionDescription.FromInstruction(_code).Name));
                        }
                        // ${SPECIAL_INSTRUCTION_HANDLING_END}
                    }
                    else
                    {
                        if (i == 0)
                        {
                            // CMP/TEST instruction.
                            if (id.Code == InstructionCode.Cmp || id.Code == InstructionCode.Test)
                            {
                                // Read-only case.
                                vdata.RegisterReadCount++;
                                var.VarFlags |= VariableAlloc.Read;
                            }
                            // CVTTSD2SI/CVTTSS2SI instructions.
                            else if (id.Code == InstructionCode.Cvttsd2si || id.Code == InstructionCode.Cvttss2si)
                            {
                                // In 32-bit mode the whole destination is replaced. In 64-bit mode
                                // we need to check whether the destination operand size is 64-bits.
                                if (Util.IsX86 || _operands[0].IsRegType(RegType.GPQ))
                                {
                                    // Write-only case.
                                    vdata.RegisterWriteCount++;
                                    var.VarFlags |= VariableAlloc.Write;
                                }
                                else if (Util.IsX64)
                                {
                                    // Read/Write.
                                    vdata.RegisterRWCount++;
                                    var.VarFlags |= VariableAlloc.ReadWrite;
                                }
                            }
                            // MOV/MOVSS/MOVSD instructions.
                            //
                            // If instruction is MOV (source replaces the destination) or
                            // MOVSS/MOVSD and source operand is memory location then register
                            // allocator should know that previous destination value is lost
                            // (write only operation).
                            else if ((id.IsMov) ||
                                    ((id.Code == InstructionCode.Movss || id.Code == InstructionCode.Movsd) /* && _operands[1].isMem() */) ||
                                    (id.Code == InstructionCode.Imul && _operands.Length == 3 && !IsSpecial))
                            {
                                // Write-only case.
                                vdata.RegisterWriteCount++;
                                var.VarFlags |= VariableAlloc.Write;
                            }
                            else if (id.Code == InstructionCode.Lea)
                            {
                                // Write.
                                vdata.RegisterWriteCount++;
                                var.VarFlags |= VariableAlloc.Write;
                            }
                            else
                            {
                                // Read/Write.
                                vdata.RegisterRWCount++;
                                var.VarFlags |= VariableAlloc.ReadWrite;
                            }
                        }
                        else
                        {
                            // Second, third, ... operands are read-only.
                            vdata.RegisterReadCount++;
                            var.VarFlags |= VariableAlloc.Read;
                        }

                        if (_memoryOperand == null && i < 2 && (id.OperandFlags[i] & OperandFlags.MEM) != 0)
                        {
                            var.VarFlags |= VariableAlloc.Memory;
                        }
                    }

                    // If variable must be in specific register we could add some hint to allocator.
                    if ((var.VarFlags & VariableAlloc.Special) != 0)
                    {
                        vdata.PreferredRegisterMask |= var.RegMask;
                        cc.NewRegisterHomeIndex(vdata, var.RegMask.FirstRegister);
                    }
                }
                else if (o.IsMem)
                {
                    Mem mem = (Mem)o;
                    if ((o.Id & Operand.OperandIdTypeMask) == Operand.OperandIdTypeVar)
                    {
                        CompilerVar vdata = Compiler.GetVarData(o.Id);
                        Contract.Assert(vdata != null);

                        __GET_VARIABLE(vdata);

                        if (i == 0)
                        {
                            // If variable is MOV instruction type (source replaces the destination)
                            // or variable is MOVSS/MOVSD instruction then register allocator should
                            // know that previous destination value is lost (write only operation).
                            if (id.IsMov || ((id.Code == InstructionCode.Movss || id.Code == InstructionCode.Movsd)))
                            {
                                // Write only case.
                                vdata.MemoryWriteCount++;
                            }
                            else
                            {
                                vdata.MemoryRWCount++;
                            }
                        }
                        else
                        {
                            vdata.MemoryReadCount++;
                        }
                    }
                    else if (((int)mem.Base & Operand.OperandIdTypeMask) == Operand.OperandIdTypeVar)
                    {
                        CompilerVar vdata = Compiler.GetVarData((int)mem.Base);
                        Contract.Assert(vdata != null);

                        __GET_VARIABLE(vdata);
                        vdata.RegisterReadCount++;
                        var.VarFlags |= VariableAlloc.Register | VariableAlloc.Read;
                        gpRestrictMask &= ~var.RegMask;
                    }

                    if (((int)mem.Index & Operand.OperandIdTypeMask) == Operand.OperandIdTypeVar)
                    {
                        CompilerVar vdata = Compiler.GetVarData((int)mem.Index);
                        Contract.Assert(vdata != null);

                        __GET_VARIABLE(vdata);
                        vdata.RegisterReadCount++;
                        var.VarFlags |= VariableAlloc.Register | VariableAlloc.Read;
                        gpRestrictMask &= ~var.RegMask;
                    }
                }
            }

            // Traverse all variables and update firstItem / lastItem. This
            // function is called from iterator that scans items using forward
            // direction so we can use this knowledge to optimize the process.
            //
            // Similar to ECall::prepare().
            for (i = 0; i < _variables.Length; i++)
            {
                CompilerVar v = _variables[i].VarData;

                // Update GP register allocator restrictions.
                if (VariableInfo.IsVariableInteger(v.Type))
                {
                    if (_variables[i].RegMask == RegisterMask.All)
                        _variables[i].RegMask &= gpRestrictMask;
                }

                // Update first/last item (begin of variable scope).
                if (v.FirstItem == null)
                    v.FirstItem = this;

                v.LastItem = this;
            }

            // There are some instructions that can be used to clear or to set all bits
            // in a register:
            //
            // - andn reg, reg        ; Set all bits in reg to 0.
            // - xor/pxor reg, reg    ; Set all bits in reg to 0.
            // - sub/psub reg, reg    ; Set all bits in reg to 0.
            // - pcmpgt reg, reg      ; Set all bits in reg to 0.
            // - pcmpeq reg, reg      ; Set all bits in reg to 1.
            //
            // There are also combinations which do nothing:
            //
            // - and reg, reg         ; Nop.
            // - or reg, reg          ; Nop.
            // - xchg reg, reg        ; Nop.

            if (_variables.Length == 1 && _operands.Length > 1 && _operands[0].IsVar && _operands[1].IsVar && _memoryOperand == null)
            {
                switch ((InstructionCode)_code)
                {
                // ----------------------------------------------------------------------
                // [Zeros/Ones]
                // ----------------------------------------------------------------------

                // ANDN Instructions.
                case InstructionCode.Pandn:

                // XOR Instructions.
                case InstructionCode.Xor:
                case InstructionCode.Xorpd:
                case InstructionCode.Xorps:
                case InstructionCode.Pxor:

                // SUB Instructions.
                case InstructionCode.Sub:
                case InstructionCode.Psubb:
                case InstructionCode.Psubw:
                case InstructionCode.Psubd:
                case InstructionCode.Psubq:
                case InstructionCode.Psubsb:
                case InstructionCode.Psubsw:
                case InstructionCode.Psubusb:
                case InstructionCode.Psubusw:

                // PCMPEQ Instructions.
                case InstructionCode.Pcmpeqb:
                case InstructionCode.Pcmpeqw:
                case InstructionCode.Pcmpeqd:
                case InstructionCode.Pcmpeqq:

                // PCMPGT Instructions.
                case InstructionCode.Pcmpgtb:
                case InstructionCode.Pcmpgtw:
                case InstructionCode.Pcmpgtd:
                case InstructionCode.Pcmpgtq:
                    // Clear the read flag. This prevents variable alloc/spill.
                    _variables[0].VarFlags = VariableAlloc.Write;
                    _variables[0].VarData.RegisterReadCount--;
                    break;

                // ----------------------------------------------------------------------
                // [Nop]
                // ----------------------------------------------------------------------

                // AND Instructions.
                case InstructionCode.And:
                case InstructionCode.Andpd:
                case InstructionCode.Andps:
                case InstructionCode.Pand:

                // OR Instructions.
                case InstructionCode.Or:
                case InstructionCode.Orpd:
                case InstructionCode.Orps:
                case InstructionCode.Por:

                // XCHG Instruction.
                case InstructionCode.Xchg:
                    // Clear the write flag.
                    _variables[0].VarFlags = VariableAlloc.Read;
                    _variables[0].VarData.RegisterWriteCount--;
                    break;
                }
            }
            cc.CurrentOffset++;
        }
Exemplo n.º 2
0
        public void UnuseVarOnEndOfScope(CompilerItem e, VarAllocRecord rec)
        {
            Contract.Requires(e != null);
            Contract.Requires(rec != null);
            Contract.Requires(rec.VarData != null);

            CompilerVar v = rec.VarData;
            if (v.LastItem == e || (rec.VarFlags & VariableAlloc.UnuseAfterUse) != 0)
                UnuseVar(v, VariableState.Unused);
        }