Пример #1
0
        private static bool Exchange(RegisterMask[] masks, int blkIndex, RegisterMask value)
        {
            RegisterMask oldValue = masks[blkIndex];

            masks[blkIndex] = value;

            return(oldValue != value);
        }
Пример #2
0
 internal FunctionDeclaration(CallingConvention callingConvention, VariableType[] arguments, VariableType @return)
 {
     Used              = new RegisterMask();
     Passed            = new RegisterMask();
     Preserved         = new RegisterMask();
     CallingConvention = callingConvention == CallingConvention.Default ? Constants.DefaultCallingConvention : callingConvention;
     _returns          = new FunctionInOut[2];
     _arguments        = new FunctionInOut[arguments.Length];
     Init(arguments, @return);
 }
Пример #3
0
 public FunctionNode(LabelNode entry, LabelNode exit, VariableType[] arguments, VariableType @return, CallingConvention callingConvention)
     : base(CodeNodeType.Function)
 {
     Entry = entry;
     Exit  = exit;
     End   = new SentinelNode();
     FunctionDeclaration   = new FunctionDeclaration(callingConvention, arguments, @return);
     _arguments            = new VariableData[arguments.Length];
     StackFrameCopyGpIndex = new int[6].InitializeWith(() => RegisterIndex.Invalid);
     SaveRestoreRegs       = new RegisterMask();
     StackFrameRegIndex    = RegisterIndex.Invalid;
     _hints = Utils.Mask((int)FuncionNodeHints.Naked);
 }
Пример #4
0
        private void EmitStoreContext(ILGenerator generator, BasicBlock block)
        {
            RegisterMask outputs = _regUsage.GetOutputs(block);

            long intOutputs = outputs.IntMask;
            long vecOutputs = outputs.VecMask;

            if (Optimizations.AssumeStrictAbiCompliance && _isComplete)
            {
                intOutputs = RegisterUsage.ClearCallerSavedIntRegs(intOutputs, _mode);
                vecOutputs = RegisterUsage.ClearCallerSavedVecRegs(vecOutputs, _mode);
            }

            StoreLocals(generator, intOutputs, RegisterType.Int);
            StoreLocals(generator, vecOutputs, RegisterType.Vector);
        }
