Пример #1
0
        public StateData(int memVarsCount)
        {
            if (memVarsCount < 0)
                throw new ArgumentOutOfRangeException("memVarsCount");

            _registers = new CompilerVar[RegisterCount];
            MemVarsData = new CompilerVar[memVarsCount];
        }
Пример #2
0
        public CompilerHint(Compiler compiler, CompilerVar varData, VariableHintKind hintKind, int hintValue)
            : base(compiler)
        {
            if (varData == null)
                throw new ArgumentNullException("varData");
            Contract.Requires(compiler != null);
            Contract.EndContractBlock();

            _varData = varData;
            _hintKind = hintKind;
            _hintValue = hintValue;
        }
Пример #3
0
        public StateData(StateData other, int memVarsCount)
        {
            if (other == null)
                throw new ArgumentNullException("other");
            if (memVarsCount < 0)
                throw new ArgumentOutOfRangeException("memVarsCount");

            _registers = (CompilerVar[])other._registers.Clone();
            Contract.Assume(_registers.Length == other._registers.Length);

            UsedGP = other.UsedGP;
            UsedMM = other.UsedMM;
            UsedXMM = other.UsedXMM;
            ChangedGP = other.ChangedGP;
            ChangedMM = other.ChangedMM;
            ChangedXMM = other.ChangedXMM;
            MemVarsData = new CompilerVar[memVarsCount];
        }
Пример #4
0
        // TODO: Find code which uses this and improve.
        internal void NewRegisterHomeMask(CompilerVar var, RegisterMask mask)
        {
            Contract.Requires(var != null);

            var.PreferredRegisterMask |= mask;
        }
Пример #5
0
        // TODO: Find code which uses this and improve.
        internal void NewRegisterHomeIndex(CompilerVar var, RegIndex idx)
        {
            Contract.Requires(var != null);

            if (var.HomeRegisterIndex == RegIndex.Invalid)
                var.HomeRegisterIndex = idx;

            var.PreferredRegisterMask |= RegisterMask.FromIndex(idx);
        }
Пример #6
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.");
        }
Пример #7
0
 protected virtual bool TryUnuseVarImpl(CompilerVar v)
 {
     Contract.Requires(v != null);
     return false;
 }
Пример #8
0
        public void SaveVar(CompilerVar var)
        {
            Contract.Requires(var != null);

            if (var == null)
                throw new ArgumentNullException("var");
            if (var.State != VariableState.Register || var.RegisterIndex == RegIndex.Invalid)
                throw new ArgumentException("Can't save a variable that isn't allocated.");

            switch (var.Type)
            {
            case VariableType.GPD:
            case VariableType.GPQ:
                if (var.Type == VariableType.GPQ && !Util.IsX64)
                    throw new NotSupportedException();

                break;

            case VariableType.X87:
            case VariableType.X87_1F:
            case VariableType.X87_1D:
                // TODO: X87 VARIABLES NOT IMPLEMENTED.
                throw new NotImplementedException("X87 variables are not yet implemented.");

            case VariableType.MM:
                break;

            case VariableType.XMM:
            case VariableType.XMM_1F:
            case VariableType.XMM_4F:
            case VariableType.XMM_1D:
            case VariableType.XMM_2D:
                break;

            default:
                throw new ArgumentException("The variable type is not supported.");
            }

            RegIndex idx = var.RegisterIndex;
            EmitSaveVar(var, idx);

            // Update VarData.
            var.Changed = false;
        }
