예제 #1
0
        internal void DoJump(CompilerContext cc)
        {
            Contract.Requires(cc != null);

            // The state have to be already known. The _doJump() method is called by
            // translate() or by Compiler in case that it's forward jump.
            if (_jumpTarget.State == null)
                throw new CompilerException("Cannot jump to a target without knowing its state.");

            if ((Code == InstructionCode.Jmp) || (IsTaken && _jumpTarget.Offset < Offset))
            {
                // Instruction type is JMP or conditional jump that should be taken (likely).
                // We can set state here instead of jumping out, setting state and jumping
                // to _jumpTarget.
                //
                // NOTE: We can't use this technique if instruction is forward conditional
                // jump. The reason is that when generating code we can't change state here,
                // because the next instruction depends on it.
                cc.RestoreState(_jumpTarget.State, _jumpTarget.Offset);
            }
            else
            {
                // Instruction type is JMP or conditional jump that should be not normally
                // taken. If we need add code that will switch between different states we
                // add it after the end of function body (after epilog, using 'ExtraBlock').
                Compiler compiler = cc.Compiler;

                CompilerItem ext = cc.ExtraBlock;
                CompilerItem old = compiler.CurrentItem;
                compiler.CurrentItem = ext;

                cc.RestoreState(_jumpTarget.State, _jumpTarget.Offset);

                if (compiler.CurrentItem != ext)
                {
                    // Add the jump to the target.
                    compiler.Jmp(_jumpTarget.Label);
                    ext = compiler.CurrentItem;

                    // The cc._restoreState() method emitted some instructions so we need to
                    // patch the jump.
                    Label L = compiler.DefineLabel();
                    compiler.CurrentItem = cc.ExtraBlock;
                    compiler.MarkLabel(L);

                    // Finally, patch the jump target.
                    if (Operands.Length == 0)
                        throw new CompilerException();

                    Operands[0] = L;                              // Operand part (Label).
                    _jumpTarget = compiler.GetTarget(L.Id); // Item part (ETarget).
                }

                cc.ExtraBlock = ext;
                compiler.CurrentItem = old;

                // Assign state back.
                cc.AssignState(_state);
            }
        }
예제 #2
0
        protected override void PrepareImpl(CompilerContext cc)
        {
            Offset = cc.CurrentOffset;

            // First item (begin of variable scope).
            if (_varData.FirstItem == null)
                _varData.FirstItem = this;

            CompilerItem oldLast = _varData.LastItem;

            // Last item (end of variable scope).
            _varData.LastItem = this;

            switch (_hintKind)
            {
            case VariableHintKind.Alloc:
            case VariableHintKind.Spill:
            case VariableHintKind.Save:
                if (!cc.IsActive(_varData))
                    cc.AddActive(_varData);
                break;

            case VariableHintKind.SaveAndUnuse:
                if (!cc.IsActive(_varData))
                    cc.AddActive(_varData);
                break;

            case VariableHintKind.Unuse:
                if (oldLast != null)
                    oldLast.TryUnuseVar(_varData);
                break;
            }
        }
예제 #3
0
        private RegIndex FindTemporaryGpRegister(CompilerContext cc, bool spillIfNecessary)
        {
            RegisterMask passedGP = Declaration.PassedGP;
            RegIndex candidate = RegIndex.Invalid;

            RegisterMask reserved = RegisterMask.FromIndex(RegIndex.Esp);
            if (!cc.AllocableEbp)
                reserved |= RegisterMask.FromIndex(RegIndex.Ebp);

            // Find all registers used to pass function arguments. We shouldn't use these
            // if possible.
            for (int i = 0; i < (int)RegNum.GP; i++)
            {
                RegisterMask mask = RegisterMask.FromIndex((RegIndex)i);
                if ((reserved & mask).RegisterCount != 0)
                    continue;

                if (cc.State.GP[i] == null)
                {
                    // If this register is used to pass arguments to function, we will mark
                    // it and use it only if there is no other one.
                    if ((passedGP & mask) != RegisterMask.Zero)
                        candidate = (RegIndex)i;
                    else
                        return (RegIndex)i;
                }
            }

            if (candidate == RegIndex.Invalid && spillIfNecessary)
            {
                for (int i = 0; i < (int)RegNum.GP; i++)
                {
                    RegisterMask mask = RegisterMask.FromIndex((RegIndex)i);
                    if ((reserved & mask).RegisterCount != 0)
                        continue;

                    candidate = (RegIndex)i;
                    if ((passedGP & mask) == RegisterMask.Zero)
                        break;

                    // If this register is used to pass arguments to function, we will mark
                    // it and use it only if there is no other one.
                    if ((passedGP & mask) != RegisterMask.Zero)
                        candidate = (RegIndex)i;
                    else
                        return (RegIndex)i;
                }

                Contract.Assert(cc.State.GP[(int)candidate] != null);
                cc.SpillGPVar(cc.State.GP[(int)candidate]);
            }

            return candidate;
        }
예제 #4
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++;
        }
예제 #5
0
        protected override void PrepareImpl(CompilerContext cc)
        {
            Offset = cc.CurrentOffset;

            // Update _isTaken to true if this is conditional backward jump. This behavior
            // can be overridden by using HINT_NOT_TAKEN when using the instruction.
            if ((Code != InstructionCode.Jmp)
                && Operands.Length == 1 && _jumpTarget.Offset < Offset)
            {
                _isTaken = true;
            }

            // Now patch all variables where jump location is in the active range.
            if (_jumpTarget.Offset != InvalidValue && cc.Active != null)
            {
                CompilerVar first = cc.Active;
                CompilerVar var = first;
                int jumpOffset = _jumpTarget.Offset;

                do
                {
                    if (var.FirstItem != null)
                    {
                        if (var.LastItem == null)
                            throw new CompilerException();

                        int start = var.FirstItem.Offset;
                        int end = var.LastItem.Offset;

                        if (jumpOffset >= start && jumpOffset <= end)
                            var.LastItem = this;
                    }
                    var = var.NextActive;
                } while (var != first);
            }

            cc.CurrentOffset++;
        }
예제 #6
0
        protected override CompilerItem TranslateImpl(CompilerContext cc)
        {
            switch (_hintKind)
            {
            case VariableHintKind.Alloc:
                cc.AllocVar(_varData, new RegisterMask(_hintValue), VariableAlloc.Read);
                break;

            case VariableHintKind.Spill:
                if (_varData.State == VariableState.Register)
                    cc.SpillVar(_varData);
                break;

            case VariableHintKind.Save:
            case VariableHintKind.SaveAndUnuse:
                if (_varData.State == VariableState.Register && _varData.Changed)
                {
                    cc.EmitSaveVar(_varData, _varData.RegisterIndex);
                    _varData.Changed = false;
                }

                if (_hintKind == VariableHintKind.SaveAndUnuse)
                    goto case VariableHintKind.Unuse;

                break;

            case VariableHintKind.Unuse:
                cc.UnuseVar(_varData, VariableState.Unused);
                goto end;
            }

            cc.UnuseVarOnEndOfScope(this, _varData);

            end:
            return Next;
        }
예제 #7
0
 protected override void PrepareImpl(CompilerContext cc)
 {
     Offset = cc.CurrentOffset++;
     PrepareVariables(this);
 }
예제 #8
0
        internal void EmitProlog(CompilerContext cc)
        {
            RegisterMask preservedGP = _modifiedAndPreservedGP;
            RegisterMask preservedMM = _modifiedAndPreservedMM;
            RegisterMask preservedXMM = _modifiedAndPreservedXMM;

            int stackOffset = RequiredStackOffset;
            int stackPos;

            // --------------------------------------------------------------------------
            // [Prolog]
            // --------------------------------------------------------------------------

            if (Compiler.Logger != null)
                Compiler.Comment("Prolog");

            // Emit standard prolog entry code (but don't do it if function is set to be
            // naked).
            //
            // Also see the _prologEpilogStackAdjust variable. If function is naked (so
            // prolog and epilog will not contain "push ebp" and "mov ebp, esp", we need
            // to adjust stack by 8 bytes in 64-bit mode (this will give us that stack
            // will remain aligned to 16 bytes).
            if (!_isNaked)
            {
                Compiler.Emit(InstructionCode.Push, Register.nbp);
                Compiler.Emit(InstructionCode.Mov, Register.nbp, Register.nsp);
            }

            // Align manually stack-pointer to 16-bytes.
            if (_isPerformed16ByteAlignment)
            {
                if (_isNaked)
                    throw new CompilerException();

                Compiler.Emit(InstructionCode.And, Register.nsp, (Imm)(-16));
            }

            // --------------------------------------------------------------------------
            // [Save Gp - Push/Pop]
            // --------------------------------------------------------------------------

            if (preservedGP != RegisterMask.Zero && _pePushPop)
            {
                for (int i = 0; i < RegNum.GP; i++)
                {
                    RegisterMask mask = RegisterMask.FromIndex((RegIndex)i);
                    if ((preservedGP & mask) != RegisterMask.Zero)
                        Compiler.Emit(InstructionCode.Push, Register.gpn((RegIndex)i));
                }
            }

            // --------------------------------------------------------------------------
            // [Adjust Scack]
            // --------------------------------------------------------------------------

            if (_isEspAdjusted)
            {
                stackPos = _memStackSize16 + _functionCallStackSize;
                if (stackOffset != 0)
                    Compiler.Emit(InstructionCode.Sub, Register.nsp, (Imm)stackOffset);
            }
            else
            {
                stackPos = -(_peMovStackSize + _peAdjustStackSize);
                //if (_pePushPop) stackPos += bitCount(preservedGP) * sizeof(sysint_t);
            }

            // --------------------------------------------------------------------------
            // [Save Xmm - MovDqa/MovDqu]
            // --------------------------------------------------------------------------

            if (preservedXMM != RegisterMask.Zero)
            {
                for (int i = 0; i < RegNum.XMM; i++)
                {
                    RegisterMask mask = RegisterMask.FromIndex((RegIndex)i);
                    if ((preservedXMM & mask) != RegisterMask.Zero)
                    {
                        Compiler.Emit(_movDqInstruction, Mem.dqword_ptr(Register.nsp, stackPos), Register.xmm((RegIndex)i));
                        stackPos += 16;
                    }
                }
            }

            // --------------------------------------------------------------------------
            // [Save Mm - MovQ]
            // --------------------------------------------------------------------------

            if (preservedMM != RegisterMask.Zero)
            {
                for (int i = 0; i < 8; i++)
                {
                    RegisterMask mask = RegisterMask.FromIndex((RegIndex)i);
                    if ((preservedMM & mask) != RegisterMask.Zero)
                    {
                        Compiler.Emit(InstructionCode.Movq, Mem.qword_ptr(Register.nsp, stackPos), Register.mm((RegIndex)i));
                        stackPos += 8;
                    }
                }
            }

            // --------------------------------------------------------------------------
            // [Save Gp - Mov]
            // --------------------------------------------------------------------------

            if (preservedGP != RegisterMask.Zero && !_pePushPop)
            {
                for (int i = 0; i < RegNum.GP; i++)
                {
                    RegisterMask mask = RegisterMask.FromIndex((RegIndex)i);
                    if ((preservedGP & mask) != RegisterMask.Zero)
                    {
                        Compiler.Emit(InstructionCode.Mov, Mem.sysint_ptr(Register.nsp, stackPos), Register.gpn((RegIndex)i));
                        stackPos += IntPtr.Size;
                    }
                }
            }

            // --------------------------------------------------------------------------
            // [...]
            // --------------------------------------------------------------------------

            if (Compiler.Logger != null)
                Compiler.Comment("Body");
        }