Пример #5
0
        private void SetPrototype(VariableType[] arguments, VariableType returnValue)
        {
            if (arguments == null)
                throw new ArgumentNullException("arguments");
            if (arguments.Length > 32)
                throw new ArgumentException();
            Contract.EndContractBlock();

            int i;

            int posGP = 0;
            int posXMM = 0;
            int stackOffset = 0;

            _returnValue = returnValue;

            if (arguments.Length == 0)
            {
                _arguments = new Argument[0];
                return;
            }

            ArgumentData[] argumentData;
            argumentData = Array.ConvertAll(arguments, a => new ArgumentData(a, RegIndex.Invalid, InvalidValue));

            // --------------------------------------------------------------------------
            // [X86 Calling Conventions (32-bit)]
            // --------------------------------------------------------------------------

            if (Util.IsX86)
            {
                // Register arguments (Integer), always left-to-right.
                for (i = 0; i != arguments.Length; i++)
                {
                    ArgumentData a = argumentData[i];
                    if (VariableInfo.IsVariableInteger(a._variableType) && posGP < 16 && CallingConventionInfo.ArgumentsGPList[posGP] != RegIndex.Invalid)
                    {
                        a._registerIndex = CallingConventionInfo.ArgumentsGPList[posGP++];
                        _passedGP |= RegisterMask.FromIndex(a._registerIndex);
                    }
                }

                // Stack arguments.
                bool ltr = CallingConventionInfo.ArgumentsDirection == ArgumentsDirection.LeftToRight;
                int istart = ltr ? 0 : arguments.Length - 1;
                int iend = ltr ? arguments.Length : -1;
                int istep = ltr ? 1 : -1;

                for (i = istart; i != iend; i += istep)
                {
                    ArgumentData a = argumentData[i];
                    if (a._registerIndex != RegIndex.Invalid)
                        continue;

                    if (VariableInfo.IsVariableInteger(a._variableType))
                    {
                        stackOffset -= 4;
                        a._stackOffset = stackOffset;
                    }
                    else if (VariableInfo.IsVariableFloat(a._variableType))
                    {
                        int size = VariableInfo.GetVariableInfo(a._variableType).Size;
                        stackOffset -= size;
                        a._stackOffset = stackOffset;
                    }
                }
            }

            // --------------------------------------------------------------------------
            // [X64 Calling Conventions (64-bit)]
            // --------------------------------------------------------------------------

            if (Util.IsX64)
            {
                // Windows 64-bit specific.
                if (_callingConvention == CallingConvention.X64W)
                {
                    int max = Math.Min(arguments.Length, 4);

                    // Register arguments (Integer / FP), always left to right.
                    for (i = 0; i != max; i++)
                    {
                        ArgumentData a = argumentData[i];

                        if (VariableInfo.IsVariableInteger(a._variableType))
                        {
                            a._registerIndex = CallingConventionInfo.ArgumentsGPList[i];
                            _passedGP |= RegisterMask.FromIndex(a._registerIndex);
                        }
                        else if (VariableInfo.IsVariableFloat(a._variableType))
                        {
                            a._registerIndex = CallingConventionInfo.ArgumentsXMMList[i];
                            _passedXMM |= RegisterMask.FromIndex(a._registerIndex);
                        }
                    }

                    // Stack arguments (always right-to-left).
                    for (i = arguments.Length - 1; i != -1; i--)
                    {
                        ArgumentData a = argumentData[i];
                        if (a.IsAssigned)
                            continue;

                        if (VariableInfo.IsVariableInteger(a._variableType))
                        {
                            stackOffset -= 8; // Always 8 bytes.
                            a._stackOffset = stackOffset;
                        }
                        else if (VariableInfo.IsVariableFloat(a._variableType))
                        {
                            int size = VariableInfo.GetVariableInfo(a._variableType).Size;
                            stackOffset -= size;
                            a._stackOffset = stackOffset;
                        }
                    }

                    // 32 bytes shadow space (X64W calling convention specific).
                    stackOffset -= 4 * 8;
                }
                // Linux/Unix 64-bit (AMD64 calling convention).
                else
                {
                    // Register arguments (Integer), always left to right.
                    for (i = 0; i != arguments.Length; i++)
                    {
                        ArgumentData a = argumentData[i];
                        if (VariableInfo.IsVariableInteger(a._variableType) && posGP < 32 && CallingConventionInfo.ArgumentsGPList[posGP] != RegIndex.Invalid)
                        {
                            a._registerIndex = CallingConventionInfo.ArgumentsGPList[posGP++];
                            _passedGP |= RegisterMask.FromIndex(a._registerIndex);
                        }
                    }

                    // Register arguments (FP), always left to right.
                    for (i = 0; i != arguments.Length; i++)
                    {
                        ArgumentData a = argumentData[i];
                        if (VariableInfo.IsVariableFloat(a._variableType))
                        {
                            a._registerIndex = CallingConventionInfo.ArgumentsXMMList[posXMM++];
                            _passedXMM |= RegisterMask.FromIndex(a._registerIndex);
                        }
                    }

                    // Stack arguments.
                    for (i = arguments.Length - 1; i != -1; i--)
                    {
                        ArgumentData a = argumentData[i];
                        if (a.IsAssigned)
                            continue;

                        if (VariableInfo.IsVariableInteger(a._variableType))
                        {
                            stackOffset -= 8;
                            a._stackOffset = stackOffset;
                        }
                        else if (VariableInfo.IsVariableFloat(a._variableType))
                        {
                            int size = VariableInfo.GetVariableInfo(a._variableType).Size;

                            stackOffset -= size;
                            a._stackOffset = stackOffset;
                        }
                    }
                }
            }

            // Modify stack offset (all function parameters will be in positive stack
            // offset that is never zero).
            for (i = 0; i < arguments.Length; i++)
            {
                if (argumentData[i]._registerIndex == RegIndex.Invalid)
                    argumentData[i]._stackOffset += IntPtr.Size - stackOffset;
            }

            _argumentsStackSize = -stackOffset;

            _arguments = Array.ConvertAll(argumentData, data => new Argument(data._variableType, data._registerIndex, data._stackOffset));
        }
