예제 #1
0
        protected override CompilerItem TranslateImpl(CompilerContext cc)
        {
            Compiler compiler = cc.Compiler;
            Operand[] ret = { _first, _second };

            // Check whether the return value is compatible.
            VariableType retValType = Function.Declaration.ReturnValue;
            int i;

            switch (retValType)
            {
            case VariableType.GPD:
            case VariableType.GPQ:
                for (i = 0; i < 2; i++)
                {
                    if (ret[i] == null)
                        continue;

                    RegIndex dsti = (i == 0) ? RegIndex.Eax : RegIndex.Edx;
                    RegIndex srci;

                    if (ret[i].IsVar)
                    {
                        if (((BaseVar)ret[i]).IsGPVar)
                        {
                            CompilerVar vdata = compiler.GetVarData(ret[i].Id);
                            Contract.Assert(vdata != null);

                            srci = vdata.RegisterIndex;
                            if (srci == RegIndex.Invalid)
                                compiler.Emit(InstructionCode.Mov, Register.gpn(dsti), cc.GetVarMem(vdata));
                            else if (dsti != srci)
                                compiler.Emit(InstructionCode.Mov, Register.gpn(dsti), Register.gpn(srci));
                        }
                    }
                    else if (ret[i].IsImm)
                    {
                        compiler.Emit(InstructionCode.Mov, Register.gpn(dsti), ret[i]);
                    }
                }
                break;

            case VariableType.X87:
            case VariableType.X87_1F:
            case VariableType.X87_1D:
                // There is case that we need to return two values (Unix-ABI specific):
                // - FLD #2
                //-  FLD #1
                i = 2;
                do
                {
                    i--;
                    int dsti = i;
                    RegIndex srci;

                    if (ret[i] == null)
                        continue;

                    if (ret[i].IsVar)
                    {
                        if (((BaseVar)ret[i]).IsX87Var)
                        {
                            // TODO: X87.
                            throw new NotImplementedException("X87 support is not yet implemented.");
                        }
                        else if (((BaseVar)ret[i]).IsXMMVar)
                        {
                            CompilerVar vdata = compiler.GetVarData(ret[i].Id);
                            Contract.Assert(vdata != null);

                            srci = vdata.RegisterIndex;
                            if (srci != RegIndex.Invalid)
                                cc.SaveVar(vdata);

                            switch (vdata.Type)
                            {
                            case VariableType.XMM_1F:
                            case VariableType.XMM_4F:
                                compiler.Emit(InstructionCode.Fld, BaseVarMem(((BaseVar)ret[i]), 4));
                                break;
                            case VariableType.XMM_1D:
                            case VariableType.XMM_2D:
                                compiler.Emit(InstructionCode.Fld, BaseVarMem(((BaseVar)ret[i]), 8));
                                break;
                            }
                        }
                    }
                } while (i != 0);
                break;

            case VariableType.MM:
                for (i = 0; i < 2; i++)
                {
                    RegIndex dsti = (RegIndex)i;
                    RegIndex srci;

                    if (ret[i] == null)
                        continue;

                    if (ret[i].IsVar)
                    {
                        if (((BaseVar)ret[i]).IsGPVar)
                        {
                            CompilerVar vdata = compiler.GetVarData(ret[i].Id);
                            Contract.Assert(vdata != null);

                            srci = vdata.RegisterIndex;
                            InstructionCode inst = ret[i].IsRegType(RegType.GPQ) ? InstructionCode.Movq : InstructionCode.Movd;

                            if (srci == RegIndex.Invalid)
                            {
                                compiler.Emit(inst, Register.mm(dsti), cc.GetVarMem(vdata));
                            }
                            else
                            {
                                if (Util.IsX86)
                                    compiler.Emit(inst, Register.mm(dsti), Register.gpd(srci));
                                else if (Util.IsX64)
                                    compiler.Emit(inst, Register.mm(dsti), ret[i].IsRegType(RegType.GPQ) ? Register.gpq(srci) : Register.gpd(srci));
                                else
                                    throw new NotImplementedException();
                            }
                        }
                        else if (((BaseVar)ret[i]).IsMMVar)
                        {
                            CompilerVar vdata = compiler.GetVarData(ret[i].Id);
                            Contract.Assert(vdata != null);

                            srci = vdata.RegisterIndex;
                            InstructionCode inst = InstructionCode.Movq;

                            if (srci == RegIndex.Invalid)
                                compiler.Emit(inst, Register.mm(dsti), cc.GetVarMem(vdata));
                            else if (dsti != srci)
                                compiler.Emit(inst, Register.mm(dsti), Register.mm(srci));
                        }
                        else if (((BaseVar)ret[i]).IsXMMVar)
                        {
                            CompilerVar vdata = compiler.GetVarData(ret[i].Id);
                            Contract.Assert(vdata != null);

                            srci = vdata.RegisterIndex;
                            InstructionCode inst = InstructionCode.Movq;
                            if (((BaseVar)ret[i]).VariableType == VariableType.XMM_1F)
                                inst = InstructionCode.Movd;

                            if (srci == RegIndex.Invalid)
                                compiler.Emit(inst, Register.mm(dsti), cc.GetVarMem(vdata));
                            else
                                compiler.Emit(inst, Register.mm(dsti), Register.xmm(srci));
                        }
                    }
                }
                break;

            case VariableType.XMM:
            case VariableType.XMM_4F:
            case VariableType.XMM_2D:
                for (i = 0; i < 2; i++)
                {
                    RegIndex dsti = (RegIndex)i;
                    RegIndex srci;

                    if (ret[i] == null)
                        continue;

                    if (ret[i].IsVar)
                    {
                        if (((BaseVar)ret[i]).IsGPVar)
                        {
                            CompilerVar vdata = compiler.GetVarData(ret[i].Id);
                            Contract.Assert(vdata != null);

                            srci = vdata.RegisterIndex;
                            InstructionCode inst = ret[i].IsRegType(RegType.GPQ) ? InstructionCode.Movq : InstructionCode.Movd;

                            if (srci == RegIndex.Invalid)
                            {
                                compiler.Emit(inst, Register.xmm(dsti), cc.GetVarMem(vdata));
                            }
                            else
                            {
                                if (Util.IsX86)
                                    compiler.Emit(inst, Register.xmm(dsti), Register.gpd(srci));
                                else if (Util.IsX64)
                                    compiler.Emit(inst, Register.xmm(dsti), ret[i].IsRegType(RegType.GPQ) ? Register.gpq(srci) : Register.gpd(srci));
                                else
                                    throw new NotImplementedException();
                            }
                        }
                        else if (((BaseVar)ret[i]).IsX87Var)
                        {
                            // TODO: X87.
                            throw new NotImplementedException("X87 support is not yet implemented.");
                        }
                        else if (((BaseVar)ret[i]).IsMMVar)
                        {
                            CompilerVar vdata = compiler.GetVarData(ret[i].Id);
                            Contract.Assert(vdata != null);

                            srci = vdata.RegisterIndex;
                            if (srci == RegIndex.Invalid)
                                compiler.Emit(InstructionCode.Movq, Register.xmm(dsti), cc.GetVarMem(vdata));
                            else
                                compiler.Emit(InstructionCode.Movq, Register.xmm(dsti), Register.mm(srci));
                        }
                        else if (((BaseVar)ret[i]).IsXMMVar)
                        {
                            CompilerVar vdata = compiler.GetVarData(ret[i].Id);
                            Contract.Assert(vdata != null);

                            srci = vdata.RegisterIndex;
                            if (srci == RegIndex.Invalid)
                                compiler.Emit(InstructionCode.Movdqa, Register.xmm(dsti), cc.GetVarMem(vdata));
                            else if (dsti != srci)
                                compiler.Emit(InstructionCode.Movdqa, Register.xmm(dsti), Register.xmm(srci));
                        }
                    }
                }
                break;

            case VariableType.XMM_1F:
                for (i = 0; i < 2; i++)
                {
                    RegIndex dsti = (RegIndex)i;
                    RegIndex srci;

                    if (ret[i] == null)
                        continue;

                    if (ret[i].IsVar)
                    {
                        if (((BaseVar)ret[i]).IsX87Var)
                        {
                            // TODO: X87.
                        }
                        else if (((BaseVar)ret[i]).IsXMMVar)
                        {
                            CompilerVar vdata = compiler.GetVarData(ret[i].Id);
                            Contract.Assert(vdata != null);

                            srci = vdata.RegisterIndex;
                            switch (vdata.Type)
                            {
                            case VariableType.XMM:
                                if (srci == RegIndex.Invalid)
                                    compiler.Emit(InstructionCode.Movdqa, Register.xmm(dsti), cc.GetVarMem(vdata));
                                else if (dsti != srci)
                                    compiler.Emit(InstructionCode.Movdqa, Register.xmm(dsti), Register.xmm(srci));
                                break;
                            case VariableType.XMM_1F:
                            case VariableType.XMM_4F:
                                if (srci == RegIndex.Invalid)
                                    compiler.Emit(InstructionCode.Movss, Register.xmm(dsti), cc.GetVarMem(vdata));
                                else
                                    compiler.Emit(InstructionCode.Movss, Register.xmm(dsti), Register.xmm(srci));
                                break;
                            case VariableType.XMM_1D:
                            case VariableType.XMM_2D:
                                if (srci == RegIndex.Invalid)
                                    compiler.Emit(InstructionCode.Cvtsd2ss, Register.xmm(dsti), cc.GetVarMem(vdata));
                                else if (dsti != srci)
                                    compiler.Emit(InstructionCode.Cvtsd2ss, Register.xmm(dsti), Register.xmm(srci));
                                break;
                            }
                        }
                    }
                }
                break;

            case VariableType.XMM_1D:
                for (i = 0; i < 2; i++)
                {
                    RegIndex dsti = (RegIndex)i;
                    RegIndex srci;

                    if (ret[i] == null)
                        continue;

                    if (ret[i].IsVar)
                    {
                        if (((BaseVar)ret[i]).IsX87Var)
                        {
                            // TODO: X87.
                        }
                        else if (((BaseVar)ret[i]).IsXMMVar)
                        {
                            CompilerVar vdata = compiler.GetVarData(ret[i].Id);
                            Contract.Assert(vdata != null);

                            srci = vdata.RegisterIndex;
                            switch (vdata.Type)
                            {
                            case VariableType.XMM:
                                if (srci == RegIndex.Invalid)
                                    compiler.Emit(InstructionCode.Movdqa, Register.xmm(dsti), cc.GetVarMem(vdata));
                                else if (dsti != srci)
                                    compiler.Emit(InstructionCode.Movdqa, Register.xmm(dsti), Register.xmm(srci));
                                break;
                            case VariableType.XMM_1F:
                            case VariableType.XMM_4F:
                                if (srci == RegIndex.Invalid)
                                    compiler.Emit(InstructionCode.Cvtss2sd, Register.xmm(dsti), cc.GetVarMem(vdata));
                                else
                                    compiler.Emit(InstructionCode.Cvtss2sd, Register.xmm(dsti), Register.xmm(srci));
                                break;
                            case VariableType.XMM_1D:
                            case VariableType.XMM_2D:
                                if (srci == RegIndex.Invalid)
                                    compiler.Emit(InstructionCode.Movsd, Register.xmm(dsti), cc.GetVarMem(vdata));
                                else
                                    compiler.Emit(InstructionCode.Movsd, Register.xmm(dsti), Register.xmm(srci));
                                break;
                            }
                        }
                    }
                }
                break;

            case VariableType.Invalid:
            default:
                break;
            }

            if (ShouldEmitJumpToEpilog())
            {
                cc.Unreachable = true;
            }

            for (i = 0; i < 2; i++)
            {
                if (ret[i] != null && ret[i].IsVar)
                {
                    CompilerVar vdata = compiler.GetVarData(ret[i].Id);
                    Contract.Assert(vdata != null);
                    cc.UnuseVarOnEndOfScope(this, vdata);
                }
            }

            return Next;
        }