예제 #9
0
        protected override CompilerItem TranslateImpl(CompilerContext cc)
        {
            RegisterMask preserved;

            RegIndex temporaryGpReg;
            RegIndex temporaryXmmReg;

            int offset = cc.CurrentOffset;
            Compiler compiler = cc.Compiler;

            // Constants.
            FunctionDeclaration.Argument[] targs = Declaration.Arguments;

            int argumentsCount = Declaration.Arguments.Length;
            int variablesCount = _variables.Length;

            // Processed arguments.
            bool[] processed = new bool[FUNC_MAX_ARGS];

            compiler.Comment("Call");

            // These variables are used by the instruction so we set current offset
            // to their work offsets -> The SpillCandidate method never returns
            // the variable used by this instruction.
            for (int i = 0; i < variablesCount; i++)
            {
                _variables[i].vdata.WorkOffset = offset;

                // Init back-reference to VarCallRecord.
                _variables[i].vdata.Temp = _variables[i];
            }

            // --------------------------------------------------------------------------
            // STEP 1:
            //
            // Spill variables which are not used by the function call and have to
            // be destroyed. These registers may be used by callee.
            // --------------------------------------------------------------------------

            preserved = Declaration.PreservedGP;
            for (int i = 0; i < RegNum.GP; i++)
            {
                RegisterMask mask = RegisterMask.FromIndex((RegIndex)i);
                CompilerVar vdata = cc.State.GP[i];
                if (vdata != null && vdata.WorkOffset != offset && (preserved & mask) == RegisterMask.Zero)
                    cc.SpillGPVar(vdata);
            }

            preserved = Declaration.PreservedMM;
            for (int i = 0; i < RegNum.MM; i++)
            {
                RegisterMask mask = RegisterMask.FromIndex((RegIndex)i);
                CompilerVar vdata = cc.State.MM[i];
                if (vdata != null && vdata.WorkOffset != offset && (preserved & mask) == RegisterMask.Zero)
                    cc.SpillMMVar(vdata);
            }

            preserved = Declaration.PreservedXMM;
            for (int i = 0; i < RegNum.XMM; i++)
            {
                RegisterMask mask = RegisterMask.FromIndex((RegIndex)i);
                CompilerVar vdata = cc.State.XMM[i];
                if (vdata != null && vdata.WorkOffset != offset && (preserved & mask) == RegisterMask.Zero)
                    cc.SpillXMMVar(vdata);
            }

            // --------------------------------------------------------------------------
            // STEP 2:
            //
            // Move all arguments to the stack which are already in registers.
            // --------------------------------------------------------------------------

            for (int i = 0; i < argumentsCount; i++)
            {
                if (processed[i])
                    continue;

                FunctionDeclaration.Argument argType = targs[i];
                if (argType._registerIndex != RegIndex.Invalid)
                    continue;

                Operand operand = _args[i];

                if (operand.IsVar)
                {
                    VarCallRecord rec = _argumentToVarRecord[i];
                    CompilerVar vdata = compiler.GetVarData(operand.Id);
                    Contract.Assert(vdata != null);

                    if (vdata.RegisterIndex != RegIndex.Invalid)
                    {
                        MoveAllocatedVariableToStack(cc, vdata, argType);

                        rec.InDone++;
                        processed[i] = true;
                    }
                }
            }

            // --------------------------------------------------------------------------
            // STEP 3:
            //
            // Spill all non-preserved variables we moved to stack in STEP #2.
            // --------------------------------------------------------------------------

            for (int i = 0; i < argumentsCount; i++)
            {
                VarCallRecord rec = _argumentToVarRecord[i];
                if (rec == null || processed[i])
                    continue;

                if (rec.InDone >= rec.InCount)
                {
                    CompilerVar vdata = rec.vdata;
                    if (vdata.RegisterIndex == RegIndex.Invalid)
                        continue;

                    if (rec.OutCount != 0)
                    {
                        // Variable will be rewritten by function return value, it's not needed
                        // to spill it. It will be allocated again by ECall.
                        cc.UnuseVar(rec.vdata, VariableState.Unused);
                    }
                    else
                    {
                        switch (vdata.Type)
                        {
                        case VariableType.GPD:
                        case VariableType.GPQ:
                            if ((Declaration.PreservedGP & RegisterMask.FromIndex(vdata.RegisterIndex)) == RegisterMask.Zero)
                                cc.SpillGPVar(vdata);
                            break;
                        case VariableType.MM:
                            if ((Declaration.PreservedMM & RegisterMask.FromIndex(vdata.RegisterIndex)) == RegisterMask.Zero)
                                cc.SpillMMVar(vdata);
                            break;
                        case VariableType.XMM:
                        case VariableType.XMM_1F:
                        case VariableType.XMM_1D:
                        case VariableType.XMM_4F:
                        case VariableType.XMM_2D:
                            if ((Declaration.PreservedXMM & RegisterMask.FromIndex(vdata.RegisterIndex)) == RegisterMask.Zero)
                                cc.SpillXMMVar(vdata);
                            break;
                        default:
                            throw new CompilerException();
                        }
                    }
                }
            }

            // --------------------------------------------------------------------------
            // STEP 4:
            //
            // Get temporary register that we can use to pass input function arguments.
            // Now it's safe to do, because the non-needed variables should be spilled.
            // --------------------------------------------------------------------------

            temporaryGpReg = FindTemporaryGpRegister(cc, true);
            temporaryXmmReg = FindTemporaryXmmRegister(cc);

            // If failed to get temporary register then we need just to pick one.
            if (temporaryGpReg == RegIndex.Invalid)
            {
                throw new NotImplementedException();
            }
            if (temporaryXmmReg == RegIndex.Invalid)
            {
                // TODO.
                throw new NotImplementedException();
            }

            // --------------------------------------------------------------------------
            // STEP 5:
            //
            // Move all remaining arguments to the stack (we can use temporary register).
            // or allocate it to the primary register. Also move immediates.
            // --------------------------------------------------------------------------

            for (int i = 0; i < argumentsCount; i++)
            {
                if (processed[i])
                    continue;

                FunctionDeclaration.Argument argType = targs[i];
                if (argType._registerIndex != RegIndex.Invalid)
                    continue;

                Operand operand = _args[i];

                if (operand.IsVar)
                {
                    VarCallRecord rec = _argumentToVarRecord[i];
                    CompilerVar vdata = compiler.GetVarData(operand.Id);
                    Contract.Assert(vdata != null);

                    MoveSpilledVariableToStack(cc, vdata, argType, temporaryGpReg, temporaryXmmReg);

                    rec.InDone++;
                    processed[i] = true;
                }
                else if (operand.IsImm)
                {
                    Mem dst;

                    switch (argType._variableType)
                    {
                    case VariableType.GPD:
                        dst = Mem.dword_ptr(Register.nsp, -IntPtr.Size + argType._stackOffset);
                        break;

                    case VariableType.GPQ:
                        dst = Mem.qword_ptr(Register.nsp, -IntPtr.Size + argType._stackOffset);
                        break;

                    case VariableType.X87:
                    case VariableType.X87_1D:
                    case VariableType.X87_1F:
                        throw new NotImplementedException();

                    case VariableType.MM:
                        dst = Mem.mmword_ptr(Register.nsp, -IntPtr.Size + argType._stackOffset);
                        break;

                    case VariableType.XMM:
                    case VariableType.XMM_1D:
                    case VariableType.XMM_1F:
                    case VariableType.XMM_2D:
                    case VariableType.XMM_4F:
                        dst = Mem.xmmword_ptr(Register.nsp, -IntPtr.Size + argType._stackOffset);
                        break;

                    default:
                        throw new NotImplementedException();
                    }

                    compiler.Mov(dst, (Imm)operand);
                }
            }

            // --------------------------------------------------------------------------
            // STEP 6:
            //
            // Allocate arguments to registers.
            // --------------------------------------------------------------------------

            bool didWork;

            do
            {
                didWork = false;

                for (int i = 0; i < argumentsCount; i++)
                {
                    if (processed[i])
                        continue;

                    VarCallRecord rsrc = _argumentToVarRecord[i];

                    Operand osrc = _args[i];
                    if (!osrc.IsVar)
                        throw new CompilerException();
                    CompilerVar vsrc = compiler.GetVarData(osrc.Id);
                    Contract.Assert(vsrc != null);

                    FunctionDeclaration.Argument srcArgType = targs[i];
                    CompilerVar vdst = GetOverlappingVariable(cc, srcArgType);

                    if (vsrc == vdst)
                    {
                        rsrc.InDone++;
                        processed[i] = true;

                        didWork = true;
                        continue;
                    }
                    else if (vdst != null)
                    {
                        VarCallRecord rdst = (VarCallRecord)(vdst.Temp);

                        if (rdst == null)
                        {
                            cc.SpillVar(vdst);
                            vdst = null;
                        }
                        else if (rdst.InDone >= rdst.InCount && (rdst.Flags & VarCallFlags.CALL_OPERAND_REG) == 0)
                        {
                            // Safe to spill.
                            if (rdst.OutCount != 0 || vdst.LastItem == this)
                                cc.UnuseVar(vdst, VariableState.Unused);
                            else
                                cc.SpillVar(vdst);
                            vdst = null;
                        }
                        else
                        {
                            int x = Declaration.FindArgumentByRegisterCode(VariableInfo.GetVariableRegisterCode(vsrc.Type, vsrc.RegisterIndex));

                            bool doSpill = true;

                            if ((VariableInfo.GetVariableClass(vdst.Type) & VariableClass.GP) != 0)
                            {
                                // Try to emit mov to register which is possible for call() operand.
                                if (x == InvalidValue && (rdst.Flags & VarCallFlags.CALL_OPERAND_REG) != 0)
                                {
                                    int rIndex;

                                    // The mask which contains registers which are not-preserved
                                    // (these that might be clobbered by the callee) and which are
                                    // not used to pass function arguments. Each register contained
                                    // in this mask is ideal to be used by call() instruction.
                                    RegisterMask possibleMask = ~Declaration.PreservedGP &
                                                            ~Declaration.PassedGP &
                                                            (RegisterMask.MaskToIndex(RegNum.GP) & ~RegisterMask.FromIndex(RegIndex.Eax));

                                    if (possibleMask != RegisterMask.Zero)
                                    {
                                        for (rIndex = 0; rIndex < RegNum.GP; rIndex++)
                                        {
                                            RegisterMask rBit = RegisterMask.FromIndex((RegIndex)rIndex);
                                            if ((possibleMask & rBit) != RegisterMask.Zero)
                                            {
                                                if (cc.State.GP[rIndex] == null)
                                                {
                                                    // This is the best possible solution, the register is
                                                    // free. We do not need to continue with this loop, the
                                                    // rIndex will be used by the call().
                                                    break;
                                                }
                                                else
                                                {
                                                    // Wait until the register is freed or try to find another.
                                                    doSpill = false;
                                                    didWork = true;
                                                }
                                            }
                                        }
                                    }
                                    else
                                    {
                                        // Try to find a register which is free and which is not used
                                        // to pass a function argument.
                                        possibleMask = Declaration.PreservedGP;

                                        for (rIndex = 0; rIndex < RegNum.GP; rIndex++)
                                        {
                                            RegisterMask rBit = RegisterMask.FromIndex((RegIndex)rIndex);
                                            if ((possibleMask & rBit) != RegisterMask.Zero)
                                            {
                                                // Found one.
                                                if (cc.State.GP[rIndex] == null)
                                                    break;
                                            }
                                        }
                                    }

                                    if (rIndex < RegNum.GP)
                                    {
                                        if (temporaryGpReg == vsrc.RegisterIndex)
                                            temporaryGpReg = (RegIndex)rIndex;

                                        compiler.Emit(InstructionCode.Mov, Register.gpn((RegIndex)rIndex), Register.gpn(vsrc.RegisterIndex));

                                        cc.State.GP[(int)vsrc.RegisterIndex] = null;
                                        cc.State.GP[rIndex] = vsrc;

                                        vsrc.RegisterIndex = (RegIndex)rIndex;
                                        cc.AllocatedGPRegister((RegIndex)rIndex);

                                        doSpill = false;
                                        didWork = true;
                                    }
                                }
                                // Emit xchg instead of spill/alloc if possible.
                                else if (x != InvalidValue)
                                {
                                    FunctionDeclaration.Argument dstArgType = targs[x];
                                    if (VariableInfo.GetVariableInfo(dstArgType._variableType).Class == VariableInfo.GetVariableInfo(srcArgType._variableType).Class)
                                    {
                                        RegIndex dstIndex = vdst.RegisterIndex;
                                        RegIndex srcIndex = vsrc.RegisterIndex;

                                        if (srcIndex == dstArgType._registerIndex)
                                        {
                                            compiler.Emit(InstructionCode.Xchg, Register.gpn(dstIndex), Register.gpd(srcIndex));
                                            if (Util.IsX64)
                                            {
                                                if (vdst.Type != VariableType.GPD || vsrc.Type != VariableType.GPD)
                                                    compiler.Emit(InstructionCode.Xchg, Register.gpq(dstIndex), Register.gpq(srcIndex));
                                                else
                                                    compiler.Emit(InstructionCode.Xchg, Register.gpd(dstIndex), Register.gpd(srcIndex));
                                            }
                                            else
                                            {
                                                compiler.Emit(InstructionCode.Xchg, Register.gpd(dstIndex), Register.gpd(srcIndex));
                                            }

                                            cc.State.GP[(int)srcIndex] = vdst;
                                            cc.State.GP[(int)dstIndex] = vsrc;

                                            vdst.RegisterIndex = srcIndex;
                                            vsrc.RegisterIndex = dstIndex;

                                            rdst.InDone++;
                                            rsrc.InDone++;

                                            processed[i] = true;
                                            processed[x] = true;

                                            doSpill = false;
                                        }
                                    }
                                }
                            }

                            if (doSpill)
                            {
                                cc.SpillVar(vdst);
                                vdst = null;
                            }
                        }
                    }

                    if (vdst == null)
                    {
                        VarCallRecord rec = (VarCallRecord)(vsrc.Temp);

                        MoveSrcVariableToRegister(cc, vsrc, srcArgType);

                        switch (srcArgType._variableType)
                        {
                        case VariableType.GPD:
                        case VariableType.GPQ:
                            cc.MarkGPRegisterModified(srcArgType._registerIndex);
                            break;

                        case VariableType.MM:
                            cc.MarkMMRegisterModified(srcArgType._registerIndex);
                            break;

                        case VariableType.XMM:
                        case VariableType.XMM_1F:
                        case VariableType.XMM_1D:
                        case VariableType.XMM_4F:
                        case VariableType.XMM_2D:
                            cc.MarkXMMRegisterModified(srcArgType._registerIndex);
                            break;
                        }

                        rec.InDone++;
                        processed[i] = true;
                    }
                }
            } while (didWork);

            // --------------------------------------------------------------------------
            // STEP 7:
            //
            // Allocate operand used by CALL instruction.
            // --------------------------------------------------------------------------

            for (int i = 0; i < variablesCount; i++)
            {
                VarCallRecord r = _variables[i];
                if ((r.Flags & VarCallFlags.CALL_OPERAND_REG) != 0 &&
                    (r.vdata.RegisterIndex == RegIndex.Invalid))
                {
                    // If the register is not allocated and the call form is 'call reg' then
                    // it's possible to keep it in memory.
                    if ((r.Flags & VarCallFlags.CALL_OPERAND_MEM) == 0)
                    {
                        _target = GPVar.FromData(r.vdata).ToMem();
                        break;
                    }

                    if (temporaryGpReg == RegIndex.Invalid)
                        temporaryGpReg = FindTemporaryGpRegister(cc, true);

                    cc.AllocGPVar(r.vdata, RegisterMask.FromIndex(temporaryGpReg),
                      VariableAlloc.Register | VariableAlloc.Read);
                }
            }

            {
                Operand[] operands = { _target };
                cc.TranslateOperands(operands);
                _target = operands[0];
            }

            // --------------------------------------------------------------------------
            // STEP 8:
            //
            // Spill all preserved variables.
            // --------------------------------------------------------------------------

            preserved = Declaration.PreservedGP;
            for (int i = 0; i < (int)RegNum.GP; i++)
            {
                RegisterMask mask = RegisterMask.FromIndex((RegIndex)i);
                CompilerVar vdata = cc.State.GP[i];
                if (vdata != null && (preserved & mask) == RegisterMask.Zero)
                {
                    VarCallRecord rec = (VarCallRecord)(vdata.Temp);
                    if (rec != null && (rec.OutCount != 0 || (rec.Flags & VarCallFlags.UnuseAfterUse) != 0 || vdata.LastItem == this))
                        cc.UnuseVar(vdata, VariableState.Unused);
                    else
                        cc.SpillGPVar(vdata);
                }
            }

            preserved = Declaration.PreservedMM;
            for (int i = 0; i < (int)RegNum.MM; i++)
            {
                RegisterMask mask = RegisterMask.FromIndex((RegIndex)i);
                CompilerVar vdata = cc.State.MM[i];
                if (vdata != null && (preserved & mask) == RegisterMask.Zero)
                {
                    VarCallRecord rec = (VarCallRecord)(vdata.Temp);
                    if (rec != null && (rec.OutCount != 0 || vdata.LastItem == this))
                        cc.UnuseVar(vdata, VariableState.Unused);
                    else
                        cc.SpillMMVar(vdata);
                }
            }

            preserved = Declaration.PreservedXMM;
            for (int i = 0; i < (int)RegNum.XMM; i++)
            {
                RegisterMask mask = RegisterMask.FromIndex((RegIndex)i);
                CompilerVar vdata = cc.State.XMM[i];
                if (vdata != null && (preserved & mask) == RegisterMask.Zero)
                {
                    VarCallRecord rec = (VarCallRecord)(vdata.Temp);
                    if (rec != null && (rec.OutCount != 0 || vdata.LastItem == this))
                        cc.UnuseVar(vdata, VariableState.Unused);
                    else
                        cc.SpillXMMVar(vdata);
                }
            }

            // --------------------------------------------------------------------------
            // STEP 9:
            //
            // Emit CALL instruction.
            // --------------------------------------------------------------------------

            compiler.Emit(InstructionCode.Call, _target);

            // Restore the stack offset.
            if (Declaration.CalleePopsStack)
            {
                int s = Declaration.ArgumentsStackSize;
                if (s != 0)
                    compiler.Emit(InstructionCode.Sub, Register.nsp, (Imm)s);
            }

            // --------------------------------------------------------------------------
            // STEP 10:
            //
            // Prepare others for return value(s) and cleanup.
            // --------------------------------------------------------------------------

            // Clear temp data, see AsmJit::VarData::temp why it's needed.
            for (int i = 0; i < variablesCount; i++)
            {
                VarCallRecord rec = _variables[i];
                CompilerVar vdata = rec.vdata;

                if ((rec.Flags & (VarCallFlags.OUT_EAX | VarCallFlags.OUT_EDX)) != 0)
                {
                    if ((VariableInfo.GetVariableInfo(vdata.Type).Class & VariableClass.GP) != 0)
                    {
                        cc.AllocGPVar(vdata, (rec.Flags & VarCallFlags.OUT_EAX) != 0
                          ? RegisterMask.FromIndex(RegIndex.Eax)
                          : RegisterMask.FromIndex(RegIndex.Edx),
                          VariableAlloc.Register | VariableAlloc.Write);
                        vdata.Changed = true;
                    }
                }

                if ((rec.Flags & (VarCallFlags.OUT_MM0)) != 0)
                {
                    if ((VariableInfo.GetVariableInfo(vdata.Type).Class & VariableClass.MM) != 0)
                    {
                        cc.AllocMMVar(vdata, RegisterMask.FromIndex(RegIndex.Mm0),
                          VariableAlloc.Register | VariableAlloc.Write);
                        vdata.Changed = true;
                    }
                }

                if ((rec.Flags & (VarCallFlags.OUT_XMM0 | VarCallFlags.OUT_XMM1)) != 0)
                {
                    if ((VariableInfo.GetVariableInfo(vdata.Type).Class & VariableClass.XMM) != 0)
                    {
                        cc.AllocXMMVar(vdata, RegisterMask.FromIndex((rec.Flags & VarCallFlags.OUT_XMM0) != 0
                          ? RegIndex.Xmm0
                          : RegIndex.Xmm1),
                          VariableAlloc.Register | VariableAlloc.Write);
                        vdata.Changed = true;
                    }
                }

                if ((rec.Flags & (VarCallFlags.OUT_ST0 | VarCallFlags.OUT_ST1)) != 0)
                {
                    if ((VariableInfo.GetVariableInfo(vdata.Type).Class & VariableClass.XMM) != 0)
                    {
                        Mem mem = cc.GetVarMem(vdata);
                        cc.UnuseVar(vdata, VariableState.Memory);

                        switch (vdata.Type)
                        {
                        case VariableType.XMM_1F:
                        case VariableType.XMM_4F:
                            {
                                //mem.Size = 4;
                                if (mem.Size != 4)
                                    throw new NotImplementedException("Size is now an immutable property.");

                                compiler.Emit(InstructionCode.Fstp, mem);
                                break;
                            }
                        case VariableType.XMM_1D:
                        case VariableType.XMM_2D:
                            {
                                //mem.Size = 8;
                                if (mem.Size != 4)
                                    throw new NotImplementedException("Size is now an immutable property.");

                                compiler.Emit(InstructionCode.Fstp, mem);
                                break;
                            }
                        default:
                            {
                                compiler.Comment("*** WARNING: Can't convert float return value to untyped XMM\n");
                                break;
                            }
                        }
                    }
                }

                // Cleanup.
                vdata.Temp = null;
            }

            for (int i = 0; i < variablesCount; i++)
            {
                cc.UnuseVarOnEndOfScope(this, _variables[i]);
            }

            return Next;
        }