Пример #9
0
        public void EmitMoveVar(CompilerVar var, RegIndex regIndex, VariableAlloc vflags)
        {
            Contract.Requires(var != null);

            if (var.RegisterIndex == RegIndex.Invalid)
                throw new ArgumentException("Caller must ensure that variable is allocated.");

            if ((vflags & VariableAlloc.Read) == 0)
                return;

            switch (var.Type)
            {
            case VariableType.GPD:
                _compiler.Emit(InstructionCode.Mov, Register.gpd(regIndex), Register.gpd(var.RegisterIndex));
                break;

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

                _compiler.Emit(InstructionCode.Mov, Register.gpq(regIndex), Register.gpq(var.RegisterIndex));
                break;

            case VariableType.X87:
            case VariableType.X87_1F:
            case VariableType.X87_1D:
                // TODO: X87 VARIABLES NOT IMPLEMENTED.
                throw new NotImplementedException("X87 variables are not yet implemented.");

            case VariableType.MM:
                _compiler.Emit(InstructionCode.Movq, Register.mm(regIndex), Register.mm(var.RegisterIndex));
                break;

            case VariableType.XMM:
                _compiler.Emit(InstructionCode.Movdqa, Register.xmm(regIndex), Register.xmm(var.RegisterIndex));
                break;
            case VariableType.XMM_1F:
                _compiler.Emit(InstructionCode.Movss, Register.xmm(regIndex), Register.xmm(var.RegisterIndex));
                break;
            case VariableType.XMM_1D:
                _compiler.Emit(InstructionCode.Movsd, Register.xmm(regIndex), Register.xmm(var.RegisterIndex));
                break;
            case VariableType.XMM_4F:
                _compiler.Emit(InstructionCode.Movaps, Register.xmm(regIndex), Register.xmm(var.RegisterIndex));
                break;
            case VariableType.XMM_2D:
                _compiler.Emit(InstructionCode.Movapd, Register.xmm(regIndex), Register.xmm(var.RegisterIndex));
                break;
            default:
                throw new CompilerException("Invalid variable type.");
            }
        }
Пример #10
0
        public void AllocXMMVar(CompilerVar var, RegisterMask regMask, VariableAlloc vflags)
        {
            Contract.Requires(var != null);
            Contract.Requires(Function != null);

            AllocNonGPVar(var, regMask, vflags, RegNum.XMM, var.Scope.Declaration.PreservedXMM, _state.UsedXMM, _state.XMM, AllocatedXMMRegister, SpillXMMVar, FreedXMMRegister);
        }
Пример #11
0
        internal void AllocatedVariable(CompilerVar var)
        {
            Contract.Requires(var != null);

            RegIndex idx = var.RegisterIndex;

            switch (var.Type)
            {
            case VariableType.GPD:
            case VariableType.GPQ:
                _state.GP[(int)idx] = var;
                AllocatedGPRegister(idx);
                break;

            case VariableType.MM:
                _state.MM[(int)idx] = var;
                AllocatedMMRegister(idx);
                break;

            case VariableType.XMM:
            case VariableType.XMM_1F:
            case VariableType.XMM_4F:
            case VariableType.XMM_1D:
            case VariableType.XMM_2D:
                _state.XMM[(int)idx] = var;
                AllocatedXMMRegister(idx);
                break;

            default:
                throw new CompilerException("Invalid variable type.");
            }
        }
Пример #12
0
        internal void AddActive(CompilerVar var)
        {
            Contract.Requires(var != null);

            if (var.NextActive != null)
                throw new ArgumentException();
            if (var.PreviousActive != null)
                throw new ArgumentException();

            if (_active == null)
            {
                var.NextActive = var;
                var.PreviousActive = var;
                _active = var;
            }
            else
            {
                CompilerVar vlast = _active.PreviousActive;
                vlast.NextActive = var;
                _active.PreviousActive = var;
                var.NextActive = _active;
                var.PreviousActive = vlast;
            }
        }
Пример #13
0
        public void UnuseVarOnEndOfScope(CompilerItem e, CompilerVar vdata)
        {
            Contract.Requires(e != null);
            Contract.Requires(vdata != null);

            if (vdata.LastItem == e)
                UnuseVar(vdata, VariableState.Unused);
        }
