コード例 #1
0
        public CompilerFunctionReturn(Compiler compiler, CompilerFunction function, Operand first, Operand second)
            : base(compiler)
        {
            Contract.Requires(compiler != null);
            Contract.Requires(function != null);

            _function = function;
            _first = first;
            _second = second;
        }
コード例 #2
0
        public CompilerFunctionCall(Compiler compiler, CompilerFunction caller, Operand target, CallingConvention callingConvention, VariableType[] arguments, VariableType returnValue)
            : base(compiler)
        {
            Contract.Requires(arguments != null);

            _caller = caller;
            _target = target;

            _functionPrototype = new FunctionDeclaration(callingConvention, arguments, returnValue);
            if (arguments != null && arguments.Length > 0)
                _args = new Operand[arguments.Length];
        }
コード例 #3
0
        public CompilerFunctionCall(Compiler compiler, CompilerFunction caller, Operand target, CallingConvention callingConvention, Type delegateType)
            : base(compiler)
        {
            Contract.Requires(compiler != null);
            Contract.Requires(caller != null);

            _caller = caller;
            _target = target;

            _functionPrototype = new FunctionDeclaration(callingConvention, delegateType);
            if (_functionPrototype.Arguments != null && _functionPrototype.Arguments.Length > 0)
                _args = new Operand[_functionPrototype.Arguments.Length];
        }
コード例 #4
0
        public CompilerJmpInstruction(Compiler compiler, InstructionCode code, Operand[] operands)
            : base(compiler, code, operands)
        {
            if (code < InstructionDescription.JumpBegin || code > InstructionDescription.JumpEnd)
                throw new ArgumentException("The specified instruction code is not a valid jump.");
            Contract.Requires(compiler != null);
            Contract.Requires(operands != null);
            Contract.EndContractBlock();

            _jumpTarget = compiler.GetTarget(Operands[0].Id);
            _jumpTarget.JumpsCount++;

            _jumpNext = _jumpTarget.From;
            _jumpTarget.From = this;

            _isTaken =
                Code == InstructionCode.Jmp
                || (Operands.Length > 1 && Operands[1].IsImm && ((Imm)Operands[1]).Value == (IntPtr)Hint.Taken);
        }
コード例 #5
0
        public CompilerInstruction(Compiler compiler, InstructionCode code, Operand[] operands)
            : base(compiler)
        {
            Contract.Requires(compiler != null);
            Contract.Requires(operands != null);

            _code = code;
            _emitOptions = compiler.EmitOptions;
            // Each created instruction takes emit options and clears it.
            compiler.EmitOptions = EmitOptions.None;

            _operands = operands;
            _memoryOperand = null;

            _variables = null;

            for (int i = 0; i < operands.Length; i++)
            {
                if (operands[i].IsMem)
                {
                    _memoryOperand = (Mem)operands[i];
                    break;
                }
            }

            InstructionDescription id = InstructionDescription.FromInstruction(_code);
            _isSpecial = id.IsSpecial;
            _isFPU = id.IsFPU;
            _isGPBHiUsed = false;
            _isGPBLoUsed = false;

            if (_isSpecial)
            {
                // ${SPECIAL_INSTRUCTION_HANDLING_BEGIN}
                switch (_code)
                {
                case InstructionCode.Cpuid:
                    // Special...
                    break;

                case InstructionCode.Cbw:
                case InstructionCode.Cdqe:
                case InstructionCode.Cwde:
                    // Special...
                    break;

                case InstructionCode.Cdq:
                case InstructionCode.Cqo:
                case InstructionCode.Cwd:
                    // Special...
                    break;

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

                    break;

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

                    break;

                case InstructionCode.Imul:
                    switch (operands.Length)
                    {
                    case 2:
                        // IMUL dst, src is not special instruction.
                        _isSpecial = false;
                        break;
                    case 3:
                        if (!(_operands[0].IsVar && _operands[1].IsVar && _operands[2].IsVarMem))
                        {
                            // Only IMUL dst_hi, dst_lo, reg/mem is special, all others don't.
                            _isSpecial = false;
                        }
                        break;
                    }
                    break;
                case InstructionCode.Mul:
                case InstructionCode.Idiv:
                case InstructionCode.Div:
                    // Special...
                    break;

                case InstructionCode.MovPtr:
                    // Special...
                    break;

                case InstructionCode.Lahf:
                case InstructionCode.Sahf:
                    // Special...
                    break;

                case InstructionCode.Maskmovdqu:
                case InstructionCode.Maskmovq:
                    // Special...
                    break;

                case InstructionCode.Enter:
                case InstructionCode.Leave:
                    // Special...
                    break;

                case InstructionCode.Ret:
                    // Special...
                    break;

                case InstructionCode.Monitor:
                case InstructionCode.Mwait:
                    // Special...
                    break;

                case InstructionCode.Pop:
                case InstructionCode.Popad:
                case InstructionCode.Popfd:
                case InstructionCode.Popfq:
                    // Special...
                    break;

                case InstructionCode.Push:
                case InstructionCode.Pushad:
                case InstructionCode.Pushfd:
                case InstructionCode.Pushfq:
                    // Special...
                    break;

                case InstructionCode.Rcl:
                case InstructionCode.Rcr:
                case InstructionCode.Rol:
                case InstructionCode.Ror:
                case InstructionCode.Sal:
                case InstructionCode.Sar:
                case InstructionCode.Shl:
                case InstructionCode.Shr:
                    // Rot instruction is special only if last operand is variable (register).
                    _isSpecial = _operands[1].IsVar;
                    break;

                case InstructionCode.Shld:
                case InstructionCode.Shrd:
                    // Shld/Shrd instruction is special only if last operand is variable (register).
                    _isSpecial = _operands[2].IsVar;
                    break;

                case InstructionCode.Rdtsc:
                case InstructionCode.Rdtscp:
                    // Special...
                    break;

                case InstructionCode.RepLodsb:
                case InstructionCode.RepLodsd:
                case InstructionCode.RepLodsq:
                case InstructionCode.RepLodsw:
                case InstructionCode.RepMovsb:
                case InstructionCode.RepMovsd:
                case InstructionCode.RepMovsq:
                case InstructionCode.RepMovsw:
                case InstructionCode.RepStosb:
                case InstructionCode.RepStosd:
                case InstructionCode.RepStosq:
                case InstructionCode.RepStosw:
                case InstructionCode.RepeCmpsb:
                case InstructionCode.RepeCmpsd:
                case InstructionCode.RepeCmpsq:
                case InstructionCode.RepeCmpsw:
                case InstructionCode.RepeScasb:
                case InstructionCode.RepeScasd:
                case InstructionCode.RepeScasq:
                case InstructionCode.RepeScasw:
                case InstructionCode.RepneCmpsb:
                case InstructionCode.RepneCmpsd:
                case InstructionCode.RepneCmpsq:
                case InstructionCode.RepneCmpsw:
                case InstructionCode.RepneScasb:
                case InstructionCode.RepneScasd:
                case InstructionCode.RepneScasq:
                case InstructionCode.RepneScasw:
                    // Special...
                    break;

                default:
                    throw new CompilerException("Instruction is marked as special but handling for it is not present.");
                }
                // ${SPECIAL_INSTRUCTION_HANDLING_END}
            }
        }