예제 #10
0
        private void MoveSrcVariableToRegister(CompilerContext cc, CompilerVar vdata, FunctionDeclaration.Argument argType)
        {
            Contract.Requires(cc != null);
            Contract.Requires(vdata != null);
            Contract.Requires(argType != null);

            RegIndex dst = argType._registerIndex;
            RegIndex src = vdata.RegisterIndex;

            Compiler compiler = cc.Compiler;

            if (src != RegIndex.Invalid)
            {
                switch (argType._variableType)
                {
                case VariableType.GPD:
                    switch (vdata.Type)
                    {
                    case VariableType.GPD:
                        compiler.Emit(InstructionCode.Mov, Register.gpd(dst), Register.gpd(src));
                        return;

                    case VariableType.GPQ:
                        if (!Util.IsX64)
                            throw new NotSupportedException();

                        compiler.Emit(InstructionCode.Mov, Register.gpq(dst), Register.gpq(src));
                        return;

                    case VariableType.MM:
                        compiler.Emit(InstructionCode.Movd, Register.gpd(dst), Register.mm(src));
                        return;
                    }
                    break;

                case VariableType.GPQ:
                    if (!Util.IsX64)
                        throw new NotSupportedException();

                    switch (vdata.Type)
                    {
                    case VariableType.GPD:
                        compiler.Emit(InstructionCode.Mov, Register.gpd(dst), Register.gpd(src));
                        return;
                    case VariableType.GPQ:
                        compiler.Emit(InstructionCode.Mov, Register.gpq(dst), Register.gpq(src));
                        return;
                    case VariableType.MM:
                        compiler.Emit(InstructionCode.Movq, Register.gpq(dst), Register.mm(src));
                        return;
                    }
                    break;

                case VariableType.MM:
                    switch (vdata.Type)
                    {
                    case VariableType.GPD:
                        compiler.Emit(InstructionCode.Movd, Register.gpd(dst), Register.gpd(src));
                        return;

                    case VariableType.GPQ:
                        if (!Util.IsX64)
                            throw new NotSupportedException();

                        compiler.Emit(InstructionCode.Movq, Register.gpq(dst), Register.gpq(src));
                        return;

                    case VariableType.MM:
                        compiler.Emit(InstructionCode.Movq, Register.mm(dst), Register.mm(src));
                        return;
                    }
                    break;

                case VariableType.XMM:
                case VariableType.XMM_4F:
                case VariableType.XMM_2D:
                    switch (vdata.Type)
                    {
                    case VariableType.GPD:
                        compiler.Emit(InstructionCode.Movd, Register.xmm(dst), Register.gpd(src));
                        return;

                    case VariableType.GPQ:
                        if (!Util.IsX64)
                            throw new NotSupportedException();

                        compiler.Emit(InstructionCode.Movq, Register.xmm(dst), Register.gpq(src));
                        return;

                    case VariableType.MM:
                        compiler.Emit(InstructionCode.Movq, Register.xmm(dst), Register.mm(src));
                        return;
                    case VariableType.XMM:
                    case VariableType.XMM_1F:
                    case VariableType.XMM_4F:
                    case VariableType.XMM_1D:
                    case VariableType.XMM_2D:
                        compiler.Emit(InstructionCode.Movdqa, Register.xmm(dst), Register.xmm(src));
                        return;
                    }
                    break;

                case VariableType.XMM_1F:
                    switch (vdata.Type)
                    {
                    case VariableType.MM:
                        compiler.Emit(InstructionCode.Movq, Register.xmm(dst), Register.mm(src));
                        return;

                    case VariableType.XMM:
                        compiler.Emit(InstructionCode.Movdqa, Register.xmm(dst), Register.xmm(src));
                        return;
                    case VariableType.XMM_1F:
                    case VariableType.XMM_4F:
                        compiler.Emit(InstructionCode.Movss, Register.xmm(dst), Register.xmm(src));
                        return;
                    case VariableType.XMM_1D:
                    case VariableType.XMM_2D:
                        compiler.Emit(InstructionCode.Cvtsd2ss, Register.xmm(dst), Register.xmm(src));
                        return;
                    }
                    break;

                case VariableType.XMM_1D:
                    switch (vdata.Type)
                    {
                    case VariableType.MM:
                        compiler.Emit(InstructionCode.Movq, Register.xmm(dst), Register.mm(src));
                        return;

                    case VariableType.XMM:
                        compiler.Emit(InstructionCode.Movdqa, Register.xmm(dst), Register.xmm(src));
                        return;
                    case VariableType.XMM_1F:
                    case VariableType.XMM_4F:
                        compiler.Emit(InstructionCode.Cvtss2sd, Register.xmm(dst), Register.xmm(src));
                        return;
                    case VariableType.XMM_1D:
                    case VariableType.XMM_2D:
                        compiler.Emit(InstructionCode.Movsd, Register.xmm(dst), Register.xmm(src));
                        return;
                    }
                    break;
                }
            }
            else
            {
                Mem mem = cc.GetVarMem(vdata);

                switch (argType._variableType)
                {
                case VariableType.GPD:
                    switch (vdata.Type)
                    {
                    case VariableType.GPD:
                        compiler.Emit(InstructionCode.Mov, Register.gpd(dst), mem);
                        return;

                    case VariableType.GPQ:
                        if (!Util.IsX64)
                            throw new NotSupportedException();

                        compiler.Emit(InstructionCode.Mov, Register.gpq(dst), mem);
                        return;

                    case VariableType.MM:
                        compiler.Emit(InstructionCode.Movd, Register.gpd(dst), mem);
                        return;
                    }
                    break;

                case VariableType.GPQ:
                    if (!Util.IsX64)
                        throw new NotSupportedException();

                    switch (vdata.Type)
                    {
                    case VariableType.GPD:
                        compiler.Emit(InstructionCode.Mov, Register.gpd(dst), mem);
                        return;
                    case VariableType.GPQ:
                        compiler.Emit(InstructionCode.Mov, Register.gpq(dst), mem);
                        return;
                    case VariableType.MM:
                        compiler.Emit(InstructionCode.Movq, Register.gpq(dst), mem);
                        return;
                    }
                    break;

                case VariableType.MM:
                    switch (vdata.Type)
                    {
                    case VariableType.GPD:
                        compiler.Emit(InstructionCode.Movd, Register.gpd(dst), mem);
                        return;

                    case VariableType.GPQ:
                        if (!Util.IsX64)
                            throw new NotSupportedException();

                        compiler.Emit(InstructionCode.Movq, Register.gpq(dst), mem);
                        return;

                    case VariableType.MM:
                        compiler.Emit(InstructionCode.Movq, Register.mm(dst), mem);
                        return;
                    }
                    break;

                case VariableType.XMM:
                case VariableType.XMM_4F:
                case VariableType.XMM_2D:
                    switch (vdata.Type)
                    {
                    case VariableType.GPD:
                        compiler.Emit(InstructionCode.Movd, Register.xmm(dst), mem);
                        return;

                    case VariableType.GPQ:
                        if (!Util.IsX64)
                            throw new NotSupportedException();

                        compiler.Emit(InstructionCode.Movq, Register.xmm(dst), mem);
                        return;

                    case VariableType.MM:
                        compiler.Emit(InstructionCode.Movq, Register.xmm(dst), mem);
                        return;
                    case VariableType.XMM:
                    case VariableType.XMM_1F:
                    case VariableType.XMM_4F:
                    case VariableType.XMM_1D:
                    case VariableType.XMM_2D:
                        compiler.Emit(InstructionCode.Movdqa, Register.xmm(dst), mem);
                        return;
                    }
                    break;

                case VariableType.XMM_1F:
                    switch (vdata.Type)
                    {
                    case VariableType.MM:
                        compiler.Emit(InstructionCode.Movq, Register.xmm(dst), mem);
                        return;

                    case VariableType.XMM:
                        compiler.Emit(InstructionCode.Movdqa, Register.xmm(dst), mem);
                        return;
                    case VariableType.XMM_1F:
                    case VariableType.XMM_4F:
                        compiler.Emit(InstructionCode.Movss, Register.xmm(dst), mem);
                        return;
                    case VariableType.XMM_1D:
                    case VariableType.XMM_2D:
                        compiler.Emit(InstructionCode.Cvtsd2ss, Register.xmm(dst), mem);
                        return;
                    }
                    break;

                case VariableType.XMM_1D:
                    switch (vdata.Type)
                    {
                    case VariableType.MM:
                        compiler.Emit(InstructionCode.Movq, Register.xmm(dst), mem);
                        return;

                    case VariableType.XMM:
                        compiler.Emit(InstructionCode.Movdqa, Register.xmm(dst), mem);
                        return;
                    case VariableType.XMM_1F:
                    case VariableType.XMM_4F:
                        compiler.Emit(InstructionCode.Cvtss2sd, Register.xmm(dst), mem);
                        return;
                    case VariableType.XMM_1D:
                    case VariableType.XMM_2D:
                        compiler.Emit(InstructionCode.Movsd, Register.xmm(dst), mem);
                        return;
                    }
                    break;
                }
            }

            throw new ArgumentException("Incompatible argument.");
        }