Пример #14
0
        public void UnuseVar(CompilerVar var, VariableState toState)
        {
            Contract.Requires(var != null);

            if (toState == VariableState.Register)
                throw new ArgumentException();

            if (var.State == VariableState.Register)
            {
                RegIndex registerIndex = var.RegisterIndex;
                switch (var.Type)
                {
                case VariableType.GPD:
                case VariableType.GPQ:
                    if (var.Type == VariableType.GPQ && !Util.IsX64)
                        throw new NotSupportedException();

                    _state.GP[(int)registerIndex] = null;
                    FreedGPRegister(registerIndex);
                    break;

                case VariableType.X87:
                case VariableType.X87_1F:
                case VariableType.X87_1D:
                    // TODO: X87 VARIABLES NOT IMPLEMENTED.
                    break;

                case VariableType.MM:
                    _state.MM[(int)registerIndex] = null;
                    FreedMMRegister(registerIndex);
                    break;

                case VariableType.XMM:
                case VariableType.XMM_1F:
                case VariableType.XMM_4F:
                case VariableType.XMM_1D:
                case VariableType.XMM_2D:
                    _state.XMM[(int)registerIndex] = null;
                    FreedXMMRegister(registerIndex);
                    break;
                default:
                    throw new CompilerException("Invalid variable type.");
                }
            }

            var.State = toState;
            var.Changed = false;
            var.RegisterIndex = RegIndex.Invalid;
        }
Пример #15
0
 public void SpillXMMVar(CompilerVar var)
 {
     Contract.Requires(var != null);
     SpillVar(var, _state.XMM, FreedXMMRegister);
 }
Пример #16
0
        public void SpillVar(CompilerVar var)
        {
            Contract.Requires(var != null);

            switch (var.Type)
            {
            case VariableType.GPD:
            case VariableType.GPQ:
                if (var.Type == VariableType.GPQ && !Util.IsX64)
                    throw new NotSupportedException();

                SpillGPVar(var);
                break;

            case VariableType.X87:
            case VariableType.X87_1F:
            case VariableType.X87_1D:
                // TODO: X87 VARIABLES NOT IMPLEMENTED.
                throw new NotImplementedException("X87 variables are not yet implemented.");

            case VariableType.MM:
                SpillMMVar(var);
                break;

            case VariableType.XMM:
            case VariableType.XMM_1F:
            case VariableType.XMM_4F:
            case VariableType.XMM_1D:
            case VariableType.XMM_2D:
                SpillXMMVar(var);
                break;
            default:
                throw new CompilerException("Invalid variable type.");
            }
        }
Пример #17
0
        public void SpillGPVar(CompilerVar var)
        {
            Contract.Requires(var != null);
            Contract.Requires(var.State == VariableState.Register);
            Contract.Requires(var.RegisterIndex != RegIndex.Invalid);

            SpillVar(var, _state.GP, FreedGPRegister);
        }
