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; }