예제 #11
0
        protected override void PrepareImpl(CompilerContext cc)
        {
            // Prepare is similar to EInstruction::prepare(). We collect unique variables
            // and update statistics, but we don't use standard alloc/free register calls.
            //
            // The calling function is also unique in variable allocator point of view,
            // because we need to alloc some variables that may be destroyed be the
            // callee (okay, may not, but this is not guaranteed).
            Offset = cc.CurrentOffset;

            // Tell EFunction that another function will be called inside. It needs this
            // information to reserve stack for the call and to mark esp adjustable.
            Caller.ReserveStackForFunctionCall(Declaration.ArgumentsStackSize);

            int i;
            int argumentsCount = Declaration.Arguments.Length;
            int operandsCount = argumentsCount;
            int variablesCount = 0;

            // Create registers used as arguments mask.
            for (i = 0; i < argumentsCount; i++)
            {
                FunctionDeclaration.Argument fArg = Declaration.Arguments[i];

                if (fArg._registerIndex != RegIndex.Invalid)
                {
                    switch (fArg._variableType)
                    {
                    case VariableType.GPD:
                    case VariableType.GPQ:
                        _gpParams |= RegisterMask.FromIndex(fArg._registerIndex);
                        break;
                    case VariableType.MM:
                        _mmParams |= RegisterMask.FromIndex(fArg._registerIndex);
                        break;
                    case VariableType.XMM:
                    case VariableType.XMM_1F:
                    case VariableType.XMM_4F:
                    case VariableType.XMM_1D:
                    case VariableType.XMM_2D:
                        _xmmParams |= RegisterMask.FromIndex(fArg._registerIndex);
                        break;
                    default:
                        throw new CompilerException("Invalid variable type in function call argument.");
                    }
                }
                else
                {
                    cc.Function.IsEspAdjusted = true;
                }
            }

            // Call address.
            operandsCount++;

            // The first return value.
            if (_ret[0] != null && !_ret[0].IsNone)
                operandsCount++;

            // The second return value.
            if (_ret[1] != null && !_ret[1].IsNone)
                operandsCount++;

            for (i = 0; i < operandsCount; i++)
            {
                Operand o = (i < argumentsCount)
                  ? (_args[i])
                  : (i == argumentsCount ? _target : _ret[i - argumentsCount - 1]);

                if (o.IsVar)
                {
                    if (o.Id == InvalidValue)
                        throw new CompilerException();

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

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

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

                        cc.MarkMemoryUsed(vdata);
                        if (!cc.IsActive(vdata))
                            cc.AddActive(vdata);

                        continue;
                    }
                    else if (((int)((Mem)o).Base & Operand.OperandIdTypeMask) == Operand.OperandIdTypeVar)
                    {
                        CompilerVar vdata = Compiler.GetVarData((int)((Mem)o).Base);
                        Contract.Assert(vdata != null);

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

                        vdata.WorkOffset = Offset;
                        variablesCount++;
                    }

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

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

                        vdata.WorkOffset = Offset;
                        variablesCount++;
                    }
                }
                else
                {
                    if (o != _target)
                        throw new NotImplementedException();
                }
            }

            _variables = new VarCallRecord[variablesCount];

            // Traverse all active variables and set their firstCallable pointer to this
            // call. This information can be used to choose between the preserved-first
            // and preserved-last register allocation.
            if (cc.Active != null)
            {
                CompilerVar first = cc.Active;
                CompilerVar active = first;
                do
                {
                    if (active.FirstCallable == null)
                        active.FirstCallable = this;
                    active = active.NextActive;
                } while (active != first);
            }

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

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

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

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

                    for (varIndex = curIndex; ; )
                    {
                        if (varIndex == 0)
                        {
                            varIndex = curIndex++;
                            _variables[varIndex].vdata = _candidate;
                            break;
                        }

                        varIndex--;

                        if (_variables[varIndex].vdata == _candidate)
                            break;
                    }

                    var = _variables[varIndex];
                    Contract.Assert(var != null);
                };

            for (i = 0; i < operandsCount; i++)
            {
                Operand o = (i < argumentsCount)
                  ? (_args[i])
                  : (i == argumentsCount ? _target : _ret[i - argumentsCount - 1]);

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

                    __GET_VARIABLE(vdata);
                    _argumentToVarRecord[i] = var;

                    if (i < argumentsCount)
                    {
                        FunctionDeclaration.Argument fArg = Declaration.Arguments[i];

                        if (fArg._registerIndex != RegIndex.Invalid)
                        {
                            cc.NewRegisterHomeIndex(vdata, fArg._registerIndex);

                            switch (fArg._variableType)
                            {
                            case VariableType.GPD:
                            case VariableType.GPQ:
                                var.Flags |= VarCallFlags.IN_GP;
                                var.InCount++;
                                break;
                            case VariableType.MM:
                                var.Flags |= VarCallFlags.IN_MM;
                                var.InCount++;
                                break;
                            case VariableType.XMM:
                            case VariableType.XMM_1F:
                            case VariableType.XMM_4F:
                            case VariableType.XMM_1D:
                            case VariableType.XMM_2D:
                                var.Flags |= VarCallFlags.IN_XMM;
                                var.InCount++;
                                break;
                            default:
                                throw new CompilerException("Invalid variable type in function call argument.");
                            }
                        }
                        else
                        {
                            var.InCount++;
                        }

                        vdata.RegisterReadCount++;
                    }
                    else if (i == argumentsCount)
                    {
                        RegisterMask mask = ~Declaration.PreservedGP &
                                        ~Declaration.PassedGP &
                                        (RegisterMask.MaskToIndex(RegNum.GP) & ~RegisterMask.FromIndex(RegIndex.Eax));

                        cc.NewRegisterHomeIndex(vdata, mask.FirstRegister);
                        cc.NewRegisterHomeMask(vdata, mask);

                        var.Flags |= VarCallFlags.CALL_OPERAND_REG;
                        vdata.RegisterReadCount++;
                    }
                    else
                    {
                        switch (vdata.Type)
                        {
                        case VariableType.GPD:
                        case VariableType.GPQ:
                            if (i == argumentsCount + 1)
                                var.Flags |= VarCallFlags.OUT_EAX;
                            else
                                var.Flags |= VarCallFlags.OUT_EDX;
                            break;

                        case VariableType.X87:
                        case VariableType.X87_1F:
                        case VariableType.X87_1D:
                            if (Util.IsX86)
                            {
                                if (i == argumentsCount + 1)
                                    var.Flags |= VarCallFlags.OUT_ST0;
                                else
                                    var.Flags |= VarCallFlags.OUT_ST1;
                            }
                            else if (Util.IsX64)
                            {
                                if (i == argumentsCount + 1)
                                    var.Flags |= VarCallFlags.OUT_XMM0;
                                else
                                    var.Flags |= VarCallFlags.OUT_XMM1;
                            }
                            else
                            {
                                throw new NotImplementedException();
                            }

                            break;

                        case VariableType.MM:
                            var.Flags |= VarCallFlags.OUT_MM0;
                            break;

                        case VariableType.XMM:
                        case VariableType.XMM_4F:
                        case VariableType.XMM_2D:
                            if (i == argumentsCount + 1)
                                var.Flags |= VarCallFlags.OUT_XMM0;
                            else
                                var.Flags |= VarCallFlags.OUT_XMM1;
                            break;

                        case VariableType.XMM_1F:
                        case VariableType.XMM_1D:
                            if (Util.IsX86)
                            {
                                if (i == argumentsCount + 1)
                                    var.Flags |= VarCallFlags.OUT_ST0;
                                else
                                    var.Flags |= VarCallFlags.OUT_ST1;
                            }
                            else if (Util.IsX64)
                            {
                                if (i == argumentsCount + 1)
                                    var.Flags |= VarCallFlags.OUT_XMM0;
                                else
                                    var.Flags |= VarCallFlags.OUT_XMM1;
                            }
                            else
                            {
                                throw new NotImplementedException();
                            }

                            break;

                        default:
                            throw new CompilerException("Invalid variable type in function call argument.");
                        }

                        vdata.RegisterWriteCount++;
                    }
                }
                else if (o.IsMem)
                {
                    if (i != argumentsCount)
                        throw new CompilerException();

                    if ((o.Id & Operand.OperandIdTypeMask) == Operand.OperandIdTypeVar)
                    {
                        CompilerVar vdata = Compiler.GetVarData(o.Id);
                        Contract.Assert(vdata != null);

                        vdata.MemoryReadCount++;
                    }
                    else if (((int)((Mem)o).Base & Operand.OperandIdTypeMask) == Operand.OperandIdTypeVar)
                    {
                        CompilerVar vdata = Compiler.GetVarData((int)((Mem)o).Base);
                        Contract.Assert(vdata != null);

                        vdata.RegisterReadCount++;

                        __GET_VARIABLE(vdata);
                        var.Flags |= VarCallFlags.CALL_OPERAND_REG | VarCallFlags.CALL_OPERAND_MEM;
                    }

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

                        vdata.RegisterReadCount++;

                        __GET_VARIABLE(vdata);
                        var.Flags |= VarCallFlags.CALL_OPERAND_REG | VarCallFlags.CALL_OPERAND_MEM;
                    }
                }
                else
                {
                    if (o != _target)
                        throw new NotImplementedException();
                }
            }

            // 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.
            //
            // Same code is in EInstruction::prepare().
            for (i = 0; i < _variables.Length; i++)
            {
                CompilerVar v = _variables[i].vdata;

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

                // Last item (end of variable scope).
                v.LastItem = this;
            }

            cc.CurrentOffset++;
        }
