Cosmos/source/Lost/Assembler/JIT/AMD64/Move.cs
LostTheBlack_cp 3060b02e0c AMD64 assembler:
[-] some unnecessary overloads
[+] overloaded operators in order to allow defining memory operands easily
[+] overloaded automatic conversions to allow operands
[+] Labels support
[+] code generator based on F# started
2008-05-09 11:29:38 +00:00

153 lines
4 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
namespace Lost.JIT.AMD64
{
[Serializable]
public class Move: ProcessorInstruction
{
public Move(InstructionOperand dest, InstructionOperand source)
{
Dest = dest;
Source = source;
}
public InstructionOperand Dest { get; set; }
public InstructionOperand Source { get; set; }
public override int? Size
{
get { throw new NotImplementedException(); }
}
public override string ToFASM()
{
if ((Dest is GeneralPurposeRegister || Dest is MemoryOperand)
&& (Source is GeneralPurposeRegister || Source is MemoryOperand || Source is ImmediateOperand)
) return string.Format("mov {0}, {1}", Dest, Source);
throw new NotImplementedException();
}
public override string OpCodeFASM
{
get { return "mov"; }
}
public override void Compile(Stream destStream)
{
GeneralPurposeRegister reg;
Rex rex = Rex.None;
#region Source is Immediate
if (Source is ImmediateOperand)
{
var source = Source as ImmediateOperand;
if (Dest is GeneralPurposeRegister)
{
reg = Dest as GeneralPurposeRegister;
int opcode = 0xB0;
opcode += reg.Register.GetIndex();
if (reg.Register.IsNew()) rex |= Rex.Reg;
switch (reg.Size)
{
case 1:
if (rex != Rex.None) destStream.WriteRex(rex);
destStream.WriteByte(opcode);
destStream.WriteByte(source.Value);
return;
case 2:
destStream.WriteByte(OperandSizeOverride);
if (rex != Rex.None) destStream.WriteRex(rex);
destStream.WriteByte(opcode + 8);
destStream.WriteShort(source.Value);
return;
case 4:
if (rex != Rex.None) destStream.WriteRex(rex);
destStream.WriteByte(opcode + 8);
destStream.WriteInt(source.Value);
return;
case 8:
rex |= Rex.Wide;
if (rex != Rex.None) destStream.WriteRex(rex);
destStream.WriteByte(opcode + 8);
destStream.WriteLong(source.Value);
return;
default:
throw new NotSupportedException();
}
}
if (Dest is MemoryOperand)
{
var mem = Dest as MemoryOperand;
throw new NotImplementedException();
}
}
#endregion Source is Immediate
int opcode_base = 0x88;
#region MOV reg, reg
if (Dest is GeneralPurposeRegister && Source is GeneralPurposeRegister)
{
var dest = Dest as GeneralPurposeRegister;
var source = Source as GeneralPurposeRegister;
if (dest.Size != source.Size) throw new NotSupportedException();
if (dest.Register.IsNew()) rex |= Rex.NewRegRM;
if (source.Register.IsNew()) rex |= Rex.Reg;
switch (dest.Size)
{
case 1:
break;
case 2:
destStream.WriteByte(OperandSizeOverride);
goto case 4;
case 4:
opcode_base++;
break;
case 8:
rex |= Rex.Wide;
goto case 4;
default:
throw new NotSupportedException();
}
if (rex != Rex.None) destStream.WriteRex(rex);
destStream.WriteByte(opcode_base);
WriteOperands(source.Register, dest.Register, destStream);
return;
}
#endregion MOV reg, reg
#region MOV reg/mem, reg (MOV reg, reg/mem)
var memory = Dest is GeneralPurposeRegister ? Source as MemoryOperand : Dest as MemoryOperand;
reg = Dest is GeneralPurposeRegister ? Dest as GeneralPurposeRegister : Source as GeneralPurposeRegister;
if (Dest is GeneralPurposeRegister) opcode_base += 2;
rex = NeedsRex(memory);
if (reg.Register.IsNew()) rex |= Rex.Reg;
switch (reg.Size)
{
case 1:
break;
case 2:
destStream.WriteByte(OperandSizeOverride);
goto case 4;
case 4:
opcode_base++;
break;
case 8:
rex |= Rex.Wide;
goto case 4;
default:
throw new NotSupportedException();
}
if (rex != Rex.None) destStream.WriteRex(rex);
destStream.WriteByte(opcode_base);
WriteOperands(reg, memory, destStream);
#endregion
}
}
}