Cosmos/source/Cosmos.IL2CPU/IL/Conv_R4.cs
fanoI 58c556f085 - Initial work as for https://github.com/CosmosOS/Cosmos/issues/359
- Added Console.Clear() to Guess Demo (the boot text remained on screen)
- Added to BCL test BitConverterTest (all failing), test for single / double arithmetic operations
- Added to TestRunner BCLTest
2016-05-21 18:55:39 +02:00

135 lines
No EOL
8.4 KiB
C#

using System;
using CPUx86 = Cosmos.Assembler.x86;
namespace Cosmos.IL2CPU.X86.IL
{
/// <summary>
/// Converts the value on top of the evaluation stack to float32.
/// </summary>
[Cosmos.IL2CPU.OpCode(ILOpCode.Code.Conv_R4)]
public class Conv_R4 : ILOp
{
public Conv_R4(Cosmos.Assembler.Assembler aAsmblr)
: base(aAsmblr)
{
}
public override void Execute(MethodInfo aMethod, ILOpCode aOpCode)
{
var xSource = aOpCode.StackPopTypes[0];
var xSourceIsFloat = TypeIsFloat(xSource);
var xSourceSize = SizeOfType(xSource);
switch (xSourceSize)
{
case 1:
case 2:
{
new CPUx86.SSE.ConvertSI2SS { DestinationReg = CPUx86.Registers.XMM0, SourceReg = CPUx86.Registers.ESP, SourceIsIndirect = true };
new CPUx86.SSE.MoveSS { DestinationReg = CPUx86.Registers.ESP, DestinationIsIndirect = true, SourceReg = CPUx86.Registers.XMM0 };
break;
}
case 4:
{
if (!xSourceIsFloat)
{
if (IsIntegerSigned(xSource))
{
new CPUx86.SSE.ConvertSI2SS { DestinationReg = CPUx86.Registers.XMM0, SourceReg = CPUx86.Registers.ESP, SourceIsIndirect = true };
new CPUx86.SSE.MoveSS { DestinationReg = CPUx86.Registers.ESP, DestinationIsIndirect = true, SourceReg = CPUx86.Registers.XMM0 };
}
else
{
#if false
/*
* x86 assembler generated by GCC 4.86 with SSE2 arch enforced:
* uint2float:
*
* LCPI0_0:
* .quad 4841369599423283200 # double 4503599627370496
*
* push ebp
* mov ebp, esp
* sub esp, 8
* mov eax, dword ptr [ebp + 8]
* mov dword ptr [ebp - 4], eax
* movsd xmm0, qword ptr [.LCPI0_0]
* movaps xmm1, xmm0
* movd xmm2, eax
* por xmm2, xmm1
* subsd xmm2, xmm0
* cvtsd2ss xmm0, xmm2
* movss dword ptr [ebp - 8], xmm0
* ; Why moving the value on x87 registers after having avoided to touch them until now? Maybe is the x87 calling convention
* ; but we follow the .NET calling convention so we should push the result directly onto the stack
* fld dword ptr [ebp - 8]
* add esp, 8
* pop ebp
* ret
*
* Let's to write it in the Cosmos dialect...
*/
new CPUx86.Push { DestinationReg = CPUx86.Registers.EBP };
new CPUx86.Mov { DestinationReg = CPUx86.Registers.EBP, SourceReg = CPUx86.Registers.ESP };
new CPUx86.Sub { DestinationReg = CPUx86.Registers.ESP, SourceValue = 8 };
new CPUx86.Mov { DestinationReg = CPUx86.Registers.EAX, SourceReg = CPUx86.Registers.EBP + 8};
new CPUx86.Mov { DestinationReg = CPUx86.Registers.EBP - 4, SourceReg = CPUx86.Registers.EAX };
/* Magic number */
new CPUx86.SSE.MoveSD { DestinationReg = CPUx86.Registers.XMM0, SourceValue = 4841369599423283200 };
new CPUx86.SSE.MoveAPS { DestinationReg = CPUx86.Registers.XMM1, SourceReg = CPUx86.Registers.XMM0 };
new CPUx86.Mov { DestinationReg = CPUx86.Registers.XMM2, SourceReg = CPUx86.Registers.EAX };
new CPUx86.SSE.Por { DestinationReg = CPUx86.Registers.XMM2, SourceReg = CPUx86.Registers.XMM1 };
new CPUx86.SSE.SubSD { DestinationReg = CPUx86.Registers.XMM2, SourceReg = CPUx86.Registers.XMM0 };
new CPUx86.SSE.ConvertSD2SS { DestinationReg = CPUx86.Registers.XMM0, SourceReg = CPUx86.Registers.XMM2 };
new CPUx86.SSE.MoveSS { DestinationReg = CPUx86.Registers.EBP - 8, SourceReg = CPUx86.Registers.XMM0 };
//new CPUx86.Add { DestinationReg = CPUx86.Registers.ESP, SourceValue = 8 };
//new CPUx86.x87.FloatLoad { DestinationReg = CPUx86.Registers.EBP - 8, Size = 32 };
// Let's try to avoid the x87 fld instruction in EPB - 8 there is the result already!
new CPUx86.Mov { DestinationReg = CPUx86.Registers.ESP, SourceReg = CPUx86.Registers.EBP - 8 };
//new CPUx86.Add { DestinationReg = CPUx86.Registers.ESP, SourceValue = 8 };
new CPUx86.Pop { DestinationReg = CPUx86.Registers.EBP };
#endif
throw new NotImplementedException("Cosmos.IL2CPU.x86->IL->Conv_R4.cs->Conversion of UInt32 to Float is not yet implemented!");
}
}
break;
}
case 8:
{
if (xSourceIsFloat)
{
new CPUx86.SSE.ConvertSD2SS { SourceReg = CPUx86.Registers.ESP, DestinationReg = CPUx86.Registers.XMM0, SourceIsIndirect = true };
new CPUx86.SSE.MoveSS { SourceReg = CPUx86.Registers.XMM0, DestinationReg = CPUx86.Registers.ESP, DestinationIsIndirect = true };
}
else
{
if (IsIntegerSigned(xSource))
{
/*
* Again there is no SSE instruction in x86 to do this conversion as we need a 64 Bit register to do this! So we are forced
* to use the legacy x87 FPU to do this operation. In x64 the SSE instruction ConvertSIQ2SS should exist.
*/
new CPUx86.x87.IntLoad { DestinationReg = CPUx86.Registers.ESP, Size = 64, DestinationIsIndirect = true };
new CPUx86.x87.FloatStoreAndPop { DestinationReg = CPUx86.Registers.ESP, Size = 32, DestinationIsIndirect = true };
//throw new NotImplementedException("Cosmos.IL2CPU.x86->IL->Conv_R4.cs->Conversion of Int64 to Float is not yet implemented!");
}
else
{
throw new NotImplementedException("Cosmos.IL2CPU.x86->IL->Conv_R4.cs->Conversion of UInt64 to Float is not yet implemented!");
}
}
// Why I need to do all this Pop / Pop / Pushing or I get stack corruption? The result in the stack as expected so?
new CPUx86.Pop { DestinationReg = CPUx86.Registers.EAX };
new CPUx86.Pop { DestinationReg = CPUx86.Registers.ECX };
new CPUx86.Push { DestinationReg = CPUx86.Registers.EAX };
break;
}
default:
//EmitNotImplementedException( Assembler, GetServiceProvider(), "Conv_U4: SourceSize " + xStackItem.Size + " not supported!", mCurLabel, mMethodInformation, mCurOffset, mNextLabel );
throw new NotImplementedException();
}
}
}
}