예제 #12
0
        private void MoveSpilledVariableToStack(CompilerContext cc, CompilerVar vdata, FunctionDeclaration.Argument argType, RegIndex temporaryGpReg, RegIndex temporaryXmmReg)
        {
            Contract.Requires(cc != null);
            Contract.Requires(vdata != null);
            Contract.Requires(argType != null);

            if (argType._registerIndex != RegIndex.Invalid)
                throw new ArgumentException();
            if (vdata.RegisterIndex != RegIndex.Invalid)
                throw new ArgumentException();

            Compiler compiler = cc.Compiler;

            Mem src = cc.GetVarMem(vdata);
            Mem dst = Mem.ptr(Register.nsp, -IntPtr.Size + argType._stackOffset);

            switch (vdata.Type)
            {
            case VariableType.GPD:
                switch (argType._variableType)
                {
                case VariableType.GPD:
                    compiler.Emit(InstructionCode.Mov, Register.gpd(temporaryGpReg), src);
                    compiler.Emit(InstructionCode.Mov, dst, Register.gpd(temporaryGpReg));
                    return;

                case VariableType.GPQ:
                case VariableType.MM:
                    if (!Util.IsX64)
                        throw new NotSupportedException();

                    compiler.Emit(InstructionCode.Mov, Register.gpd(temporaryGpReg), src);
                    compiler.Emit(InstructionCode.Mov, dst, Register.gpq(temporaryGpReg));
                    return;

                default:
                    throw new CompilerException();
                }

            case VariableType.GPQ:
                if (!Util.IsX64)
                    throw new NotSupportedException();

                switch (argType._variableType)
                {
                case VariableType.GPD:
                    compiler.Emit(InstructionCode.Mov, Register.gpd(temporaryGpReg), src);
                    compiler.Emit(InstructionCode.Mov, dst, Register.gpd(temporaryGpReg));
                    return;

                case VariableType.GPQ:
                case VariableType.MM:
                    compiler.Emit(InstructionCode.Mov, Register.gpq(temporaryGpReg), src);
                    compiler.Emit(InstructionCode.Mov, dst, Register.gpq(temporaryGpReg));
                    return;

                default:
                    throw new CompilerException();
                }

            case VariableType.MM:
                switch (argType._variableType)
                {
                case VariableType.GPD:
                case VariableType.X87_1F:
                case VariableType.XMM_1F:
                    compiler.Emit(InstructionCode.Mov, Register.gpd(temporaryGpReg), src);
                    compiler.Emit(InstructionCode.Mov, dst, Register.gpd(temporaryGpReg));
                    return;

                case VariableType.GPQ:
                case VariableType.MM:
                case VariableType.X87_1D:
                case VariableType.XMM_1D:
                    // TODO
                    return;

                default:
                    throw new CompilerException();
                }

            // We allow incompatible types here, because the called can convert them
            // to correct format before function is called.

            case VariableType.XMM:
            case VariableType.XMM_4F:
            case VariableType.XMM_2D:
                switch (argType._variableType)
                {
                case VariableType.XMM:
                    compiler.Emit(InstructionCode.Movdqu, Register.xmm(temporaryXmmReg), src);
                    compiler.Emit(InstructionCode.Movdqu, dst, Register.xmm(temporaryXmmReg));
                    return;

                case VariableType.XMM_1F:
                case VariableType.XMM_4F:
                    compiler.Emit(InstructionCode.Movups, Register.xmm(temporaryXmmReg), src);
                    compiler.Emit(InstructionCode.Movups, dst, Register.xmm(temporaryXmmReg));
                    return;

                case VariableType.XMM_1D:
                case VariableType.XMM_2D:
                    compiler.Emit(InstructionCode.Movupd, Register.xmm(temporaryXmmReg), src);
                    compiler.Emit(InstructionCode.Movupd, dst, Register.xmm(temporaryXmmReg));
                    return;

                default:
                    throw new CompilerException();
                }

            case VariableType.XMM_1F:
                switch (argType._variableType)
                {
                case VariableType.X87_1F:
                case VariableType.XMM:
                case VariableType.XMM_1F:
                case VariableType.XMM_4F:
                case VariableType.XMM_1D:
                case VariableType.XMM_2D:
                    compiler.Emit(InstructionCode.Movss, Register.xmm(temporaryXmmReg), src);
                    compiler.Emit(InstructionCode.Movss, dst, Register.xmm(temporaryXmmReg));
                    return;

                default:
                    throw new CompilerException();
                }

            case VariableType.XMM_1D:
                switch (argType._variableType)
                {
                case VariableType.X87_1D:
                case VariableType.XMM:
                case VariableType.XMM_1F:
                case VariableType.XMM_4F:
                case VariableType.XMM_1D:
                case VariableType.XMM_2D:
                    compiler.Emit(InstructionCode.Movsd, Register.xmm(temporaryXmmReg), src);
                    compiler.Emit(InstructionCode.Movsd, dst, Register.xmm(temporaryXmmReg));
                    return;

                default:
                    throw new CompilerException();
                }

            default:
                throw new CompilerException("Incompatible argument.");
            }
        }
예제 #13
0
        private void MoveAllocatedVariableToStack(CompilerContext cc, CompilerVar vdata, FunctionDeclaration.Argument argType)
        {
            Contract.Requires(cc != null);
            Contract.Requires(vdata != null);
            Contract.Requires(argType != null);

            if (argType._registerIndex != RegIndex.Invalid)
                throw new ArgumentException();
            if (vdata.RegisterIndex == RegIndex.Invalid)
                throw new ArgumentException();

            Compiler compiler = cc.Compiler;

            RegIndex src = vdata.RegisterIndex;
            Mem dst = Mem.ptr(Register.nsp, -IntPtr.Size + argType._stackOffset);

            switch (vdata.Type)
            {
            case VariableType.GPD:
                switch (argType._variableType)
                {
                case VariableType.GPD:
                    compiler.Emit(InstructionCode.Mov, dst, Register.gpd(src));
                    return;

                case VariableType.GPQ:
                case VariableType.MM:
                    if (!Util.IsX64)
                        throw new NotSupportedException();

                    compiler.Emit(InstructionCode.Mov, dst, Register.gpq(src));
                    return;
                }
                break;

            case VariableType.GPQ:
                if (!Util.IsX64)
                    throw new NotSupportedException();

                switch (argType._variableType)
                {
                case VariableType.GPD:
                    compiler.Emit(InstructionCode.Mov, dst, Register.gpd(src));
                    return;
                case VariableType.GPQ:
                    compiler.Emit(InstructionCode.Mov, dst, Register.gpq(src));
                    return;
                case VariableType.MM:
                    compiler.Emit(InstructionCode.Movq, dst, Register.gpq(src));
                    return;
                }
                break;

            case VariableType.MM:
                switch (argType._variableType)
                {
                case VariableType.GPD:
                case VariableType.X87_1F:
                case VariableType.XMM_1F:
                    compiler.Emit(InstructionCode.Movd, dst, Register.mm(src));
                    return;
                case VariableType.GPQ:
                case VariableType.MM:
                case VariableType.X87_1D:
                case VariableType.XMM_1D:
                    compiler.Emit(InstructionCode.Movq, dst, Register.mm(src));
                    return;
                }
                break;

            // We allow incompatible types here, because the called can convert them
            // to correct format before function is called.

            case VariableType.XMM:
            case VariableType.XMM_4F:
            case VariableType.XMM_2D:
                switch (argType._variableType)
                {
                case VariableType.XMM:
                    compiler.Emit(InstructionCode.Movdqu, dst, Register.xmm(src));
                    return;
                case VariableType.XMM_1F:
                case VariableType.XMM_4F:
                    compiler.Emit(InstructionCode.Movups, dst, Register.xmm(src));
                    return;
                case VariableType.XMM_1D:
                case VariableType.XMM_2D:
                    compiler.Emit(InstructionCode.Movupd, dst, Register.xmm(src));
                    return;
                }
                break;

            case VariableType.XMM_1F:
                switch (argType._variableType)
                {
                case VariableType.X87_1F:
                case VariableType.XMM:
                case VariableType.XMM_1F:
                case VariableType.XMM_4F:
                case VariableType.XMM_1D:
                case VariableType.XMM_2D:
                    compiler.Emit(InstructionCode.Movss, dst, Register.xmm(src));
                    return;
                }
                break;

            case VariableType.XMM_1D:
                switch (argType._variableType)
                {
                case VariableType.X87_1D:
                case VariableType.XMM:
                case VariableType.XMM_1F:
                case VariableType.XMM_4F:
                case VariableType.XMM_1D:
                case VariableType.XMM_2D:
                    compiler.Emit(InstructionCode.Movsd, dst, Register.xmm(src));
                    return;
                }
                break;
            }

            throw new ArgumentException("Incompatible argument.");
        }