Пример #18
0
        public void AllocGPVar(CompilerVar var, RegisterMask regMask, VariableAlloc variableAlloc)
        {
            Contract.Requires(var != null);
            Contract.Requires(Function != null);

            RegisterMask fullMask = RegisterMask.MaskToIndex(RegNum.GP) & ~RegisterMask.FromIndex(RegIndex.Esp);
            if (!_allocableEBP)
                fullMask &= ~RegisterMask.FromIndex(RegIndex.Ebp);

              // Fix the regMask (0 or full bit-array means that any register may be used).
            if (regMask == RegisterMask.Zero)
                regMask = RegisterMask.MaskToIndex(RegNum.GP);
            regMask &= fullMask;

            int i;
            RegisterMask mask;

            // Last register code (aka home).
            RegIndex home = var.HomeRegisterIndex;
            // New register code.
            RegIndex idx = RegIndex.Invalid;

            // Preserved GP variables.
            RegisterMask preservedGP = var.Scope.Declaration.PreservedGP;

            // Spill candidate.
            CompilerVar spillCandidate = null;
            // spill caused by direct jump to L_Spill
            bool doSpill = false;

            // Whether to alloc the non-preserved variables first.
            bool nonPreservedFirst = true;
            if (Function.IsCaller)
            {
                nonPreservedFirst = var.FirstCallable == null ||
                       var.FirstCallable.Offset >= var.LastItem.Offset;
            }

            // --------------------------------------------------------------------------
            // [Already Allocated]
            // --------------------------------------------------------------------------

            // Go away if variable is already allocated.
            if (var.State == VariableState.Register)
            {
                RegIndex oldIndex = var.RegisterIndex;

                // Already allocated in the right register.
                if ((RegisterMask.FromIndex(oldIndex) & regMask) != RegisterMask.Zero)
                    return;

                // Try to find unallocated register first.
                mask = regMask & ~_state.UsedGP;
                if (mask != RegisterMask.Zero)
                {
                    idx = ((nonPreservedFirst && (mask & ~preservedGP) != RegisterMask.Zero) ? mask & ~preservedGP : mask).FirstRegister;
                }
                // Then find the allocated and exchange later.
                else
                {
                    idx = (regMask & _state.UsedGP).FirstRegister;
                }

                Contract.Assert(idx != RegIndex.Invalid);

                CompilerVar other = _state.GP[(int)idx];
                EmitExchangeVar(var, idx, variableAlloc, other);

                _state.GP[(int)oldIndex] = other;
                _state.GP[(int)idx] = var;

                if (other != null)
                    other.RegisterIndex = oldIndex;
                else
                    FreedGPRegister(oldIndex);

                // Update VarData.
                var.State = VariableState.Register;
                var.RegisterIndex = idx;
                var.HomeRegisterIndex = idx;

                AllocatedGPRegister(idx);
                return;
            }

            // --------------------------------------------------------------------------
            // [Find Unused GP]
            // --------------------------------------------------------------------------

            // Home register code.
            if (idx == RegIndex.Invalid
                && home != RegIndex.Invalid
                && (regMask & RegisterMask.FromIndex(home)) != RegisterMask.Zero
                && (State.UsedGP & RegisterMask.FromIndex(home)) == RegisterMask.Zero)
            {
                idx = home;
                goto _Alloc;
            }

            // We start from 1, because EAX/RAX register is sometimes explicitly
            // needed. So we trying to prevent reallocation in near future.
            if (idx == RegIndex.Invalid)
            {
                for (i = 1, mask = RegisterMask.FromIndex((RegIndex)i); i < (int)RegNum.GP; i++, mask = RegisterMask.FromIndex((RegIndex)i))
                {
                    if ((regMask & mask) != RegisterMask.Zero && (_state.UsedGP & mask) == RegisterMask.Zero)
                    {
                        // Convenience to alloc non-preserved first or non-preserved last.
                        if (nonPreservedFirst)
                        {
                            if (idx != RegIndex.Invalid && (preservedGP & mask) != RegisterMask.Zero)
                                continue;

                            idx = (RegIndex)i;
                            // If current register is preserved, we should try to find different
                            // one that is not. This can save one push / pop in prolog / epilog.
                            if ((preservedGP & mask) == RegisterMask.Zero)
                                break;
                        }
                        else
                        {
                            if (idx != RegIndex.Invalid && (preservedGP & mask) == RegisterMask.Zero)
                                continue;

                            idx = (RegIndex)i;
                            // The opposite.
                            if ((preservedGP & mask) != RegisterMask.Zero)
                                break;
                        }
                    }
                }
            }

            // If not found, try EAX/RAX.
            if (idx == RegIndex.Invalid
                && (regMask & RegisterMask.FromIndex(RegIndex.Eax)) != RegisterMask.Zero
                && (_state.UsedGP & RegisterMask.FromIndex(RegIndex.Eax)) == RegisterMask.Zero)
            {
                idx = RegIndex.Eax;
                goto _Alloc;
            }

            // If regMask contains restricted registers which may be used then everything
            // is handled inside this block.
            if (idx == RegIndex.Invalid && regMask != fullMask)
            {
                // Try to find unallocated register first.
                mask = regMask & ~_state.UsedGP;
                if (mask != RegisterMask.Zero)
                {
                    idx = ((nonPreservedFirst && (mask & ~preservedGP) != RegisterMask.Zero) ? (mask & ~preservedGP) : mask).FirstRegister;
                    Contract.Assert(idx != RegIndex.Invalid);
                }
                // Then find the allocated and spill later.
                else
                {
                    idx = (regMask & _state.UsedGP).FirstRegister;
                    Contract.Assert(idx != RegIndex.Invalid);

                    // Spill register we need.
                    spillCandidate = _state.GP[(int)idx];

                    // Jump to spill part of allocation.
                    doSpill = true;
                    goto L_Spill;
                }
            }

            // --------------------------------------------------------------------------
            // [Spill]
            // --------------------------------------------------------------------------

            // If register is still not found, spill other variable.
            if (idx == RegIndex.Invalid)
            {
                if (spillCandidate == null)
                {
                    spillCandidate = GetSpillCandidateGP();
                }

                // Spill candidate not found?
                if (spillCandidate == null)
                {
                    throw new CompilerException("Not enough registers.");
                }
            }

            L_Spill:

            if (idx == RegIndex.Invalid || doSpill)
            {
                // Prevented variables can't be spilled. _getSpillCandidate() never returns
                // prevented variables, but when jumping to L_Spill it can happen.
                if (spillCandidate.WorkOffset == _currentOffset)
                {
                    throw new CompilerException("Registers overlap.");
                }

                idx = spillCandidate.RegisterIndex;
                SpillGPVar(spillCandidate);
            }

            // --------------------------------------------------------------------------
            // [Alloc]
            // --------------------------------------------------------------------------

            _Alloc:
            if (var.State == VariableState.Memory && (variableAlloc & VariableAlloc.Read) != 0)
            {
                EmitLoadVar(var, idx);
            }

            // Update VarData.
            var.State = VariableState.Register;
            var.RegisterIndex = idx;
            var.HomeRegisterIndex = idx;

            // Update StateData.
            AllocatedVariable(var);
        }