Пример #6
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;
        }
Пример #7
0
        public RegisterUsage(BasicBlock entryBlock, int blocksCount)
        {
            _inputs  = new RegisterMask[blocksCount];
            _outputs = new RegisterMask[blocksCount];

            HashSet <BasicBlock> visited = new HashSet <BasicBlock>();

            Stack <BasicBlock> blockStack = new Stack <BasicBlock>();

            List <BasicBlock> postOrderBlocks = new List <BasicBlock>(blocksCount);

            visited.Add(entryBlock);

            blockStack.Push(entryBlock);

            while (blockStack.TryPop(out BasicBlock block))
            {
                if (block.Next != null && visited.Add(block.Next))
                {
                    blockStack.Push(block);
                    blockStack.Push(block.Next);
                }
                else if (block.Branch != null && visited.Add(block.Branch))
                {
                    blockStack.Push(block);
                    blockStack.Push(block.Branch);
                }
                else
                {
                    postOrderBlocks.Add(block);
                }
            }

            RegisterMask[] cmnOutputMasks = new RegisterMask[blocksCount];

            bool modified;

            bool firstPass = true;

            do
            {
                modified = false;

                for (int blkIndex = postOrderBlocks.Count - 1; blkIndex >= 0; blkIndex--)
                {
                    BasicBlock block = postOrderBlocks[blkIndex];

                    if (block.Predecessors.Count != 0 && !block.HasStateLoad)
                    {
                        BasicBlock predecessor = block.Predecessors[0];

                        RegisterMask cmnOutputs = predecessor.RegOutputs | cmnOutputMasks[predecessor.Index];

                        RegisterMask outputs = _outputs[predecessor.Index];

                        for (int pIndex = 1; pIndex < block.Predecessors.Count; pIndex++)
                        {
                            predecessor = block.Predecessors[pIndex];

                            cmnOutputs &= predecessor.RegOutputs | cmnOutputMasks[predecessor.Index];

                            outputs |= _outputs[predecessor.Index];
                        }

                        _inputs[block.Index] |= outputs & ~cmnOutputs;

                        if (!firstPass)
                        {
                            cmnOutputs &= cmnOutputMasks[block.Index];
                        }

                        if (Exchange(cmnOutputMasks, block.Index, cmnOutputs))
                        {
                            modified = true;
                        }

                        outputs |= block.RegOutputs;

                        if (Exchange(_outputs, block.Index, _outputs[block.Index] | outputs))
                        {
                            modified = true;
                        }
                    }
                    else if (Exchange(_outputs, block.Index, block.RegOutputs))
                    {
                        modified = true;
                    }
                }

                firstPass = false;
            }while (modified);

            do
            {
                modified = false;

                for (int blkIndex = 0; blkIndex < postOrderBlocks.Count; blkIndex++)
                {
                    BasicBlock block = postOrderBlocks[blkIndex];

                    RegisterMask inputs = block.RegInputs;

                    if (block.Next != null)
                    {
                        inputs |= _inputs[block.Next.Index];
                    }

                    if (block.Branch != null)
                    {
                        inputs |= _inputs[block.Branch.Index];
                    }

                    inputs &= ~cmnOutputMasks[block.Index];

                    if (Exchange(_inputs, block.Index, _inputs[block.Index] | inputs))
                    {
                        modified = true;
                    }
                }
            }while (modified);
        }
Пример #8
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);
        }
Пример #9
0
        // TODO: Find code which uses this and improve.
        internal void NewRegisterHomeMask(CompilerVar var, RegisterMask mask)
        {
            Contract.Requires(var != null);

            var.PreferredRegisterMask |= mask;
        }
Пример #10
0
 internal void MarkXMMRegisterModified(RegIndex index)
 {
     _modifiedXMMRegisters |= RegisterMask.FromIndex(index);
 }
