Пример #1
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.");
            }
        }
Пример #2
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;
                }
            }
        }
Пример #3
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);
        }
Пример #4
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);
        }
Пример #5
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);
        }