Пример #19
0
        public void AllocVar(CompilerVar var, RegisterMask regMask, VariableAlloc variableAlloc)
        {
            Contract.Requires(var != null);

            switch (var.Type)
            {
            case VariableType.GPD:
            case VariableType.GPQ:
                if (var.Type == VariableType.GPQ && !Util.IsX64)
                    throw new NotSupportedException();

                AllocGPVar(var, regMask, variableAlloc);
                break;

            case VariableType.X87:
            case VariableType.X87_1F:
            case VariableType.X87_1D:
                // TODO: X87 VARIABLES NOT IMPLEMENTED.
                break;

            case VariableType.MM:
                AllocMMVar(var, regMask, variableAlloc);
                break;

            case VariableType.XMM:
            case VariableType.XMM_1F:
            case VariableType.XMM_4F:
            case VariableType.XMM_1D:
            case VariableType.XMM_2D:
                AllocXMMVar(var, regMask, variableAlloc);
                break;
            }

            PostAlloc(var, variableAlloc);
        }
Пример #20
0
        internal void Clear()
        {
            Contract.Ensures(Function == null);

            //_zone.clear();
            _function = null;

            _start = null;
            _stop = null;

            _state.Clear();
            _active = null;

            _forwardJumps = null;

            _currentOffset = 0;
            //_unreachable = 0;

            _modifiedGPRegisters = RegisterMask.Zero;
            _modifiedMMRegisters = RegisterMask.Zero;
            _modifiedXMMRegisters = RegisterMask.Zero;

            _allocableEBP = false;

            _adjustESP = 0;

            _argumentsBaseReg = RegIndex.Invalid;
            _argumentsBaseOffset = 0;
            _argumentsActualDisp = 0;

            _variablesBaseReg = RegIndex.Invalid;
            _variablesBaseOffset = 0;
            _variablesActualDisp = 0;

            _memUsed = null;
            _memFree = null;

            _mem4BlocksCount = 0;
            _mem8BlocksCount = 0;
            _mem16BlocksCount = 0;

            _memBytesTotal = 0;

            _backCode.Clear();
            _backPos = 0;
        }
