mirror of
https://github.com/danbulant/Cosmos
synced 2026-05-29 20:30:44 +00:00
# Conflicts: # Tests/Cosmos.Compiler.Tests.SingleEchoTest/Kernel.cs # source/Cosmos.Assembler/Assembler.cs # source/Cosmos.IL2CPU/IL/Add.cs # source/Cosmos.IL2CPU/IL/Ceq.cs # source/Cosmos.IL2CPU/IL/Cgt.cs # source/Cosmos.IL2CPU/IL/Cgt_Un.cs # source/Cosmos.IL2CPU/IL/Clt.cs # source/Cosmos.IL2CPU/IL/Clt_Un.cs # source/Cosmos.IL2CPU/IL/Conv_I2.cs # source/Cosmos.IL2CPU/IL/Conv_I4.cs # source/Cosmos.IL2CPU/IL/Conv_I8.cs # source/Cosmos.IL2CPU/IL/Conv_R4.cs # source/Cosmos.IL2CPU/IL/Conv_R_Un.cs # source/Cosmos.IL2CPU/IL/Conv_U1.cs # source/Cosmos.IL2CPU/IL/Conv_U2.cs # source/Cosmos.IL2CPU/IL/Div.cs # source/Cosmos.IL2CPU/IL/Mul.cs # source/Cosmos.IL2CPU/IL/Sub.cs
183 lines
No EOL
11 KiB
C#
183 lines
No EOL
11 KiB
C#
using System;
|
|
using XSharp.Compiler;
|
|
using CPUx86 = Cosmos.Assembler.x86;
|
|
using Cosmos.Assembler.x86;
|
|
using static XSharp.Compiler.XSRegisters;
|
|
using static Cosmos.Assembler.x86.SSE.ComparePseudoOpcodes;
|
|
|
|
namespace Cosmos.IL2CPU.X86.IL
|
|
{
|
|
/// <summary>
|
|
/// Converts the unsigned integer value on top of the evaluation stack to F (native float) it can be double or some FPU extended precision Floating Point
|
|
/// type as the weird 80 bit float of x87). For now we assume it to be always equal to double.
|
|
/// </summary>
|
|
[Cosmos.IL2CPU.OpCode(ILOpCode.Code.Conv_R_Un)]
|
|
|
|
public class Conv_R_Un : ILOp
|
|
{
|
|
|
|
public Conv_R_Un(Cosmos.Assembler.Assembler aAsmblr)
|
|
: base(aAsmblr)
|
|
{
|
|
}
|
|
|
|
public override void Execute(MethodInfo aMethod, ILOpCode aOpCode)
|
|
{
|
|
var xValue = aOpCode.StackPopTypes[0];
|
|
var xValueIsFloat = TypeIsFloat(xValue);
|
|
var xValueSize = SizeOfType(xValue);
|
|
|
|
if (xValueSize > 8)
|
|
{
|
|
//EmitNotImplementedException( Assembler, aServiceProvider, "Size '" + xSize.Size + "' not supported (add)", aCurrentLabel, aCurrentMethodInfo, aCurrentOffset, aNextLabel );
|
|
throw new NotImplementedException();
|
|
}
|
|
//TODO if on stack a float it is first truncated, http://msdn.microsoft.com/en-us/library/system.reflection.emit.opcodes.conv_r_un.aspx
|
|
if (!xValueIsFloat)
|
|
{
|
|
switch (xValueSize)
|
|
{
|
|
case 1:
|
|
case 2:
|
|
case 4:
|
|
/*
|
|
* Code generated by C# / Visual Studio 2015
|
|
* mov eax,dword ptr [anInt]
|
|
* mov dword ptr [ebp-0E0h],eax
|
|
* cvtsi2sd xmm0,dword ptr [ebp-0E0h]
|
|
* mov ecx,dword ptr [ebp-0E0h]
|
|
* shr ecx,1Fh
|
|
* addsd xmm0,mmword ptr __xmm@41f00000000000000000000000000000 (01176B40h)[ecx*8]
|
|
* movsd mmword ptr [aDouble],xmm0 # This for now means to copy our converted double to ESP
|
|
*/
|
|
string BaseLabel = GetLabel(aMethod, aOpCode) + ".";
|
|
string LabelSign_Bit_Unset = BaseLabel + "LabelSign_Bit_Unset";
|
|
|
|
XS.Set(EAX, ESP, sourceIsIndirect: true);
|
|
XS.Set(EBP, EAX, destinationDisplacement: -0xE0, destinationIsIndirect: true);
|
|
XS.SSE2.ConvertSI2SD(XMM0, EBP, sourceDisplacement: -0xE0, sourceIsIndirect: true);
|
|
XS.Set(ECX, EBP, sourceDisplacement: -0xE0, sourceIsIndirect: true);
|
|
// OK now we put in ECX the last bit of our unsigned value, we call it "SIGN_BIT" but is a little improper...
|
|
XS.ShiftRight(ECX, 31);
|
|
/*
|
|
* if the 'SIGN_BIT' is 0 it means that our uint could have been placed in a normal int so ConvertSI2SD did already
|
|
* the right thing: we have finished
|
|
* if the value is 1 we need to do that addition with that weird constant to obtain the real value as double
|
|
*/
|
|
XS.Compare(ECX, 0x00);
|
|
XS.Jump(ConditionalTestEnum.Equal, LabelSign_Bit_Unset);
|
|
XS.LiteralCode(@"addsd xmm0, [__xmm@41f0000000000000]");
|
|
XS.Label(LabelSign_Bit_Unset);
|
|
// We have converted our value to double put it on ESP
|
|
// expand stack, that moved data is valid stack
|
|
XS.Sub(ESP, 4);
|
|
XS.SSE2.MoveSD(ESP, XMM0, destinationIsIndirect: true);
|
|
break;
|
|
#if false
|
|
/*
|
|
* This is the original code. It cannot work as ConvertSI2SS want a *signed* int as input but here we have an *unsigned* int
|
|
* indeed we get always 0!
|
|
*/
|
|
new CPUx86.Mov { SourceReg = CPUx86.RegistersEnum.ESP, DestinationReg = CPUx86.RegistersEnum.EAX, SourceIsIndirect = true };
|
|
XS.SSE.ConvertSI2SS(XSRegisters.XMM0, XSRegisters.EAX);
|
|
XS.SSE.MoveSS(XSRegisters.ESP, XSRegisters.XMM0, destinationIsIndirect: true);
|
|
break;
|
|
#endif
|
|
case 8:
|
|
/*
|
|
* This code is generated by GCC 4.8.4 it works perfectly but in Cosmos I continue to get stack corruption (a bug?)
|
|
* sub esp, 20
|
|
* mov edx, DWORD PTR [esp+28]
|
|
* mov eax, DWORD PTR [esp+24]
|
|
* mov DWORD PTR [esp+4], edx
|
|
* test edx, edx
|
|
* mov DWORD PTR [esp], eax
|
|
* fild QWORD PTR [esp]
|
|
* js .L11
|
|
* fstp QWORD PTR [esp+8]
|
|
* // This is not needed as we need the Double onto the stack not on x87 registers!
|
|
* //fld QWORD PTR [esp+8]
|
|
* add esp, 20
|
|
* .L11:
|
|
* fadd DWORD PTR .LC1
|
|
* fstp QWORD PTR [esp+8]
|
|
* // This is not needed as we need the Double onto the stack not on x87 registers!
|
|
* //fld QWORD PTR [esp+8]
|
|
* add esp, 20
|
|
*/
|
|
BaseLabel = GetLabel(aMethod, aOpCode) + ".";
|
|
LabelSign_Bit_Unset = BaseLabel + "LabelSign_Bit_Unset";
|
|
|
|
#if false
|
|
//new CPUx86.Sub { DestinationReg = CPUx86.Registers.ESP, SourceValue = 20 };
|
|
//new CPUx86.Push { DestinationReg = CPUx86.Registers.EBP };
|
|
|
|
//new CPUx86.Push { DestinationReg = CPUx86.Registers.EDX };
|
|
//new CPUx86.Push { DestinationReg = CPUx86.Registers.EAX };
|
|
new CPUx86.Mov { DestinationReg = CPUx86.Registers.EBP, SourceReg = CPUx86.Registers.ESP };
|
|
new CPUx86.Sub { DestinationReg = CPUx86.Registers.ESP, SourceValue = 20 };
|
|
new CPUx86.Mov { DestinationReg = CPUx86.Registers.ESP, SourceReg = CPUx86.Registers.EBP };
|
|
new CPUx86.Mov { DestinationReg = CPUx86.Registers.EDX, SourceReg = CPUx86.Registers.ESP, SourceIsIndirect = true, SourceDisplacement = 28 };
|
|
new CPUx86.Mov { DestinationReg = CPUx86.Registers.EAX, SourceReg = CPUx86.Registers.ESP, SourceIsIndirect = true, SourceDisplacement = 24 };
|
|
new CPUx86.Mov { DestinationReg = CPUx86.Registers.ESP, SourceReg = CPUx86.Registers.EDX, DestinationIsIndirect = true, DestinationDisplacement = 4 };
|
|
new CPUx86.Test { DestinationReg = CPUx86.Registers.EDX, SourceReg = CPUx86.Registers.EDX };
|
|
new CPUx86.x87.IntLoad { DestinationReg = CPUx86.Registers.ESP, DestinationIsIndirect = true, Size = 64 };
|
|
new CPUx86.ConditionalJump { Condition = CPUx86.ConditionalTestEnum.NotSign, DestinationLabel = LabelSign_Bit_Unset };
|
|
/* If the value was signed (that is more than LONG_MAX) we need to adjust the double adding a "Magical Constant" */
|
|
new Assembler.LiteralAssemblerCode(@"fadd DWORD [__ulong2double_const]");
|
|
new Assembler.Label(LabelSign_Bit_Unset);
|
|
// We have converted our value to double put it on ESP
|
|
//new CPUx86.x87.FloatStoreAndPop { DestinationReg = CPUx86.Registers.ESP, DestinationIsIndirect = true, DestinationDisplacement = 8, Size = 64 };
|
|
//new CPUx86.Add { DestinationReg = CPUx86.Registers.ESP, SourceValue = };
|
|
new CPUx86.x87.FloatStoreAndPop { DestinationReg = CPUx86.Registers.ESP, DestinationIsIndirect = true, Size = 64 };
|
|
//new CPUx86.x87.FloatLoad { DestinationReg = CPUx86.Registers.ESP, Size = 64, DestinationIsIndirect = true, DestinationDisplacement = 8 };
|
|
//new CPUx86.Sub { DestinationReg = CPUx86.Registers.ESP, SourceValue = 20 };
|
|
new CPUx86.Add { DestinationReg = CPUx86.Registers.ESP, SourceValue = 20 };
|
|
//new CPUx86.Add { DestinationReg = CPUx86.Registers.ESP, SourceValue = 4 };
|
|
//new CPUx86.Pop { DestinationReg = CPUx86.Registers.EBP };
|
|
//new CPUx86.Pop { DestinationReg = CPUx86.Registers.EDX };
|
|
//new CPUx86.Pop { DestinationReg = CPUx86.Registers.EAX };
|
|
//new Assembler.LiteralAssemblerCode(@"ALIGN 32, db 0");
|
|
//new Assembler.LiteralAssemblerCode(@".p2align 3");
|
|
#endif
|
|
|
|
/* This is my try! It is really simple and it should work the only problem is what should be the value of the constant
|
|
* __ulong2double_const2?
|
|
*/
|
|
/*
|
|
* mov EAX, ESP + 4
|
|
* fild qword ptr [esp]
|
|
* shr EAX, 31
|
|
* cmp ESP, 0
|
|
* jpe LabelSign_Bit_Unset
|
|
* LabelSign_Bit_Unset:
|
|
* fadd dword ptr __ulong2double_const2
|
|
* fstp ESP
|
|
*/
|
|
// Save the high part of the ulong in EAX (we cannot move all of ESP as it has 64 bit size)
|
|
XS.Set(EAX, ESP, sourceIsIndirect: true, sourceDisplacement: 4);
|
|
XS.FPU.IntLoad(ESP, isIndirect: true, size: RegisterSize.Long64);
|
|
// Get its highest bit to check if the value was signed or unsigned
|
|
//XS.ShiftRight(EAX, 31);
|
|
//XS.Compare(EAX, 0x00);
|
|
//XS.Jump(ConditionalTestEnum.Equal, LabelSign_Bit_Unset);
|
|
XS.Test(EAX, EAX);
|
|
XS.Jump(ConditionalTestEnum.NotSign, LabelSign_Bit_Unset);
|
|
//XS.LiteralCode(@"fadd qword [__ulong2double_const3]");
|
|
XS.LiteralCode(@"fadd qword [0x5F800000]");
|
|
XS.Label(LabelSign_Bit_Unset);
|
|
XS.FPU.FloatStoreAndPop(ESP, isIndirect: true, size: RegisterSize.Long64);
|
|
break;
|
|
|
|
default:
|
|
//EmitNotImplementedException( Assembler, GetServiceProvider(), "Conv_I: SourceSize " + xSource + " not supported!", mCurLabel, mMethodInformation, mCurOffset, mNextLabel );
|
|
throw new NotImplementedException("Conv_R_Un with type " + xValue + " not supported!");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
}
|
|
}
|
|
} |