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];
        }
        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];
        }
Esempio n. 3
0
        private CompilerFunction(Compiler compiler, FunctionDeclaration prototype)
            : base(compiler)
        {
            Contract.Requires(compiler != null);
            Contract.Requires(prototype != null);

            _functionPrototype = prototype;

            _entryLabel = compiler.DefineLabel();
            _exitLabel = compiler.DefineLabel();
            _entryTarget = compiler.GetTarget(_entryLabel.Id);
            _exitTarget = compiler.GetTarget(_exitLabel.Id);

            _end = new CompilerFunctionEnd(compiler, this);
        }
Esempio n. 4
0
        public static FunctionDeclaration GetFunctionPrototype(CallingConvention callingConvention, VariableType[] arguments, VariableType returnValue)
        {
            if (arguments == null)
                throw new ArgumentNullException("arguments");
            Contract.Ensures(Contract.Result<FunctionDeclaration>() != null);
            Contract.EndContractBlock();

            bool isAction = returnValue == VariableType.Invalid;
            Type delegateType;

            if (isAction)
            {
                delegateType = Expression.GetActionType(Array.ConvertAll(arguments, i => Compiler.IdToType(i)));
            }
            else
            {
                List<Type> typeArgs = arguments.Select(i => Compiler.IdToType(i)).ToList();
                typeArgs.Add(Compiler.IdToType(returnValue));
                delegateType = Expression.GetFuncType(typeArgs.ToArray());
            }

            List<FunctionDeclaration> prototypes = _prototypes.GetOrAdd(delegateType, key => new List<FunctionDeclaration>());
            lock (prototypes)
            {
                FunctionDeclaration prototype = prototypes.FirstOrDefault(i => i.CallingConvention == callingConvention);
                if (prototype == null)
                {
                    prototype = new FunctionDeclaration(callingConvention, arguments, returnValue);
                    prototypes.Add(prototype);
                }

                return prototype;
            }
        }
Esempio n. 5
0
        public static FunctionDeclaration GetFunctionPrototype(CallingConvention callingConvention, Type delegateType)
        {
            if (delegateType == null)
                throw new ArgumentNullException("delegateType");
            Contract.Ensures(Contract.Result<FunctionDeclaration>() != null);
            Contract.EndContractBlock();

            List<FunctionDeclaration> prototypes = _prototypes.GetOrAdd(delegateType, key => new List<FunctionDeclaration>());
            lock (prototypes)
            {
                FunctionDeclaration prototype = prototypes.FirstOrDefault(i => i.CallingConvention == callingConvention);
                if (prototype == null)
                {
                    prototype = new FunctionDeclaration(callingConvention, delegateType);
                    prototypes.Add(prototype);
                }

                return prototype;
            }
        }
        private void MoveSrcVariableToRegister(CompilerContext cc, CompilerVar vdata, FunctionDeclaration.Argument argType)
        {
            Contract.Requires(cc != null);
            Contract.Requires(vdata != null);
            Contract.Requires(argType != null);

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

            Compiler compiler = cc.Compiler;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

            throw new ArgumentException("Incompatible argument.");
        }
        private void MoveSpilledVariableToStack(CompilerContext cc, CompilerVar vdata, FunctionDeclaration.Argument argType, RegIndex temporaryGpReg, RegIndex temporaryXmmReg)
        {
            Contract.Requires(cc != null);
            Contract.Requires(vdata != null);
            Contract.Requires(argType != null);

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

            Compiler compiler = cc.Compiler;

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

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

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

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

                default:
                    throw new CompilerException();
                }

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

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

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

                default:
                    throw new CompilerException();
                }

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

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

                default:
                    throw new CompilerException();
                }

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

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

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

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

                default:
                    throw new CompilerException();
                }

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

                default:
                    throw new CompilerException();
                }

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

                default:
                    throw new CompilerException();
                }

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

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

            Compiler compiler = cc.Compiler;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

            default:
                throw new CompilerException();
            }
        }