Пример #21
0
        public void EmitExchangeVar(CompilerVar var, RegIndex regIndex, VariableAlloc vflags, CompilerVar other)
        {
            Contract.Requires(var != null);
            Contract.Requires(other != null);

            if (var.RegisterIndex == RegIndex.Invalid)
                throw new CompilerException("Caller must ensure that variable is allocated.");

            // If other is not valid then we can just emit MOV (or other similar instruction).
            if (other == null)
            {
                EmitMoveVar(var, regIndex, vflags);
                return;
            }

            // If we need to alloc for write-only operation then we can move other
            // variable away instead of exchanging them.
            if ((vflags & VariableAlloc.Read) == 0)
            {
                EmitMoveVar(other, var.RegisterIndex, VariableAlloc.Read);
                return;
            }

            switch (var.Type)
            {
            case VariableType.GPD:
                _compiler.Emit(InstructionCode.Xchg, Register.gpd(regIndex), Register.gpd(var.RegisterIndex));
                break;

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

                _compiler.Emit(InstructionCode.Xchg, Register.gpq(regIndex), Register.gpq(var.RegisterIndex));
                break;

            case VariableType.X87:
            case VariableType.X87_1F:
            case VariableType.X87_1D:
                // TODO: X87 VARIABLES NOT IMPLEMENTED.
                break;

            // NOTE: MM and XMM registers shoudln't be exchanged using this way, it's
            // correct, but it sucks.

            case VariableType.MM:
                {
                    MMReg a = Register.mm(regIndex);
                    MMReg b = Register.mm(var.RegisterIndex);

                    _compiler.Emit(InstructionCode.Pxor, a, b);
                    _compiler.Emit(InstructionCode.Pxor, b, a);
                    _compiler.Emit(InstructionCode.Pxor, a, b);
                    break;
                }

            case VariableType.XMM_1F:
            case VariableType.XMM_4F:
                {
                    XMMReg a = Register.xmm(regIndex);
                    XMMReg b = Register.xmm(var.RegisterIndex);

                    _compiler.Emit(InstructionCode.Xorps, a, b);
                    _compiler.Emit(InstructionCode.Xorps, b, a);
                    _compiler.Emit(InstructionCode.Xorps, a, b);
                    break;
                }

            case VariableType.XMM_1D:
            case VariableType.XMM_2D:
                {
                    XMMReg a = Register.xmm(regIndex);
                    XMMReg b = Register.xmm(var.RegisterIndex);

                    _compiler.Emit(InstructionCode.Xorpd, a, b);
                    _compiler.Emit(InstructionCode.Xorpd, b, a);
                    _compiler.Emit(InstructionCode.Xorpd, a, b);
                    break;
                }

            case VariableType.XMM:
                {
                    XMMReg a = Register.xmm(regIndex);
                    XMMReg b = Register.xmm(var.RegisterIndex);

                    _compiler.Emit(InstructionCode.Pxor, a, b);
                    _compiler.Emit(InstructionCode.Pxor, b, a);
                    _compiler.Emit(InstructionCode.Pxor, a, b);
                    break;
                }
            }
        }
Пример #22
0
        internal void FreeActive(CompilerVar var)
        {
            Contract.Requires(var != null);

            CompilerVar next = var.NextActive;
            CompilerVar prev = var.PreviousActive;

            if (prev == next)
            {
                _active = null;
            }
            else
            {
                if (_active == var)
                    _active = next;
                prev.NextActive = next;
                next.PreviousActive = prev;
            }

            var.NextActive = null;
            var.PreviousActive = null;
        }