예제 #14
0
        private CompilerVar GetOverlappingVariable(CompilerContext cc, FunctionDeclaration.Argument argType)
        {
            Contract.Requires(cc != null);
            Contract.Requires(argType != null);

            if (argType._variableType == VariableType.Invalid)
                throw new ArgumentException();

            switch (argType._variableType)
            {
            case VariableType.GPD:
            case VariableType.GPQ:
                return cc.State.GP[(int)argType._registerIndex];

            case VariableType.MM:
                return cc.State.MM[(int)argType._registerIndex];

            case VariableType.XMM:
            case VariableType.XMM_1F:
            case VariableType.XMM_1D:
            case VariableType.XMM_4F:
            case VariableType.XMM_2D:
                return cc.State.XMM[(int)argType._registerIndex];

            default:
                throw new CompilerException();
            }
        }
예제 #15
0
        private RegIndex FindTemporaryXmmRegister(CompilerContext cc)
        {
            Contract.Requires(cc != null);

            RegisterMask passedXMM = Declaration.PassedXMM;
            RegIndex candidate = RegIndex.Invalid;

            // Find all registers used to pass function arguments. We shouldn't use these
            // if possible.
            for (int i = 0; i < RegNum.XMM; i++)
            {
                RegisterMask mask = RegisterMask.FromIndex((RegIndex)i);
                if (cc.State.XMM[i] == null)
                {
                    // If this register is used to pass arguments to function, we will mark
                    // it and use it only if there is no other one.
                    if ((passedXMM & mask) != RegisterMask.Zero)
                        candidate = (RegIndex)i;
                    else
                        return (RegIndex)i;
                }
            }

            return candidate;
        }
예제 #16
0
        internal void DumpFunction(CompilerContext cc)
        {
            Logger logger = Compiler.Logger;
            if (logger == null)
                throw new InvalidOperationException("Cannot dump a function without a logger.");

            int i;
            StringBuilder buffer = new StringBuilder();

            // Log function prototype.
            {
                int argumentsCount = _functionPrototype.Arguments.Length;
                bool first = true;

                logger.LogString("; Function Prototype:" + Environment.NewLine);
                logger.LogString(";" + Environment.NewLine);

                for (i = 0; i < argumentsCount; i++)
                {
                    FunctionDeclaration.Argument a = _functionPrototype.Arguments[i];
                    CompilerVar vdata = _argumentVariables[i];

                    if (first)
                    {
                        logger.LogString("; IDX| Type     | Sz | Home           |" + Environment.NewLine);
                        logger.LogString("; ---+----------+----+----------------+" + Environment.NewLine);
                    }

                    buffer.Clear();

                    if (a._registerIndex != RegIndex.Invalid)
                    {
                        var regOp = new GPReg(Register.NativeRegisterType, a._registerIndex);
                        Assembler.DumpOperand(buffer, regOp, Register.NativeRegisterType);
                    }
                    else
                    {
                        Mem memOp = new Mem();
                        memOp.Base = RegIndex.Esp;
                        memOp.Displacement = (IntPtr)a._stackOffset;
                        Assembler.DumpOperand(buffer, memOp, Register.NativeRegisterType);
                    }

                    // original format string: "; %-3u| %-9s| %-3u| %-15s|\n"
                    logger.LogFormat("; {0,-3}| {1,-9}| {2,-3}| {3,-15}|" + Environment.NewLine,
                        // Argument index.
                        i,
                        // Argument type.
                        (int)vdata.Type < _variableTypeCount ? VariableInfo.GetVariableInfo(vdata.Type).Name : "invalid",
                        // Argument size.
                        vdata.Size,
                        // Argument memory home.
                        buffer
                        );

                    first = false;
                }
                logger.LogString(";" + Environment.NewLine);
            }

            // Log variables.
            {
                int variablesCount = Compiler.Variables.Count;
                bool first = true;

                logger.LogString("; Variables:" + Environment.NewLine);
                logger.LogString(";" + Environment.NewLine);

                for (i = 0; i < variablesCount; i++)
                {
                    CompilerVar vdata = Compiler.GetVarData(i);
                    Contract.Assert(vdata != null);

                    // If this variable is not related to this function then skip it.
                    if (vdata.Scope != this)
                        continue;

                    // Get some information about variable type.
                    VariableInfo vinfo = VariableInfo.GetVariableInfo(vdata.Type);

                    if (first)
                    {
                        logger.LogString("; ID | Type     | Sz | Home           | Register Access   | Memory Access     |" + Environment.NewLine);
                        logger.LogString("; ---+----------+----+----------------+-------------------+-------------------+" + Environment.NewLine);
                    }

                    buffer.Clear();
                    buffer.Append("[None]");

                    if (vdata.HomeMemoryData != null)
                    {
                        buffer.Clear();

                        Mem memOp = new Mem();
                        if (vdata.IsMemArgument)
                        {
                            FunctionDeclaration.Argument a = _functionPrototype.Arguments[i];

                            memOp.Base = cc.ArgumentsBaseReg;
                            memOp.Displacement += cc.ArgumentsBaseOffset;
                            memOp.Displacement += a._stackOffset;
                        }
                        else
                        {
                            VarMemBlock memBlock = vdata.HomeMemoryData;
                            memOp.Base = cc.VariablesBaseReg;
                            memOp.Displacement += cc.VariablesBaseOffset;
                            memOp.Displacement += memBlock.Offset;
                        }

                        Assembler.DumpOperand(buffer, memOp, Register.NativeRegisterType);
                    }

                    string registerAccess = string.Format("r={0}w={1}x={2}", vdata.RegisterReadCount, vdata.RegisterWriteCount, vdata.RegisterRWCount);
                    string memoryAccess = string.Format("r={0}w={1}x={2}", vdata.MemoryReadCount, vdata.MemoryWriteCount, vdata.MemoryRWCount);
                    logger.LogFormat("; {0,-3}| {1,-9}| {2,-3}| {3,-15}| {4,-18}| {5,-18}|" + Environment.NewLine,
                        // Variable id.
                        (uint)(i & Operand.OperandIdValueMask),
                        // Variable type.
                        (int)vdata.Type < _variableTypeCount ? vinfo.Name : "invalid",
                        // Variable size.
                        vdata.Size,
                        // Variable memory home.
                        buffer,
                        // Register access count.
                        registerAccess,
                        // Memory access count.
                        memoryAccess
                        );

                    first = false;
                }
                logger.LogString(";" + Environment.NewLine);
            }

            // Log modified registers.
            {
                buffer.Clear();

                int r;
                int modifiedRegisters = 0;

                for (r = 0; r < 3; r++)
                {
                    bool first = true;
                    RegisterMask regs;
                    RegType type;

                    switch (r)
                    {
                    case 0:
                        regs = cc.ModifiedGPRegisters;
                        type = Register.NativeRegisterType;
                        buffer.Append("; GP : ");
                        break;
                    case 1:
                        regs = cc.ModifiedMMRegisters;
                        type = RegType.MM;
                        buffer.Append("; MM : ");
                        break;
                    case 2:
                        regs = cc.ModifiedXMMRegisters;
                        type = RegType.XMM;
                        buffer.Append("; XMM: ");
                        break;
                    default:
                        Contract.Assert(false, "");
                        continue;
                    }

                    for (i = 0; i < RegNum.Base; i++)
                    {
                        if ((regs & RegisterMask.FromIndex((RegIndex)i)) != RegisterMask.Zero)
                        {
                            if (!first)
                            {
                                buffer.Append(',');
                                buffer.Append(' ');
                            }

                            DumpRegister(buffer, type, i);
                            first = false;
                            modifiedRegisters++;
                        }
                    }

                    buffer.AppendLine();
                }

                logger.LogFormat("; Modified registers ({0}):" + Environment.NewLine, modifiedRegisters);
                logger.LogString(buffer.ToString());
            }

            logger.LogString(Environment.NewLine);
        }
예제 #17
0
        internal void EmitEpilog(CompilerContext cc)
        {
            // --------------------------------------------------------------------------
            // [Init]
            // --------------------------------------------------------------------------

            RegisterMask preservedGP = _modifiedAndPreservedGP;
            RegisterMask preservedMM = _modifiedAndPreservedMM;
            RegisterMask preservedXMM = _modifiedAndPreservedXMM;

            int stackOffset = RequiredStackOffset;
            int stackPos;

            if (IsEspAdjusted)
                stackPos = _memStackSize16 + _functionCallStackSize;
            else
                stackPos = -(_peMovStackSize + _peAdjustStackSize);

            // --------------------------------------------------------------------------
            // [Epilog]
            // --------------------------------------------------------------------------

            if (Compiler.Logger != null)
                Compiler.Comment("Epilog");

            // --------------------------------------------------------------------------
            // [Restore Xmm - MovDqa/ModDqu]
            // --------------------------------------------------------------------------

            if (preservedXMM != RegisterMask.Zero)
            {
                for (int i = 0; i < RegNum.XMM; i++)
                {
                    RegisterMask mask = RegisterMask.FromIndex((RegIndex)i);
                    if ((preservedXMM & mask) != RegisterMask.Zero)
                    {
                        Compiler.Emit(_movDqInstruction, Register.xmm((RegIndex)i), Mem.dqword_ptr(Register.nsp, stackPos));
                        stackPos += 16;
                    }
                }
            }

            // --------------------------------------------------------------------------
            // [Restore Mm - MovQ]
            // --------------------------------------------------------------------------

            if (preservedMM != RegisterMask.Zero)
            {
                for (int i = 0; i < 8; i++)
                {
                    RegisterMask mask = RegisterMask.FromIndex((RegIndex)i);
                    if ((preservedMM & mask) != RegisterMask.Zero)
                    {
                        Compiler.Emit(InstructionCode.Movq, Register.mm((RegIndex)i), Mem.qword_ptr(Register.nsp, stackPos));
                        stackPos += 8;
                    }
                }
            }

            // --------------------------------------------------------------------------
            // [Restore Gp - Mov]
            // --------------------------------------------------------------------------

            if (preservedGP != RegisterMask.Zero && !_pePushPop)
            {
                for (int i = 0; i < (int)RegNum.GP; i++)
                {
                    RegisterMask mask = RegisterMask.FromIndex((RegIndex)i);
                    if ((preservedGP & mask) != RegisterMask.Zero)
                    {
                        Compiler.Emit(InstructionCode.Mov, Register.gpn((RegIndex)i), Mem.sysint_ptr(Register.nsp, stackPos));
                        stackPos += IntPtr.Size;
                    }
                }
            }

            // --------------------------------------------------------------------------
            // [Adjust Stack]
            // --------------------------------------------------------------------------

            if (_isEspAdjusted && stackOffset != 0)
                Compiler.Emit(InstructionCode.Add, Register.nsp, (Imm)stackOffset);

            // --------------------------------------------------------------------------
            // [Restore Gp - Push/Pop]
            // --------------------------------------------------------------------------

            if (preservedGP != RegisterMask.Zero && _pePushPop)
            {
                for (int i = RegNum.GP - 1; i >= 0; i--)
                {
                    RegisterMask mask = RegisterMask.FromIndex((RegIndex)i);
                    if ((preservedGP & mask) != RegisterMask.Zero)
                    {
                        Compiler.Emit(InstructionCode.Pop, Register.gpn((RegIndex)i));
                    }
                }
            }

            // --------------------------------------------------------------------------
            // [Emms]
            // --------------------------------------------------------------------------

            if (_emitEMMS)
                Compiler.Emit(InstructionCode.Emms);

            // --------------------------------------------------------------------------
            // [MFence/SFence/LFence]
            // --------------------------------------------------------------------------

            if (_emitSFence && _emitLFence)
                Compiler.Emit(InstructionCode.Mfence); // MFence == SFence & LFence.
            else if (_emitSFence)
                Compiler.Emit(InstructionCode.Sfence); // Only SFence.
            else if (_emitLFence)
                Compiler.Emit(InstructionCode.Lfence); // Only LFence.

            // --------------------------------------------------------------------------
            // [Epilog]
            // --------------------------------------------------------------------------

            if (!_isNaked)
            {
                CpuInfo cpuInfo = CpuInfo.Instance;

                // AMD seems to prefer LEAVE instead of MOV/POP sequence.
                if (cpuInfo.VendorId == CpuVendor.Amd)
                {
                    Compiler.Emit(InstructionCode.Leave);
                }
                else
                {
                    Compiler.Emit(InstructionCode.Mov, Register.nsp, Register.nbp);
                    Compiler.Emit(InstructionCode.Pop, Register.nbp);
                }
            }

            // Emit return.
            if (_functionPrototype.CalleePopsStack)
            {
                Compiler.Emit(InstructionCode.Ret, (Imm)((short)_functionPrototype.ArgumentsStackSize));
            }
            else
            {
                Compiler.Emit(InstructionCode.Ret);
            }
        }