Пример #11
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;
        }
Пример #12
0
 internal void AllocatedXMMRegister(RegIndex index)
 {
     _state.UsedXMM |= RegisterMask.FromIndex(index);
     _modifiedXMMRegisters |= RegisterMask.FromIndex(index);
 }
Пример #13
0
        private CallingConventionInfo(CallingConvention callingConvention)
        {
            _callingConvention = callingConvention;
            _argumentsDirection = ArgumentsDirection.RightToLeft;

            RegIndex[] argumentsGPList = new RegIndex[(int)RegNum.GP];
            RegIndex[] argumentsXMMList = new RegIndex[(int)RegNum.XMM];

            for (int i = 0; i < argumentsGPList.Length; i++)
                argumentsGPList[i] = RegIndex.Invalid;
            for (int i = 0; i < argumentsXMMList.Length; i++)
                argumentsXMMList[i] = RegIndex.Invalid;

            if (Util.IsX86)
            {
                _preservedGP =
                    RegisterMask.FromIndex(RegIndex.Ebx) |
                    RegisterMask.FromIndex(RegIndex.Esp) |
                    RegisterMask.FromIndex(RegIndex.Ebp) |
                    RegisterMask.FromIndex(RegIndex.Esi) |
                    RegisterMask.FromIndex(RegIndex.Edi);
                _preservedXMM = RegisterMask.Zero;

                switch (_callingConvention)
                {
                case NAsmJit.CallingConvention.Cdecl:
                    _calleePopsStack = false;
                    break;

                case NAsmJit.CallingConvention.StdCall:
                    _calleePopsStack = true;
                    break;

                case NAsmJit.CallingConvention.MsThisCall:
                    _calleePopsStack = true;
                    argumentsGPList[0] = RegIndex.Ecx;
                    _argumentsGP = RegisterMask.FromIndex(RegIndex.Ecx);
                    break;

                case NAsmJit.CallingConvention.MsFastCall:
                    _calleePopsStack = true;
                    argumentsGPList[0] = RegIndex.Ecx;
                    argumentsGPList[1] = RegIndex.Edx;
                    _argumentsGP = RegisterMask.FromIndex(RegIndex.Ecx) |
                                   RegisterMask.FromIndex(RegIndex.Edx);
                    break;

                case NAsmJit.CallingConvention.BorlandFastCall:
                    _calleePopsStack = true;
                    _argumentsDirection = ArgumentsDirection.LeftToRight;
                    argumentsGPList[0] = RegIndex.Eax;
                    argumentsGPList[1] = RegIndex.Edx;
                    argumentsGPList[2] = RegIndex.Ecx;

                    _argumentsGP = RegisterMask.FromIndex(RegIndex.Eax) |
                                   RegisterMask.FromIndex(RegIndex.Edx) |
                                   RegisterMask.FromIndex(RegIndex.Ecx);
                    break;

                case NAsmJit.CallingConvention.GccFastCall:
                    _calleePopsStack = true;
                    argumentsGPList[0] = RegIndex.Ecx;
                    argumentsGPList[1] = RegIndex.Edx;

                    _argumentsGP = RegisterMask.FromIndex(RegIndex.Ecx) |
                                   RegisterMask.FromIndex(RegIndex.Edx);
                    break;

                case NAsmJit.CallingConvention.GccRegParm1:
                    _calleePopsStack = false;
                    argumentsGPList[0] = RegIndex.Eax;

                    _argumentsGP = RegisterMask.FromIndex(RegIndex.Eax);
                    break;

                case NAsmJit.CallingConvention.GccRegParm2:
                    _calleePopsStack = false;
                    argumentsGPList[0] = RegIndex.Eax;
                    argumentsGPList[1] = RegIndex.Edx;

                    _argumentsGP = RegisterMask.FromIndex(RegIndex.Eax) |
                                   RegisterMask.FromIndex(RegIndex.Edx);
                    break;

                case NAsmJit.CallingConvention.GccRegParm3:
                    _calleePopsStack = false;
                    argumentsGPList[0] = RegIndex.Eax;
                    argumentsGPList[1] = RegIndex.Edx;
                    argumentsGPList[2] = RegIndex.Ecx;

                    _argumentsGP = RegisterMask.FromIndex(RegIndex.Eax) |
                                   RegisterMask.FromIndex(RegIndex.Edx) |
                                   RegisterMask.FromIndex(RegIndex.Ecx);
                    break;

                default:
                    throw new NotSupportedException(string.Format("The calling convention '{0}' is not supported on this platform.", callingConvention));
                }
            }
            else if (Util.IsX64)
            {
                switch (_callingConvention)
                {
                case CallingConvention.X64W:
                    argumentsGPList[0] = RegIndex.Rcx;
                    argumentsGPList[1] = RegIndex.Rdx;
                    argumentsGPList[2] = RegIndex.R8;
                    argumentsGPList[3] = RegIndex.R9;

                    argumentsXMMList[0] = RegIndex.Xmm0;
                    argumentsXMMList[1] = RegIndex.Xmm1;
                    argumentsXMMList[2] = RegIndex.Xmm2;
                    argumentsXMMList[3] = RegIndex.Xmm3;

                    _argumentsGP = RegisterMask.FromIndex(RegIndex.Rcx) |
                                   RegisterMask.FromIndex(RegIndex.Rdx) |
                                   RegisterMask.FromIndex(RegIndex.R8) |
                                   RegisterMask.FromIndex(RegIndex.R9);

                    _argumentsXMM = RegisterMask.FromIndex(RegIndex.Xmm0) |
                                    RegisterMask.FromIndex(RegIndex.Xmm1) |
                                    RegisterMask.FromIndex(RegIndex.Xmm2) |
                                    RegisterMask.FromIndex(RegIndex.Xmm3);

                    _preservedGP =
                        RegisterMask.FromIndex(RegIndex.Rbx) |
                        RegisterMask.FromIndex(RegIndex.Rsp) |
                        RegisterMask.FromIndex(RegIndex.Rbp) |
                        RegisterMask.FromIndex(RegIndex.Rsi) |
                        RegisterMask.FromIndex(RegIndex.Rdi) |
                        RegisterMask.FromIndex(RegIndex.R12) |
                        RegisterMask.FromIndex(RegIndex.R13) |
                        RegisterMask.FromIndex(RegIndex.R14) |
                        RegisterMask.FromIndex(RegIndex.R15);
                    _preservedXMM =
                        RegisterMask.FromIndex(RegIndex.Xmm6) |
                        RegisterMask.FromIndex(RegIndex.Xmm7) |
                        RegisterMask.FromIndex(RegIndex.Xmm8) |
                        RegisterMask.FromIndex(RegIndex.Xmm9) |
                        RegisterMask.FromIndex(RegIndex.Xmm10) |
                        RegisterMask.FromIndex(RegIndex.Xmm11) |
                        RegisterMask.FromIndex(RegIndex.Xmm12) |
                        RegisterMask.FromIndex(RegIndex.Xmm13) |
                        RegisterMask.FromIndex(RegIndex.Xmm14) |
                        RegisterMask.FromIndex(RegIndex.Xmm15);
                    break;

                case CallingConvention.X64U:
                    argumentsGPList[0] = RegIndex.Rdi;
                    argumentsGPList[1] = RegIndex.Rsi;
                    argumentsGPList[2] = RegIndex.Rdx;
                    argumentsGPList[3] = RegIndex.Rcx;
                    argumentsGPList[4] = RegIndex.R8;
                    argumentsGPList[5] = RegIndex.R9;

                    argumentsXMMList[0] = RegIndex.Xmm0;
                    argumentsXMMList[1] = RegIndex.Xmm1;
                    argumentsXMMList[2] = RegIndex.Xmm2;
                    argumentsXMMList[3] = RegIndex.Xmm3;
                    argumentsXMMList[4] = RegIndex.Xmm4;
                    argumentsXMMList[5] = RegIndex.Xmm5;
                    argumentsXMMList[6] = RegIndex.Xmm6;
                    argumentsXMMList[7] = RegIndex.Xmm7;

                    _argumentsGP = RegisterMask.FromIndex(RegIndex.Rdi) |
                                   RegisterMask.FromIndex(RegIndex.Rsi) |
                                   RegisterMask.FromIndex(RegIndex.Rdx) |
                                   RegisterMask.FromIndex(RegIndex.Rcx) |
                                   RegisterMask.FromIndex(RegIndex.R8) |
                                   RegisterMask.FromIndex(RegIndex.R9);

                    _argumentsXMM = RegisterMask.FromIndex(RegIndex.Xmm0) |
                                    RegisterMask.FromIndex(RegIndex.Xmm1) |
                                    RegisterMask.FromIndex(RegIndex.Xmm2) |
                                    RegisterMask.FromIndex(RegIndex.Xmm3) |
                                    RegisterMask.FromIndex(RegIndex.Xmm4) |
                                    RegisterMask.FromIndex(RegIndex.Xmm5) |
                                    RegisterMask.FromIndex(RegIndex.Xmm6) |
                                    RegisterMask.FromIndex(RegIndex.Xmm7);

                    _preservedGP =
                        RegisterMask.FromIndex(RegIndex.Rbx) |
                        RegisterMask.FromIndex(RegIndex.Rsp) |
                        RegisterMask.FromIndex(RegIndex.Rbp) |
                        RegisterMask.FromIndex(RegIndex.R12) |
                        RegisterMask.FromIndex(RegIndex.R13) |
                        RegisterMask.FromIndex(RegIndex.R14) |
                        RegisterMask.FromIndex(RegIndex.R15);
                    break;

                default:
                    throw new NotSupportedException(string.Format("The calling convention '{0}' is not supported on this platform.", callingConvention));
                }
            }
            else
            {
                throw new NotImplementedException();
            }

            _argumentsGPList = new ReadOnlyCollection<RegIndex>(argumentsGPList);
            _argumentsXMMList = new ReadOnlyCollection<RegIndex>(argumentsXMMList);
        }