Пример #23
0
        public void EmitSaveVar(CompilerVar var, RegIndex regIndex)
        {
            Contract.Requires(var != null);

            if (var == null)
                throw new ArgumentNullException("var");
            if (regIndex == RegIndex.Invalid)
                throw new ArgumentException("Caller must ensure that variable is allocated.");

            Mem m = GetVarMem(var);

            switch (var.Type)
            {
            case VariableType.GPD:
                _compiler.Emit(InstructionCode.Mov, m, Register.gpd(regIndex));
                if (_emitComments)
                    goto addComment;
                break;

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

                _compiler.Emit(InstructionCode.Mov, m, Register.gpq(regIndex));
                if (_emitComments)
                    goto addComment;
                break;

            case VariableType.X87:
            case VariableType.X87_1F:
            case VariableType.X87_1D:
                // TODO: X87 VARIABLES NOT IMPLEMENTED.
                break;

            case VariableType.MM:
                _compiler.Emit(InstructionCode.Movq, m, Register.mm(regIndex));
                if (_emitComments)
                    goto addComment;
                break;

            case VariableType.XMM:
                _compiler.Emit(InstructionCode.Movdqa, m, Register.xmm(regIndex));
                if (_emitComments)
                    goto addComment;
                break;
            case VariableType.XMM_1F:
                _compiler.Emit(InstructionCode.Movss, m, Register.xmm(regIndex));
                if (_emitComments)
                    goto addComment;
                break;
            case VariableType.XMM_1D:
                _compiler.Emit(InstructionCode.Movsd, m, Register.xmm(regIndex));
                if (_emitComments)
                    goto addComment;
                break;
            case VariableType.XMM_4F:
                _compiler.Emit(InstructionCode.Movaps, m, Register.xmm(regIndex));
                if (_emitComments)
                    goto addComment;
                break;
            case VariableType.XMM_2D:
                _compiler.Emit(InstructionCode.Movapd, m, Register.xmm(regIndex));
                if (_emitComments)
                    goto addComment;
                break;
            default:
                throw new CompilerException("Invalid variable type.");
            }
            return;

            addComment:
            _compiler.CurrentItem.Comment = string.Format("Spill {0}", var.Name);
        }
Пример #24
0
        internal Mem GetVarMem(CompilerVar var)
        {
            Contract.Requires(var != null);
            Contract.Ensures(Contract.Result<Mem>() != null);

            Mem m = new Mem(var.Id);
            if (!var.IsMemArgument)
                m.Displacement = (IntPtr)_adjustESP;

            MarkMemoryUsed(var);
            return m;
        }
Пример #25
0
        /// <summary>
        /// Try to unuse the variable <paramref name="v"/>.
        /// </summary>
        /// <param name="v"></param>
        /// <returns>
        /// @c true only if the variable will be unused by the instruction,
        /// otherwise @c false is returned.
        /// </returns>
        public bool TryUnuseVar(CompilerVar v)
        {
            Contract.Requires(v != null);

            return TryUnuseVarImpl(v);
        }
Пример #26
0
        protected override bool TryUnuseVarImpl(CompilerVar v)
        {
            for (uint i = 0; i < _variables.Length; i++)
            {
                if (_variables[i].VarData == v)
                {
                    _variables[i].VarFlags |= VariableAlloc.UnuseAfterUse;
                    return true;
                }
            }

            return false;
        }
Пример #27
0
        internal bool IsActive(CompilerVar var)
        {
            Contract.Requires(var != null);

            return var.NextActive != null;
        }
Пример #28
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.");
            }
        }
Пример #29
0
        public static GPVar FromData(CompilerVar vdata)
        {
            Contract.Requires(vdata != null);

            return new GPVar(vdata.Id, vdata.Size, VariableInfo.GetVariableInfo(vdata.Type).RegisterType, vdata.Type);
        }
Пример #30
0
        internal void MarkMemoryUsed(CompilerVar var)
        {
            Contract.Requires(var != null);

            if (var.HomeMemoryData != null)
                return;

            VarMemBlock mem = AllocMemBlock(var.Size);
            if (mem == null)
                return;

            var.HomeMemoryData = mem;
        }