예제 #18
0
 protected override void PrepareImpl(CompilerContext cc)
 {
     Offset = cc.CurrentOffset++;
 }
예제 #19
0
        internal void PreparePrologEpilog(CompilerContext cc)
        {
            Contract.Requires(cc != null);

            _pePushPop = false;
            _emitEMMS = false;
            _emitSFence = false;
            _emitLFence = false;
            _isAssumed16ByteAlignment = false;
            _isPerformed16ByteAlignment = false;

            uint accessibleMemoryBelowStack = 0;
            if (_functionPrototype.CallingConvention == CallingConvention.X64U)
                accessibleMemoryBelowStack = 128;

            if (_isCaller && (cc.MemBytesTotal > 0 || _isAssumed16ByteAlignment))
                _isEspAdjusted = true;

            if (cc.MemBytesTotal > accessibleMemoryBelowStack)
                _isEspAdjusted = true;

            _isAssumed16ByteAlignment = (_hints & FunctionHints.Assume16ByteAlignment) != 0;
            _isPerformed16ByteAlignment = (_hints & FunctionHints.Perform16ByteAlignment) != 0;
            _isNaked = (_hints & FunctionHints.Naked) != 0;
            _pePushPop = (_hints & FunctionHints.PushPopSequence) != 0;
            _emitEMMS = (_hints & FunctionHints.Emms) != 0;
            _emitSFence = (_hints & FunctionHints.StoreFence) != 0;
            _emitLFence = (_hints & FunctionHints.LoadFence) != 0;

            // Updated to respect comment from issue #47, align also when using MMX code.
            if (!_isAssumed16ByteAlignment && !_isNaked && (cc.Mem16BlocksCount + cc.Mem8BlocksCount > 0))
            {
                // Have to align stack to 16-bytes.
                _isPerformed16ByteAlignment = true;
                _isEspAdjusted = true;
            }

            _modifiedAndPreservedGP = cc.ModifiedGPRegisters & _functionPrototype.PreservedGP & ~RegisterMask.FromIndex(RegIndex.Esp);
            _modifiedAndPreservedMM = cc.ModifiedMMRegisters & _functionPrototype.PreservedMM;
            _modifiedAndPreservedXMM = cc.ModifiedXMMRegisters & _functionPrototype.PreservedXMM;

            _movDqInstruction = (IsAssumed16ByteAlignment || IsPerformed16ByteAlignment) ? InstructionCode.Movdqa : InstructionCode.Movdqu;

            // Prolog & Epilog stack size.
            {
                int memGpSize = _modifiedAndPreservedGP.RegisterCount * IntPtr.Size;
                int memMmSize = _modifiedAndPreservedMM.RegisterCount * 8;
                int memXmmSize = _modifiedAndPreservedXMM.RegisterCount * 16;

                if (_pePushPop)
                {
                    _pePushPopStackSize = memGpSize;
                    _peMovStackSize = memXmmSize + Util.AlignTo16(memMmSize);
                }
                else
                {
                    _pePushPopStackSize = 0;
                    _peMovStackSize = memXmmSize + Util.AlignTo16(memMmSize + memGpSize);
                }
            }

            if (IsPerformed16ByteAlignment)
            {
                _peAdjustStackSize += Util.DeltaTo16(_pePushPopStackSize);
            }
            else
            {
                int v = 16 - IntPtr.Size;
                if (!_isNaked)
                    v -= IntPtr.Size;

                v -= _pePushPopStackSize & 15;
                if (v < 0)
                    v += 16;
                _peAdjustStackSize = v;

                //_peAdjustStackSize += deltaTo16(_pePushPopStackSize + v);
            }

            // Memory stack size.
            _memStackSize = cc.MemBytesTotal;
            _memStackSize16 = Util.AlignTo16(_memStackSize);

            if (_isNaked)
            {
                cc.ArgumentsBaseReg = RegIndex.Esp;
                cc.ArgumentsBaseOffset = (_isEspAdjusted)
                  ? (_functionCallStackSize + _memStackSize16 + _peMovStackSize + _pePushPopStackSize + _peAdjustStackSize)
                  : (_pePushPopStackSize);
            }
            else
            {
                cc.ArgumentsBaseReg = RegIndex.Ebp;
                cc.ArgumentsBaseOffset = IntPtr.Size;
            }

            cc.VariablesBaseReg = RegIndex.Esp;
            cc.VariablesBaseOffset = _functionCallStackSize;
            if (!_isEspAdjusted)
                cc.VariablesBaseOffset = -_memStackSize16 - _peMovStackSize - _peAdjustStackSize;
        }
예제 #20
0
        protected override CompilerItem TranslateImpl(CompilerContext cc)
        {
            // If this Target was already translated, it's needed to change the current
            // state and return null to tell CompilerContext to process next untranslated
            // item.
            if (IsTranslated)
            {
                cc.RestoreState(_state);
                return null;
            }

            if (cc.Unreachable)
            {
                // If the context has "isUnreachable" flag set and there is no state then
                // it means that this code will be never called. This is a problem, because
                // we are unable to assign a state to current location so we can't allocate
                // registers for variables used inside. So instead of doing anything wrong
                // we remove the unreachable code.
                if (_state == null)
                    return RemoveUnreachableItems();

                // Assign state to the compiler context.
                cc.Unreachable = false;
                cc.AssignState(_state);
            }
            else
            {
                _state = cc.SaveState();
            }

            return Next;
        }
예제 #21
0
 protected override CompilerItem TranslateImpl(CompilerContext cc)
 {
     AllocVariables(cc);
     return base.TranslateImpl(cc);
 }
예제 #22
0
        public void Prepare(CompilerContext cc)
        {
            Contract.Requires(cc != null);

            PrepareImpl(cc);
        }
예제 #23
0
        public CompilerItem Translate(CompilerContext cc)
        {
            Contract.Requires(cc != null);

            CompilerItem next = TranslateImpl(cc);
            Contract.Assert(!_isTranslated || next == null);
            _isTranslated = true;
            return next;
        }
예제 #24
0
        protected virtual void PrepareImpl(CompilerContext cc)
        {
            Contract.Requires(cc != null);

            _offset = cc.CurrentOffset;
        }
예제 #25
0
        protected override CompilerItem TranslateImpl(CompilerContext cc)
        {
            // translate using Instruction
            CompilerItem ret = base.TranslateImpl(cc);

            // we jump with item if it's InstructionCode.JMP (unconditional) and points to yet unknown location.
            if (Code == InstructionCode.Jmp && !JumpTarget.IsTranslated)
            {
                cc.AddBackwardCode(this);
                ret = JumpTarget;
            }
            else
            {
                _state = cc.SaveState();
                if (JumpTarget.IsTranslated)
                {
                    DoJump(cc);
                }
                else
                {
                    // state is not known, so we need to call DoJump() later. Compiler will do it for us.
                    cc.AddForwardJump(this);
                    JumpTarget.State = _state;
                }

                // Mark next code as unrecheable, cleared by a next label (ETarget).
                if (Code == InstructionCode.Jmp)
                {
                    cc.Unreachable = true;
                }
            }

            // Need to traverse over all active variables and unuse them if their scope ends here
            if (cc.Active != null)
            {
                CompilerVar first = cc.Active;
                CompilerVar var = first;

                do
                {
                    cc.UnuseVarOnEndOfScope(this, var);
                    var = var.NextActive;
                } while (var != first);
            }

            return ret;
        }
예제 #26
0
 protected virtual CompilerItem TranslateImpl(CompilerContext cc)
 {
     Contract.Requires(cc != null);
     return Next;
 }
예제 #27
0
        protected override CompilerItem TranslateImpl(CompilerContext cc)
        {
            int i;
            int variablesCount = (_variables != null) ? _variables.Length : 0;

            if (variablesCount > 0)
            {
                // These variables are used by the instruction and we set current offset
                // to their work offsets -> getSpillCandidate never return the variable
                // used this instruction.
                for (i = 0; i < variablesCount; i++)
                {
                    _variables[i].VarData.WorkOffset = cc.CurrentOffset;
                }

                // Alloc variables used by the instruction (special first).
                for (i = 0; i < variablesCount; i++)
                {
                    VarAllocRecord r = _variables[i];
                    // Alloc variables with specific register first.
                    if ((r.VarFlags & VariableAlloc.Special) != 0)
                        cc.AllocVar(r.VarData, r.RegMask, r.VarFlags);
                }

                for (i = 0; i < variablesCount; i++)
                {
                    VarAllocRecord r = _variables[i];
                    // Alloc variables without specific register last.
                    if ((r.VarFlags & VariableAlloc.Special) == 0)
                        cc.AllocVar(r.VarData, r.RegMask, r.VarFlags);
                }

                cc.TranslateOperands(_operands);
            }

            if (_memoryOperand != null && (_memoryOperand.Id & Operand.OperandIdTypeMask) == Operand.OperandIdTypeVar)
            {
                CompilerVar vdata = Compiler.GetVarData(_memoryOperand.Id);
                Contract.Assert(vdata != null);

                switch (vdata.State)
                {
                case VariableState.Unused:
                    vdata.State = VariableState.Memory;
                    break;

                case VariableState.Register:
                    vdata.Changed = false;
                    cc.UnuseVar(vdata, VariableState.Memory);
                    break;
                }
            }

            for (i = 0; i < variablesCount; i++)
            {
                cc.UnuseVarOnEndOfScope(this, _variables[i]);
            }

            return Next;
        }
예제 #28
0
        internal void AllocVariables(CompilerContext cc)
        {
            int i;
            int count = _functionPrototype.Arguments.Length;
            if (count == 0)
                return;

            for (i = 0; i < count; i++)
            {
                CompilerVar vdata = _argumentVariables[i];

                if (vdata.FirstItem != null ||
                    vdata.IsRegArgument ||
                    vdata.IsMemArgument)
                {
                    // Variable is used.
                    if (vdata.RegisterIndex != RegIndex.Invalid)
                    {
                        vdata.State = VariableState.Register;
                        // If variable is in register -> mark it as changed so it will not be
                        // lost by first spill.
                        vdata.Changed = true;
                        cc.AllocatedVariable(vdata);
                    }
                    else if (vdata.IsMemArgument)
                    {
                        vdata.State = VariableState.Memory;
                    }
                }
                else
                {
                    // Variable is not used.
                    vdata.RegisterIndex = RegIndex.Invalid;
                }
            }
        }