Пример #14
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++;
        }
Пример #15
0
 private static bool Exchange(RegisterMask[] masks, int blkIndex, RegisterMask value)
 {
     ref RegisterMask curValue = ref masks[blkIndex];
Пример #16
0
        public static void RunPass(ControlFlowGraph cfg, ExecutionMode mode)
        {
            // Compute local register inputs and outputs used inside blocks.
            RegisterMask[] localInputs  = new RegisterMask[cfg.Blocks.Count];
            RegisterMask[] localOutputs = new RegisterMask[cfg.Blocks.Count];

            for (BasicBlock block = cfg.Blocks.First; block != null; block = block.ListNext)
            {
                for (Operation node = block.Operations.First; node != default; node = node.ListNext)
                {
                    for (int index = 0; index < node.SourcesCount; index++)
                    {
                        Operand source = node.GetSource(index);

                        if (source.Kind == OperandKind.Register)
                        {
                            Register register = source.GetRegister();

                            localInputs[block.Index] |= GetMask(register) & ~localOutputs[block.Index];
                        }
                    }

                    if (node.Destination != default && node.Destination.Kind == OperandKind.Register)
                    {
                        localOutputs[block.Index] |= GetMask(node.Destination.GetRegister());
                    }
                }
            }

            // Compute global register inputs and outputs used across blocks.
            RegisterMask[] globalCmnOutputs = new RegisterMask[cfg.Blocks.Count];

            RegisterMask[] globalInputs  = new RegisterMask[cfg.Blocks.Count];
            RegisterMask[] globalOutputs = new RegisterMask[cfg.Blocks.Count];

            bool modified;
            bool firstPass = true;

            do
            {
                modified = false;

                // Compute register outputs.
                for (int index = cfg.PostOrderBlocks.Length - 1; index >= 0; index--)
                {
                    BasicBlock block = cfg.PostOrderBlocks[index];

                    if (block.Predecessors.Count != 0 && !HasContextLoad(block))
                    {
                        BasicBlock predecessor = block.Predecessors[0];

                        RegisterMask cmnOutputs = localOutputs[predecessor.Index] | globalCmnOutputs[predecessor.Index];
                        RegisterMask outputs    = globalOutputs[predecessor.Index];

                        for (int pIndex = 1; pIndex < block.Predecessors.Count; pIndex++)
                        {
                            predecessor = block.Predecessors[pIndex];

                            cmnOutputs &= localOutputs[predecessor.Index] | globalCmnOutputs[predecessor.Index];
                            outputs    |= globalOutputs[predecessor.Index];
                        }

                        globalInputs[block.Index] |= outputs & ~cmnOutputs;

                        if (!firstPass)
                        {
                            cmnOutputs &= globalCmnOutputs[block.Index];
                        }

                        modified |= Exchange(globalCmnOutputs, block.Index, cmnOutputs);
                        outputs  |= localOutputs[block.Index];
                        modified |= Exchange(globalOutputs, block.Index, globalOutputs[block.Index] | outputs);
                    }
                    else
                    {
                        modified |= Exchange(globalOutputs, block.Index, localOutputs[block.Index]);
                    }
                }

                // Compute register inputs.
                for (int index = 0; index < cfg.PostOrderBlocks.Length; index++)
                {
                    BasicBlock block = cfg.PostOrderBlocks[index];

                    RegisterMask inputs = localInputs[block.Index];

                    for (int i = 0; i < block.SuccessorsCount; i++)
                    {
                        inputs |= globalInputs[block.GetSuccessor(i).Index];
                    }

                    inputs &= ~globalCmnOutputs[block.Index];

                    modified |= Exchange(globalInputs, block.Index, globalInputs[block.Index] | inputs);
                }

                firstPass = false;
            }while (modified);

            // Insert load and store context instructions where needed.
            for (BasicBlock block = cfg.Blocks.First; block != null; block = block.ListNext)
            {
                bool hasContextLoad = HasContextLoad(block);

                if (hasContextLoad)
                {
                    block.Operations.Remove(block.Operations.First);
                }

                Operand arg = default;

                // The only block without any predecessor should be the entry block.
                // It always needs a context load as it is the first block to run.
                if (block.Predecessors.Count == 0 || hasContextLoad)
                {
                    arg = Local(OperandType.I64);

                    Operation loadArg = block.Operations.AddFirst(Operation(Instruction.LoadArgument, arg, Const(0)));

                    LoadLocals(block, globalInputs[block.Index].VecMask, RegisterType.Vector, mode, loadArg, arg);
                    LoadLocals(block, globalInputs[block.Index].IntMask, RegisterType.Integer, mode, loadArg, arg);
                }

                bool hasContextStore = HasContextStore(block);

                if (hasContextStore)
                {
                    block.Operations.Remove(block.Operations.Last);
                }

                if (EndsWithReturn(block) || hasContextStore)
                {
                    if (arg == default)
                    {
                        arg = Local(OperandType.I64);

                        block.Append(Operation(Instruction.LoadArgument, arg, Const(0)));
                    }

                    StoreLocals(block, globalOutputs[block.Index].IntMask, RegisterType.Integer, mode, arg);
                    StoreLocals(block, globalOutputs[block.Index].VecMask, RegisterType.Vector, mode, arg);
                }
            }
        }
Пример #17
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);
        }