コード例 #6
0
        public void TranslateOperands(Operand[] operands)
        {
            Contract.Requires(operands != null);

            int i;
            int count = operands.Length;

            // Translate variables to registers.
            for (i = 0; i < count; i++)
            {
                Operand o = operands[i];

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

                    operands[i] = new GPReg(((BaseVar)o).RegisterType, vdata.RegisterIndex);
                }
                else if (o.IsMem)
                {
                    Mem mem = (Mem)o;

                    if ((o.Id & Operand.OperandIdTypeMask) == Operand.OperandIdTypeVar)
                    {
                        // Memory access. We just increment here actual displacement.
                        CompilerVar vdata = _compiler.GetVarData(o.Id);
                        Contract.Assert(vdata != null);

                        mem.Displacement += vdata.IsMemArgument
                          ? _argumentsActualDisp
                          : _variablesActualDisp;
                        // NOTE: This is not enough, variable position will be patched later
                        // by CompilerContext::_patchMemoryOperands().
                    }
                    else if (((int)mem.Base & Operand.OperandIdTypeMask) == Operand.OperandIdTypeVar)
                    {
                        CompilerVar vdata = _compiler.GetVarData((int)mem.Base);
                        Contract.Assert(vdata != null);

                        mem.Base = vdata.RegisterIndex;
                    }

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

                        mem.Index = vdata.RegisterIndex;
                    }
                }
            }
        }
コード例 #7
0
        protected override CompilerItem TranslateImpl(CompilerContext cc)
        {
            RegisterMask preserved;

            RegIndex temporaryGpReg;
            RegIndex temporaryXmmReg;

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

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

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

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

            compiler.Comment("Call");

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

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

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

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

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

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

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

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

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

                Operand operand = _args[i];

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

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

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

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

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

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

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

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

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

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

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

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

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

                Operand operand = _args[i];

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

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

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

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

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

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

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

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

                    default:
                        throw new NotImplementedException();
                    }

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

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

            bool didWork;

            do
            {
                didWork = false;

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

                    VarCallRecord rsrc = _argumentToVarRecord[i];

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

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

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

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

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

                            bool doSpill = true;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

                                            doSpill = false;
                                        }
                                    }
                                }
                            }

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

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

                        MoveSrcVariableToRegister(cc, vsrc, srcArgType);

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

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

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

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

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

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

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

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

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

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

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

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

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

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

            compiler.Emit(InstructionCode.Call, _target);

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

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

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

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

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

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

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

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

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

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

                // Cleanup.
                vdata.Temp = null;
            }

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

            return Next;
        }
コード例 #8
0
        public bool SetReturn(Operand first, Operand second)
        {
            first = first ?? Operand.None;
            second = second ?? Operand.None;

            if (!(first.IsNone || first.IsVarMem) || !(second.IsNone || second.IsVarMem))
                throw new ArgumentException("The return value storage location must be a variable or memory location.");

            _ret[0] = first;
            _ret[1] = second;
            return true;
        }
コード例 #9
0
 public bool SetReturn(Operand first)
 {
     return SetReturn(first, Operand.None);
 }
コード例 #10
0
        public void SetArgument(int i, Operand operand)
        {
            if (i < 0)
                throw new ArgumentOutOfRangeException("i");
            if (i >= _functionPrototype.Arguments.Length)
                throw new ArgumentException();

            _args[i] = operand;
        }