예제 #29
0
 protected override CompilerItem TranslateImpl(CompilerContext cc)
 {
     return null;
 }
예제 #30
0
        protected override CompilerItem TranslateImpl(CompilerContext cc)
        {
            Compiler compiler = cc.Compiler;
            Operand[] ret = { _first, _second };

            // Check whether the return value is compatible.
            VariableType retValType = Function.Declaration.ReturnValue;
            int i;

            switch (retValType)
            {
            case VariableType.GPD:
            case VariableType.GPQ:
                for (i = 0; i < 2; i++)
                {
                    if (ret[i] == null)
                        continue;

                    RegIndex dsti = (i == 0) ? RegIndex.Eax : RegIndex.Edx;
                    RegIndex srci;

                    if (ret[i].IsVar)
                    {
                        if (((BaseVar)ret[i]).IsGPVar)
                        {
                            CompilerVar vdata = compiler.GetVarData(ret[i].Id);
                            Contract.Assert(vdata != null);

                            srci = vdata.RegisterIndex;
                            if (srci == RegIndex.Invalid)
                                compiler.Emit(InstructionCode.Mov, Register.gpn(dsti), cc.GetVarMem(vdata));
                            else if (dsti != srci)
                                compiler.Emit(InstructionCode.Mov, Register.gpn(dsti), Register.gpn(srci));
                        }
                    }
                    else if (ret[i].IsImm)
                    {
                        compiler.Emit(InstructionCode.Mov, Register.gpn(dsti), ret[i]);
                    }
                }
                break;

            case VariableType.X87:
            case VariableType.X87_1F:
            case VariableType.X87_1D:
                // There is case that we need to return two values (Unix-ABI specific):
                // - FLD #2
                //-  FLD #1
                i = 2;
                do
                {
                    i--;
                    int dsti = i;
                    RegIndex srci;

                    if (ret[i] == null)
                        continue;

                    if (ret[i].IsVar)
                    {
                        if (((BaseVar)ret[i]).IsX87Var)
                        {
                            // TODO: X87.
                            throw new NotImplementedException("X87 support is not yet implemented.");
                        }
                        else if (((BaseVar)ret[i]).IsXMMVar)
                        {
                            CompilerVar vdata = compiler.GetVarData(ret[i].Id);
                            Contract.Assert(vdata != null);

                            srci = vdata.RegisterIndex;
                            if (srci != RegIndex.Invalid)
                                cc.SaveVar(vdata);

                            switch (vdata.Type)
                            {
                            case VariableType.XMM_1F:
                            case VariableType.XMM_4F:
                                compiler.Emit(InstructionCode.Fld, BaseVarMem(((BaseVar)ret[i]), 4));
                                break;
                            case VariableType.XMM_1D:
                            case VariableType.XMM_2D:
                                compiler.Emit(InstructionCode.Fld, BaseVarMem(((BaseVar)ret[i]), 8));
                                break;
                            }
                        }
                    }
                } while (i != 0);
                break;

            case VariableType.MM:
                for (i = 0; i < 2; i++)
                {
                    RegIndex dsti = (RegIndex)i;
                    RegIndex srci;

                    if (ret[i] == null)
                        continue;

                    if (ret[i].IsVar)
                    {
                        if (((BaseVar)ret[i]).IsGPVar)
                        {
                            CompilerVar vdata = compiler.GetVarData(ret[i].Id);
                            Contract.Assert(vdata != null);

                            srci = vdata.RegisterIndex;
                            InstructionCode inst = ret[i].IsRegType(RegType.GPQ) ? InstructionCode.Movq : InstructionCode.Movd;

                            if (srci == RegIndex.Invalid)
                            {
                                compiler.Emit(inst, Register.mm(dsti), cc.GetVarMem(vdata));
                            }
                            else
                            {
                                if (Util.IsX86)
                                    compiler.Emit(inst, Register.mm(dsti), Register.gpd(srci));
                                else if (Util.IsX64)
                                    compiler.Emit(inst, Register.mm(dsti), ret[i].IsRegType(RegType.GPQ) ? Register.gpq(srci) : Register.gpd(srci));
                                else
                                    throw new NotImplementedException();
                            }
                        }
                        else if (((BaseVar)ret[i]).IsMMVar)
                        {
                            CompilerVar vdata = compiler.GetVarData(ret[i].Id);
                            Contract.Assert(vdata != null);

                            srci = vdata.RegisterIndex;
                            InstructionCode inst = InstructionCode.Movq;

                            if (srci == RegIndex.Invalid)
                                compiler.Emit(inst, Register.mm(dsti), cc.GetVarMem(vdata));
                            else if (dsti != srci)
                                compiler.Emit(inst, Register.mm(dsti), Register.mm(srci));
                        }
                        else if (((BaseVar)ret[i]).IsXMMVar)
                        {
                            CompilerVar vdata = compiler.GetVarData(ret[i].Id);
                            Contract.Assert(vdata != null);

                            srci = vdata.RegisterIndex;
                            InstructionCode inst = InstructionCode.Movq;
                            if (((BaseVar)ret[i]).VariableType == VariableType.XMM_1F)
                                inst = InstructionCode.Movd;

                            if (srci == RegIndex.Invalid)
                                compiler.Emit(inst, Register.mm(dsti), cc.GetVarMem(vdata));
                            else
                                compiler.Emit(inst, Register.mm(dsti), Register.xmm(srci));
                        }
                    }
                }
                break;

            case VariableType.XMM:
            case VariableType.XMM_4F:
            case VariableType.XMM_2D:
                for (i = 0; i < 2; i++)
                {
                    RegIndex dsti = (RegIndex)i;
                    RegIndex srci;

                    if (ret[i] == null)
                        continue;

                    if (ret[i].IsVar)
                    {
                        if (((BaseVar)ret[i]).IsGPVar)
                        {
                            CompilerVar vdata = compiler.GetVarData(ret[i].Id);
                            Contract.Assert(vdata != null);

                            srci = vdata.RegisterIndex;
                            InstructionCode inst = ret[i].IsRegType(RegType.GPQ) ? InstructionCode.Movq : InstructionCode.Movd;

                            if (srci == RegIndex.Invalid)
                            {
                                compiler.Emit(inst, Register.xmm(dsti), cc.GetVarMem(vdata));
                            }
                            else
                            {
                                if (Util.IsX86)
                                    compiler.Emit(inst, Register.xmm(dsti), Register.gpd(srci));
                                else if (Util.IsX64)
                                    compiler.Emit(inst, Register.xmm(dsti), ret[i].IsRegType(RegType.GPQ) ? Register.gpq(srci) : Register.gpd(srci));
                                else
                                    throw new NotImplementedException();
                            }
                        }
                        else if (((BaseVar)ret[i]).IsX87Var)
                        {
                            // TODO: X87.
                            throw new NotImplementedException("X87 support is not yet implemented.");
                        }
                        else if (((BaseVar)ret[i]).IsMMVar)
                        {
                            CompilerVar vdata = compiler.GetVarData(ret[i].Id);
                            Contract.Assert(vdata != null);

                            srci = vdata.RegisterIndex;
                            if (srci == RegIndex.Invalid)
                                compiler.Emit(InstructionCode.Movq, Register.xmm(dsti), cc.GetVarMem(vdata));
                            else
                                compiler.Emit(InstructionCode.Movq, Register.xmm(dsti), Register.mm(srci));
                        }
                        else if (((BaseVar)ret[i]).IsXMMVar)
                        {
                            CompilerVar vdata = compiler.GetVarData(ret[i].Id);
                            Contract.Assert(vdata != null);

                            srci = vdata.RegisterIndex;
                            if (srci == RegIndex.Invalid)
                                compiler.Emit(InstructionCode.Movdqa, Register.xmm(dsti), cc.GetVarMem(vdata));
                            else if (dsti != srci)
                                compiler.Emit(InstructionCode.Movdqa, Register.xmm(dsti), Register.xmm(srci));
                        }
                    }
                }
                break;

            case VariableType.XMM_1F:
                for (i = 0; i < 2; i++)
                {
                    RegIndex dsti = (RegIndex)i;
                    RegIndex srci;

                    if (ret[i] == null)
                        continue;

                    if (ret[i].IsVar)
                    {
                        if (((BaseVar)ret[i]).IsX87Var)
                        {
                            // TODO: X87.
                        }
                        else if (((BaseVar)ret[i]).IsXMMVar)
                        {
                            CompilerVar vdata = compiler.GetVarData(ret[i].Id);
                            Contract.Assert(vdata != null);

                            srci = vdata.RegisterIndex;
                            switch (vdata.Type)
                            {
                            case VariableType.XMM:
                                if (srci == RegIndex.Invalid)
                                    compiler.Emit(InstructionCode.Movdqa, Register.xmm(dsti), cc.GetVarMem(vdata));
                                else if (dsti != srci)
                                    compiler.Emit(InstructionCode.Movdqa, Register.xmm(dsti), Register.xmm(srci));
                                break;
                            case VariableType.XMM_1F:
                            case VariableType.XMM_4F:
                                if (srci == RegIndex.Invalid)
                                    compiler.Emit(InstructionCode.Movss, Register.xmm(dsti), cc.GetVarMem(vdata));
                                else
                                    compiler.Emit(InstructionCode.Movss, Register.xmm(dsti), Register.xmm(srci));
                                break;
                            case VariableType.XMM_1D:
                            case VariableType.XMM_2D:
                                if (srci == RegIndex.Invalid)
                                    compiler.Emit(InstructionCode.Cvtsd2ss, Register.xmm(dsti), cc.GetVarMem(vdata));
                                else if (dsti != srci)
                                    compiler.Emit(InstructionCode.Cvtsd2ss, Register.xmm(dsti), Register.xmm(srci));
                                break;
                            }
                        }
                    }
                }
                break;

            case VariableType.XMM_1D:
                for (i = 0; i < 2; i++)
                {
                    RegIndex dsti = (RegIndex)i;
                    RegIndex srci;

                    if (ret[i] == null)
                        continue;

                    if (ret[i].IsVar)
                    {
                        if (((BaseVar)ret[i]).IsX87Var)
                        {
                            // TODO: X87.
                        }
                        else if (((BaseVar)ret[i]).IsXMMVar)
                        {
                            CompilerVar vdata = compiler.GetVarData(ret[i].Id);
                            Contract.Assert(vdata != null);

                            srci = vdata.RegisterIndex;
                            switch (vdata.Type)
                            {
                            case VariableType.XMM:
                                if (srci == RegIndex.Invalid)
                                    compiler.Emit(InstructionCode.Movdqa, Register.xmm(dsti), cc.GetVarMem(vdata));
                                else if (dsti != srci)
                                    compiler.Emit(InstructionCode.Movdqa, Register.xmm(dsti), Register.xmm(srci));
                                break;
                            case VariableType.XMM_1F:
                            case VariableType.XMM_4F:
                                if (srci == RegIndex.Invalid)
                                    compiler.Emit(InstructionCode.Cvtss2sd, Register.xmm(dsti), cc.GetVarMem(vdata));
                                else
                                    compiler.Emit(InstructionCode.Cvtss2sd, Register.xmm(dsti), Register.xmm(srci));
                                break;
                            case VariableType.XMM_1D:
                            case VariableType.XMM_2D:
                                if (srci == RegIndex.Invalid)
                                    compiler.Emit(InstructionCode.Movsd, Register.xmm(dsti), cc.GetVarMem(vdata));
                                else
                                    compiler.Emit(InstructionCode.Movsd, Register.xmm(dsti), Register.xmm(srci));
                                break;
                            }
                        }
                    }
                }
                break;

            case VariableType.Invalid:
            default:
                break;
            }

            if (ShouldEmitJumpToEpilog())
            {
                cc.Unreachable = true;
            }

            for (i = 0; i < 2; i++)
            {
                if (ret[i] != null && ret[i].IsVar)
                {
                    CompilerVar vdata = compiler.GetVarData(ret[i].Id);
                    Contract.Assert(vdata != null);
                    cc.UnuseVarOnEndOfScope(this, vdata);
                }
            }

            return Next;
        }