Пример #18
0
        public static void RunPass(ControlFlowGraph cfg, bool isCompleteFunction)
        {
            // Compute local register inputs and outputs used inside blocks.
            RegisterMask[] localInputs  = new RegisterMask[cfg.Blocks.Count];
            RegisterMask[] localOutputs = new RegisterMask[cfg.Blocks.Count];

            for (BasicBlock block = cfg.Blocks.First; block != null; block = block.ListNext)
            {
                for (Node node = block.Operations.First; node != null; node = node.ListNext)
                {
                    Operation operation = node as Operation;

                    for (int srcIndex = 0; srcIndex < operation.SourcesCount; srcIndex++)
                    {
                        Operand source = operation.GetSource(srcIndex);

                        if (source.Kind != OperandKind.Register)
                        {
                            continue;
                        }

                        Register register = source.GetRegister();

                        localInputs[block.Index] |= GetMask(register) & ~localOutputs[block.Index];
                    }

                    if (operation.Destination != null && operation.Destination.Kind == OperandKind.Register)
                    {
                        localOutputs[block.Index] |= GetMask(operation.Destination.GetRegister());
                    }
                }
            }

            // Compute global register inputs and outputs used across blocks.
            RegisterMask[] globalCmnOutputs = new RegisterMask[cfg.Blocks.Count];

            RegisterMask[] globalInputs  = new RegisterMask[cfg.Blocks.Count];
            RegisterMask[] globalOutputs = new RegisterMask[cfg.Blocks.Count];

            bool modified;

            bool firstPass = true;

            do
            {
                modified = false;

                // Compute register outputs.
                for (int index = cfg.PostOrderBlocks.Length - 1; index >= 0; index--)
                {
                    BasicBlock block = cfg.PostOrderBlocks[index];

                    if (block.Predecessors.Count != 0 && !HasContextLoad(block))
                    {
                        BasicBlock predecessor = block.Predecessors[0];

                        RegisterMask cmnOutputs = localOutputs[predecessor.Index] | globalCmnOutputs[predecessor.Index];

                        RegisterMask outputs = globalOutputs[predecessor.Index];

                        for (int pIndex = 1; pIndex < block.Predecessors.Count; pIndex++)
                        {
                            predecessor = block.Predecessors[pIndex];

                            cmnOutputs &= localOutputs[predecessor.Index] | globalCmnOutputs[predecessor.Index];

                            outputs |= globalOutputs[predecessor.Index];
                        }

                        globalInputs[block.Index] |= outputs & ~cmnOutputs;

                        if (!firstPass)
                        {
                            cmnOutputs &= globalCmnOutputs[block.Index];
                        }

                        if (Exchange(globalCmnOutputs, block.Index, cmnOutputs))
                        {
                            modified = true;
                        }

                        outputs |= localOutputs[block.Index];

                        if (Exchange(globalOutputs, block.Index, globalOutputs[block.Index] | outputs))
                        {
                            modified = true;
                        }
                    }
                    else if (Exchange(globalOutputs, block.Index, localOutputs[block.Index]))
                    {
                        modified = true;
                    }
                }

                // Compute register inputs.
                for (int index = 0; index < cfg.PostOrderBlocks.Length; index++)
                {
                    BasicBlock block = cfg.PostOrderBlocks[index];

                    RegisterMask inputs = localInputs[block.Index];

                    if (block.Next != null)
                    {
                        inputs |= globalInputs[block.Next.Index];
                    }

                    if (block.Branch != null)
                    {
                        inputs |= globalInputs[block.Branch.Index];
                    }

                    inputs &= ~globalCmnOutputs[block.Index];

                    if (Exchange(globalInputs, block.Index, globalInputs[block.Index] | inputs))
                    {
                        modified = true;
                    }
                }

                firstPass = false;
            }while (modified);

            // Insert load and store context instructions where needed.
            for (BasicBlock block = cfg.Blocks.First; block != null; block = block.ListNext)
            {
                bool hasContextLoad = HasContextLoad(block);

                if (hasContextLoad)
                {
                    block.Operations.Remove(block.Operations.First);
                }

                // The only block without any predecessor should be the entry block.
                // It always needs a context load as it is the first block to run.
                if (block.Predecessors.Count == 0 || hasContextLoad)
                {
                    LoadLocals(block, globalInputs[block.Index].VecMask, RegisterType.Vector);
                    LoadLocals(block, globalInputs[block.Index].IntMask, RegisterType.Integer);
                }

                bool hasContextStore = HasContextStore(block);

                if (hasContextStore)
                {
                    block.Operations.Remove(block.Operations.Last);
                }

                if (EndsWithReturn(block) || hasContextStore)
                {
                    StoreLocals(block, globalOutputs[block.Index].IntMask, RegisterType.Integer, isCompleteFunction);
                    StoreLocals(block, globalOutputs[block.Index].VecMask, RegisterType.Vector, isCompleteFunction);
                }
            }
        }
Пример #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);
        }