<commit_before>﻿/*
 * (c) 2008 MOSA - The Managed Operating System Alliance
 *
 * Licensed under the terms of the New BSD License.
 *
 * Authors:
 *  <NAME> (tgiphil) <<EMAIL>>
 */

using System;

using Mosa.Runtime.CompilerFramework;
using Mosa.Runtime.Metadata;

namespace Mosa.Platforms.x86
{
	/// <summary>
	/// Returns X86 opcodes.
	/// </summary>
	public static class X86
	{

		#region X86Intructions

#pragma warning disable 1591
        /// <summary>
        /// This class contains OpCodes for every x86 asm instruction
        /// used by the x86 backend.
        /// 
        /// Note: When 16 bit register/memory usage is needed, 
        ///       the opcode for 32 bit is used, prefixed by 0x66.
        ///       This forces the CPU to fall back to 16 bit register/memory
        ///       usage.
        /// </summary>
		public static class X86Instruction
		{
			public static class Add
			{
				public static OpCode R_C = new OpCode(new byte[] { 0x81 }, 0);
				public static OpCode R_R = new OpCode(new byte[] { 0x03 });
				public static OpCode R_M = new OpCode(new byte[] { 0x03 });
				public static OpCode M_R = new OpCode(new byte[] { 0x01 });
				public static OpCode R_M_U8 = new OpCode(new byte[] { 0x02 }); // Add r/m8 to r8
				public static OpCode M_R_U8 = new OpCode(new byte[] { 0x00 }); // Add r8 to r/m8
			}
			public static class And
			{
				public static OpCode R_C = new OpCode(new byte[] { 0x81 }, 4);
				public static OpCode M_C = new OpCode(new byte[] { 0x81 }, 4);
				public static OpCode R_M = new OpCode(new byte[] { 0x23 });
				public static OpCode R_R = new OpCode(new byte[] { 0x23 });
				public static OpCode M_R = new OpCode(new byte[] { 0x21 });
			}
			public static class Div
			{
				public static OpCode R = new OpCode(new byte[] { 0xF7 }, 6);
				public static OpCode M = new OpCode(new byte[] { 0xF7 }, 6);
			}
			public static class Mov
			{
				public static OpCode R_C = new OpCode(new byte[] { 0xC7 }, 0); // Move imm32 to r/m32
				public static OpCode R_C_16 = new OpCode(new byte[] { 0x66, 0xC7 }, 0);
				public static OpCode M_C = new OpCode(new byte[] { 0xC7 }, 0);
				public static OpCode M_C_16 = new OpCode(new byte[] { 0x66, 0xC7 }, 0);
				public static OpCode R_R = new OpCode(new byte[] { 0x8B });
				public static OpCode R_R_16 = new OpCode(new byte[] { 0x66, 0x8B });
				public static OpCode R_M = new OpCode(new byte[] { 0x8B }); // Move r/m32 to R32
				public static OpCode R_M_16 = new OpCode(new byte[] { 0x66, 0x8B });
				public static OpCode M_R = new OpCode(new byte[] { 0x89 });
				public static OpCode M_R_16 = new OpCode(new byte[] { 0x66, 0x89 });
				public static OpCode M_R_U8 = new OpCode(new byte[] { 0x88 }); // Move R8 to r/rm8
				public static OpCode R_M_U8 = new OpCode(new byte[] { 0x8A }); // Move r/m8 to R8
			}
			public static class Neg
			{
				public static OpCode R = new OpCode(new byte[] { 0xF7 }, 3);
				public static OpCode M = new OpCode(new byte[] { 0xF7 }, 3);
			}
			public static class Or
			{
				public static OpCode R_C = new OpCode(new byte[] { 0x81 }, 1);
				public static OpCode M_C = new OpCode(new byte[] { 0x81 }, 1);
				public static OpCode R_M = new OpCode(new byte[] { 0x0B });
				public static OpCode R_R = new OpCode(new byte[] { 0x0B });
				public static OpCode M_R = new OpCode(new byte[] { 0x09 });
			}
			public static class Shl
			{
				public static OpCode R = new OpCode(new byte[] { 0xD3 }, 4);
				public static OpCode M = new OpCode(new byte[] { 0xD3 }, 4);
				public static OpCode R_C = new OpCode(new byte[] { 0xC1 }, 4);
				public static OpCode M_C = new OpCode(new byte[] { 0xC1 }, 4);
			}
			public static class Shr
			{
				public static OpCode R = new OpCode(new byte[] { 0xD3 }, 5);
				public static OpCode M = new OpCode(new byte[] { 0xD3 }, 5);
				public static OpCode R_C = new OpCode(new byte[] { 0xC1 }, 5);
				public static OpCode M_C = new OpCode(new byte[] { 0xC1 }, 5);
			}
			public static class Sub
			{
				public static OpCode O_C = new OpCode(new byte[] { 0x81 }, 5);
				public static OpCode R_O = new OpCode(new byte[] { 0x2B });
				public static OpCode R_O_16 = new OpCode(new byte[] { 0x66, 0x2B });
				public static OpCode M_R = new OpCode(new byte[] { 0x29 });

			}
			public static class Xor
			{
				public static OpCode R_C = new OpCode(new byte[] { 0x81 }, 6);
				public static OpCode R_M = new OpCode(new byte[] { 0x33 });
				public static OpCode R_R = new OpCode(new byte[] { 0x33 });
				public static OpCode M_R = new OpCode(new byte[] { 0x31 });
			}
			public static class Cwd
			{
				public static OpCode ALL = new OpCode(new byte[] { 0x99 });
			}
			public static class Adc
			{
				public static OpCode R_C = new OpCode(new byte[] { 0x81 });
				public static OpCode R_R = new OpCode(new byte[] { 0x11 });
				public static OpCode R_M = new OpCode(new byte[] { 0x13 });
				public static OpCode M_R = new OpCode(new byte[] { 0x11 });
			}
			public static class Out8
			{
				public static OpCode C_R = new OpCode(new byte[] { 0xE6 });
				public static OpCode R_R = new OpCode(new byte[] { 0xEE });
			}
			public static class Out32
			{
				public static OpCode C_R = new OpCode(new byte[] { 0xE7 });
				public static OpCode R_R = new OpCode(new byte[] { 0xEF });
			}
			public static class Xchg
			{
				public static OpCode R_M = new OpCode(new byte[] { 0x87 });
				public static OpCode R_R = new OpCode(new byte[] { 0x87 });
				public static OpCode M_R = new OpCode(new byte[] { 0x87 });
			}
			public static class Xsave
			{
				public static OpCode M = new OpCode(new byte[] { 0x0F, 0xAE }, 4);
			}
			public static class Dec
			{
				public static OpCode R = new OpCode(new byte[] { 0xFF }, 1);
				public static OpCode M = new OpCode(new byte[] { 0xFF }, 1);
			}
			public static class Inc
			{
				public static OpCode R = new OpCode(new byte[] { 0xFF }, 0);
				public static OpCode M = new OpCode(new byte[] { 0xFF }, 0);
			}
			public static class Not
			{
				public static OpCode R = new OpCode(new byte[] { 0xF7 }, 2);
				public static OpCode M = new OpCode(new byte[] { 0xF7 }, 2);
			}
			public static class Cmp
			{
				public static OpCode M_R = new OpCode(new byte[] { 0x39 });
				public static OpCode R_M = new OpCode(new byte[] { 0x3B });
				public static OpCode R_R = new OpCode(new byte[] { 0x3B });
				public static OpCode M_C = new OpCode(new byte[] { 0x81 }, 7);
				public static OpCode R_C = new OpCode(new byte[] { 0x81 }, 7);
				public static OpCode M_R_8 = new OpCode(new byte[] { 0x38 });
				public static OpCode R_M_8 = new OpCode(new byte[] { 0x3A });
			}
			public static class Cmpxchg
			{
				public static OpCode R_R = new OpCode(new byte[] { 0x0F, 0xB1 });
				public static OpCode M_R = new OpCode(new byte[] { 0x0F, 0xB1 });
			}
			public static class Mul
			{
				public static OpCode R = new OpCode(new byte[] { 0xF7 }, 4);
				public static OpCode M = new OpCode(new byte[] { 0xF7 }, 4);
			}
			public static class Sar
			{
				public static OpCode R = new OpCode(new byte[] { 0xD3 }, 7);
				public static OpCode M = new OpCode(new byte[] { 0xD3 }, 7);
				public static OpCode R_C = new OpCode(new byte[] { 0xC1 }, 7);
				public static OpCode M_C = new OpCode(new byte[] { 0xC1 }, 7);
			}
			public static class Sfence
			{
				public static OpCode ALL = new OpCode(new byte[] { 0x0F, 0xAE }, 7);
			}
			public static class Sgdt
			{
				public static OpCode M = new OpCode(new byte[] { 0x0F, 0x01 }, 0);
			}
			public static class Sidt
			{
				public static OpCode M = new OpCode(new byte[] { 0x0F, 0x01 }, 1);
			}
			public static class Sldt
			{
				public static OpCode M = new OpCode(new byte[] { 0x0F, 0x00 }, 0);
			}
			public static class Smsw
			{
				public static OpCode M = new OpCode(new byte[] { 0x0F, 0x01 }, 4);
				public static OpCode R = new OpCode(new byte[] { 0x0F, 0x01 }, 4);
			}
			public static class Stmxcsr
			{
				public static OpCode M = new OpCode(new byte[] { 0x0F, 0xAE }, 3);
			}
			public static class Shr_const
			{
				public static OpCode R = new OpCode(new byte[] { 0xD1 }, 5);
				public static OpCode M = new OpCode(new byte[] { 0xD1 }, 5);
			}
			public static class Rcr
			{
				public static OpCode R = new OpCode(new byte[] { 0xD1 }, 3);
				public static OpCode M = new OpCode(new byte[] { 0xD1 }, 3);
			}
			public static class Idiv
			{
				public static OpCode R = new OpCode(new byte[] { 0xF7 }, 7);
				public static OpCode M = new OpCode(new byte[] { 0xF7 }, 7);
			}
			public static class In8
			{
				public static OpCode R_C = new OpCode(new byte[] { 0xE4 });
				public static OpCode R_R = new OpCode(new byte[] { 0xEC });
			}
			public static class In32
			{
				public static OpCode R_C = new OpCode(new byte[] { 0xE5 });
				public static OpCode R_R = new OpCode(new byte[] { 0xED });
			}
			public static class Lgdt
			{
				public static OpCode M = new OpCode(new byte[] { 0x0F, 0x01 }, 2);
			}
			public static class Lidt
			{
				public static OpCode M = new OpCode(new byte[] { 0x0F, 0x01 }, 3);
			}
			public static class Lldt
			{
				public static OpCode R = new OpCode(new byte[] { 0x0F, 0x00 }, 2);
				public static OpCode M = new OpCode(new byte[] { 0x0F, 0x00 }, 2);
			}
			public static class Lmsw
			{
				public static OpCode R = new OpCode(new byte[] { 0x0F, 0x01 }, 6);
				public static OpCode M = new OpCode(new byte[] { 0x0F, 0x01 }, 6);
			}
			public static class Movsx8
			{
				public static OpCode R_R = new OpCode(new byte[] { 0x0F, 0xBE });
				public static OpCode R_M = new OpCode(new byte[] { 0x0F, 0xBE });
			}
			public static class Movsx16
			{
				public static OpCode R_R = new OpCode(new byte[] { 0x0F, 0xBF });
				public static OpCode R_M = new OpCode(new byte[] { 0x0F, 0xBF });
			}
			public static class Movzx8
			{
				public static OpCode R_R = new OpCode(new byte[] { 0x0F, 0xB6 });
				public static OpCode R_M = new OpCode(new byte[] { 0x0F, 0xB6 });
			}
			public static class Movzx16
			{
				public static OpCode R_R = new OpCode(new byte[] { 0x0F, 0xB7 });
				public static OpCode R_M = new OpCode(new byte[] { 0x0F, 0xB7 });
			}
			public static class Sbb
			{
				public static OpCode R_C = new OpCode(new byte[] { 0x81 }, 3);
				public static OpCode M_C = new OpCode(new byte[] { 0x81 }, 3);
				public static OpCode R_R = new OpCode(new byte[] { 0x19 });
				public static OpCode M_R = new OpCode(new byte[] { 0x19 });
				public static OpCode R_M = new OpCode(new byte[] { 0x1B });
			}
			public static class Movsd
			{
				public static OpCode R_L = new OpCode(new byte[] { 0xF2, 0x0F, 0x10 });
				public static OpCode R_M = new OpCode(new byte[] { 0xF2, 0x0F, 0x10 });
				public static OpCode R_R = new OpCode(new byte[] { 0xF2, 0x0F, 0x10 });
				public static OpCode M_R = new OpCode(new byte[] { 0xF2, 0x0F, 0x11 });
			}
			public static class Movss
			{
				public static OpCode R_L = new OpCode(new byte[] { 0xF3, 0x0F, 0x10 });
				public static OpCode R_M = new OpCode(new byte[] { 0xF3, 0x0F, 0x10 });
				public static OpCode R_R = new OpCode(new byte[] { 0xF3, 0x0F, 0x10 });
				public static OpCode M_R = new OpCode(new byte[] { 0xF3, 0x0F, 0x11 });
			}
			public static class Cvtsd2ss
			{
				public static OpCode R_R = new OpCode(new byte[] { 0xF2, 0x0F, 0x5A });
				public static OpCode R_M = new OpCode(new byte[] { 0xF2, 0x0F, 0x5A });
			}
			public static class Cvtsi2sd
			{
				public static OpCode R_R = new OpCode(new byte[] { 0xF2, 0x0F, 0x2A });
				public static OpCode R_M = new OpCode(new byte[] { 0xF2, 0x0F, 0x2A });
			}
			public static class Cvtsi2ss
			{
				public static OpCode R_R = new OpCode(new byte[] { 0xF3, 0x0F, 0x2A });
				public static OpCode R_M = new OpCode(new byte[] { 0xF3, 0x0F, 0x2A });
			}
			public static class Cvttsd2si
			{
				public static OpCode R_R = new OpCode(new byte[] { 0xF2, 0x0F, 0x2C });
				public static OpCode R_M = new OpCode(new byte[] { 0xF2, 0x0F, 0x2C });
			}
			public static class Cvttss2si
			{
				public static OpCode R_R = new OpCode(new byte[] { 0xF3, 0x0F, 0x2C });
				public static OpCode R_M = new OpCode(new byte[] { 0xF3, 0x0F, 0x2C });
			}
			public static class Cvtss2sd
			{
				public static OpCode R_L = new OpCode(new byte[] { 0xF3, 0x0F, 0x5A });
				public static OpCode R_M = new OpCode(new byte[] { 0xF3, 0x0F, 0x5A });
				public static OpCode R_R = new OpCode(new byte[] { 0xF3, 0x0F, 0x5A });
			}
			public static class Addsd
			{
				public static OpCode R_R = new OpCode(new byte[] { 0xF2, 0x0F, 0x58 });
				public static OpCode R_M = new OpCode(new byte[] { 0xF2, 0x0F, 0x58 });
				public static OpCode R_L = new OpCode(new byte[] { 0xF2, 0x0F, 0x58 });
			}
			public static class Addss
			{
				public static OpCode R_R = new OpCode(new byte[] { 0xF3, 0x0F, 0x58 });
				public static OpCode R_M = new OpCode(new byte[] { 0xF3, 0x0F, 0x58 });
				public static OpCode R_L = new OpCode(new byte[] { 0xF3, 0x0F, 0x58 });
			}
			public static class Subsd
			{
				public static OpCode R_R = new OpCode(new byte[] { 0xF2, 0x0F, 0x5C });
				public static OpCode R_M = new OpCode(new byte[] { 0xF2, 0x0F, 0x5C });
				public static OpCode R_L = new OpCode(new byte[] { 0xF2, 0x0F, 0x5C });
			}
			public static class Mulsd
			{
				public static OpCode R_R = new OpCode(new byte[] { 0xF2, 0x0F, 0x59 });
				public static OpCode R_M = new OpCode(new byte[] { 0xF2, 0x0F, 0x59 });
				public static OpCode R_L = new OpCode(new byte[] { 0xF2, 0x0F, 0x59 });
			}
			public static class Divsd
			{
				public static OpCode R_R = new OpCode(new byte[] { 0xF2, 0x0F, 0x5E });
				public static OpCode R_M = new OpCode(new byte[] { 0xF2, 0x0F, 0x5E });
			}
			public static class Cmpsd
			{
				public static OpCode R_R = new OpCode(new byte[] { 0xF2, 0x0F, 0xC2 });
				public static OpCode R_M = new OpCode(new byte[] { 0xF2, 0x0F, 0xC2 });
				public static OpCode R_L = new OpCode(new byte[] { 0xF2, 0x0F, 0xC2 });
				public static OpCode R_C = new OpCode(new byte[] { 0xF2, 0x0F, 0xC2 });
			}
			public static class Comisd
			{
				public static OpCode R_R = new OpCode(new byte[] { 0x66, 0x0F, 0x2F });
				public static OpCode R_M = new OpCode(new byte[] { 0x66, 0x0F, 0x2F });
				public static OpCode R_L = new OpCode(new byte[] { 0x66, 0x0F, 0x2F });
				public static OpCode R_C = new OpCode(new byte[] { 0x66, 0x0F, 0x2F });
			}
			public static class Comiss
			{
				public static OpCode R_R = new OpCode(new byte[] { 0x0F, 0x2F });
				public static OpCode R_M = new OpCode(new byte[] { 0x0F, 0x2F });
				public static OpCode R_L = new OpCode(new byte[] { 0x0F, 0x2F });
				public static OpCode R_C = new OpCode(new byte[] { 0x0F, 0x2F });
			}
			public static class Ucomisd
			{
				public static OpCode R_R = new OpCode(new byte[] { 0x66, 0x0F, 0x2E });
				public static OpCode R_M = new OpCode(new byte[] { 0x66, 0x0F, 0x2E });
				public static OpCode R_L = new OpCode(new byte[] { 0x66, 0x0F, 0x2E });
				public static OpCode R_C = new OpCode(new byte[] { 0x66, 0x0F, 0x2E });
			}
			public static class Ucomiss
			{
				public static OpCode R_R = new OpCode(new byte[] { 0x0F, 0x2E });
				public static OpCode R_M = new OpCode(new byte[] { 0x0F, 0x2E });
				public static OpCode R_L = new OpCode(new byte[] { 0x0F, 0x2E });
				public static OpCode R_C = new OpCode(new byte[] { 0x0F, 0x2E });
			}
			public static class Shrd
			{
				public static OpCode R_R_C = new OpCode(new byte[] { 0x0F, 0xAC }, 4);
				public static OpCode M_R_C = new OpCode(new byte[] { 0x0F, 0xAC }, 4);
				public static OpCode R_R_R = new OpCode(new byte[] { 0x0F, 0xAD }, 4);
				public static OpCode M_R_R = new OpCode(new byte[] { 0x0F, 0xAD }, 4);
			}
			public static class Shld
			{
				public static OpCode R_R_C = new OpCode(new byte[] { 0x0F, 0xA4 }, 4);
				public static OpCode M_R_C = new OpCode(new byte[] { 0x0F, 0xA4 }, 4);
				public static OpCode R_R_R = new OpCode(new byte[] { 0x0F, 0xA5 }, 4);
				public static OpCode M_R_R = new OpCode(new byte[] { 0x0F, 0xA5 }, 4);
			}
		};
#pragma warning restore 1591

		#endregion

		#region Add
		/// <summary>
		/// Add
		/// </summary>
		/// <param name="dest">The dest.</param>
		/// <param name="src">The SRC.</param>
		/// <returns></returns>
		public static OpCode Add(Operand dest, Operand src)
		{
			if ((dest is RegisterOperand) && (src is ConstantOperand))
				return X86Instruction.Add.R_C;

			if ((dest is RegisterOperand) && (src is RegisterOperand))
				return X86Instruction.Add.R_R;

			if ((dest is RegisterOperand) && (src is MemoryOperand))
				if (IsUByte(dest))
					return X86Instruction.Add.R_M_U8;
				else
					return X86Instruction.Add.R_M;

			if ((dest is MemoryOperand) && (src is RegisterOperand))
				if (IsUByte(dest))
					return X86Instruction.Add.M_R_U8;
				else
					return X86Instruction.Add.M_R;

			throw new ArgumentException(@"No opcode for operand type.");
		}

		#endregion

		#region And
		/// <summary>
		/// And
		/// </summary>
		/// <param name="dest">The dest.</param>
		/// <param name="src">The SRC.</param>
		/// <returns></returns>
		public static OpCode And(Operand dest, Operand src)
		{
			if ((dest is RegisterOperand) && (src is ConstantOperand))
				return X86Instruction.And.R_C;

			if ((dest is MemoryOperand) && (src is ConstantOperand))
				return X86Instruction.And.M_C;

			if ((dest is RegisterOperand) && (src is MemoryOperand))
				return X86Instruction.And.R_M;

			if ((dest is RegisterOperand) && (src is RegisterOperand))
				return X86Instruction.And.R_R;

			if ((dest is MemoryOperand) && (src is RegisterOperand))
				return X86Instruction.And.M_C;

			throw new ArgumentException(@"No opcode for operand type.");
		}

		#endregion

		#region Div
		/// <summary>
		/// Returns the matching OpCode for DIV
		/// </summary>
		/// <param name="dest">Destination operand</param>
		/// <param name="src">Source Operand</param>
		/// <returns>The matching OpCode</returns>
		public static OpCode Div(Operand dest, Operand src)
		{
			if (src is RegisterOperand)
				return X86Instruction.Div.R;

			if (src is MemoryOperand)
				return X86Instruction.Div.M;

			throw new ArgumentException(@"No opcode for operand type.");
		}

		#endregion

		#region Move
		/// <summary>
		/// Move
		/// </summary>
		/// <param name="dest">The dest.</param>
		/// <param name="src">The SRC.</param>
		/// <returns></returns>
		public static OpCode Move(Operand dest, Operand src)
		{
			if ((dest is RegisterOperand) && (src is ConstantOperand)) {
				if (IsChar(src))
					return X86Instruction.Mov.R_C_16;
				else
					return X86Instruction.Mov.R_C;
			}

			if ((dest is MemoryOperand) && (src is ConstantOperand)) {
				if (IsChar(src))
					return X86Instruction.Mov.M_C_16;
				else
					return X86Instruction.Mov.M_C;
			}

			if ((dest is RegisterOperand) && (src is RegisterOperand)) {
				if (IsChar(src))
					return X86Instruction.Mov.R_R_16;
				else
					return X86Instruction.Mov.R_R;
			}

			if ((dest is RegisterOperand) && (src is MemoryOperand)) {
				if (IsByte(dest))
					return X86Instruction.Mov.R_M_U8;
				else if (IsChar(dest))
					return X86Instruction.Mov.R_M_16;
				else
					return X86Instruction.Mov.R_M;
			}

			if ((dest is MemoryOperand) && (src is RegisterOperand)) {
				if (IsByte(dest))
					return X86Instruction.Mov.M_R_U8;
				else if (IsChar(dest))
					return X86Instruction.Mov.M_R_16;
				else
					return X86Instruction.Mov.M_R;
			}

			throw new ArgumentException(@"No opcode for operand type. [" + dest.GetType() + ", " + src.GetType() + ")");
		}

		#endregion

		#region Neg
		/// <summary>
		/// Negate
		/// </summary>
		/// <param name="dest">The dest.</param>
		/// <returns></returns>
		public static OpCode Neg(Operand dest)
		{
			if (dest is RegisterOperand)
				return X86Instruction.Neg.R;

			if (dest is MemoryOperand)
				return X86Instruction.Neg.M;

			throw new ArgumentException(@"No opcode for operand type.");
		}

		#endregion

		#region Or
		/// <summary>
		/// Or
		/// </summary>
		/// <param name="dest">The dest.</param>
		/// <param name="src">The SRC.</param>
		/// <returns></returns>
		public static OpCode Or(Operand dest, Operand src)
		{
			if ((dest is RegisterOperand) && (src is ConstantOperand))
				return X86Instruction.Or.R_C;

			if ((dest is RegisterOperand) && (src is MemoryOperand))
				return X86Instruction.Or.R_M;

			if ((dest is RegisterOperand) && (src is RegisterOperand))
				return X86Instruction.Or.R_R;

			if ((dest is MemoryOperand) && (src is RegisterOperand))
				return X86Instruction.Or.M_R;

			throw new ArgumentException(@"No opcode for operand type.");
		}

		#endregion

		#region Shl
		/// <summary>
		/// SHL
		/// </summary>
		/// <param name="dest">The dest.</param>
		/// <param name="src">The SRC.</param>
		/// <returns></returns>
		public static OpCode Shl(Operand dest, Operand src)
		{
			if ((dest is RegisterOperand) && (src is ConstantOperand))
				return X86Instruction.Shl.R_C;

			if ((dest is MemoryOperand) && (src is ConstantOperand))
				return X86Instruction.Shl.M_C;

			if (dest is RegisterOperand)
				return X86Instruction.Shl.R;

			if (dest is MemoryOperand)
				return X86Instruction.Shl.M;

			throw new ArgumentException(@"No opcode for operand type.");
		}

		#endregion

		#region Shr
		/// <summary>
		/// SHR
		/// </summary>
		/// <param name="dest">The dest.</param>
		/// <param name="src">The SRC.</param>
		/// <returns></returns>
		public static OpCode Shr(Operand dest, Operand src)
		{
			if ((dest is RegisterOperand) && (src is ConstantOperand))
				return X86Instruction.Shr.R_C;

			if ((dest is MemoryOperand) && (src is ConstantOperand))
				return X86Instruction.Shr.M_C;

			if (dest is RegisterOperand)
				return X86Instruction.Shr.R;

			if (dest is MemoryOperand)
				return X86Instruction.Shr.M;

			throw new ArgumentException(@"No opcode for operand type.");
		}

		#endregion

		#region Sub
		/// <summary>
		/// Sub
		/// </summary>
		/// <param name="dest">The dest.</param>
		/// <param name="src">The SRC.</param>
		/// <returns></returns>
		public static OpCode Sub(Operand dest, Operand src)
		{
			if ((dest is Operand) && (src is ConstantOperand))
				return X86Instruction.Sub.O_C;

			if ((dest is RegisterOperand) && (src is Operand)) {
				if (src.Type.Type == CilElementType.Char || dest.Type.Type == CilElementType.Char)
					return X86Instruction.Sub.R_O_16;
				else
					return X86Instruction.Sub.R_O;
			}

			if ((dest is MemoryOperand) && (src is RegisterOperand))
				return X86Instruction.Sub.M_R;

			throw new ArgumentException(@"No opcode for operand type.");
		}
		#endregion

		#region Xor
		/// <summary>
		/// Xor
		/// </summary>
		/// <param name="dest">The dest.</param>
		/// <param name="src">The SRC.</param>
		/// <returns></returns>
		public static OpCode Xor(Operand dest, Operand src)
		{
			if ((dest is RegisterOperand) && (src is ConstantOperand))
				return X86Instruction.Xor.R_C;

			if ((dest is RegisterOperand) && (src is MemoryOperand))
				return X86Instruction.Xor.R_M;

			if ((dest is RegisterOperand) && (src is RegisterOperand))
				return X86Instruction.Xor.R_R;

			if ((dest is MemoryOperand) && (src is RegisterOperand))
				return X86Instruction.Xor.M_R;

			throw new ArgumentException(@"No opcode for operand type.");
		}

		#endregion

		/// <summary>
		/// Adc
		/// </summary>
		/// <param name="dest">The dest.</param>
		/// <param name="src">The SRC.</param>
		/// <returns></returns>
		public static OpCode Adc(Operand dest, Operand src)
		{
			if ((dest is RegisterOperand) && (src is ConstantOperand)) return X86Instruction.Adc.R_C;
			if ((dest is RegisterOperand) && (src is RegisterOperand)) return X86Instruction.Adc.R_R;
			if ((dest is RegisterOperand) && (src is MemoryOperand)) return X86Instruction.Adc.R_M;
			if ((dest is MemoryOperand) && (src is RegisterOperand)) return X86Instruction.Adc.M_R;
			throw new ArgumentException(@"No opcode for operand type.");
		}

		/// <summary>
		/// Out8
		/// </summary>
		/// <param name="dest">The dest.</param>
		/// <param name="src">The SRC.</param>
		/// <returns></returns>
		public static OpCode Out8(Operand dest, Operand src)
		{
			if ((dest is ConstantOperand) && (src is RegisterOperand)) return X86Instruction.Out8.C_R;
			if ((dest is RegisterOperand) && (src is RegisterOperand)) return X86Instruction.Out8.R_R;
			throw new ArgumentException(@"No opcode for operand type.");
		}

		/// <summary>
		/// Out32
		/// </summary>
		/// <param name="dest">The dest.</param>
		/// <param name="src">The SRC.</param>
		/// <returns></returns>
		public static OpCode Out32(Operand dest, Operand src)
		{
			if ((dest is ConstantOperand) && (src is RegisterOperand)) return X86Instruction.Out32.C_R;
			if ((dest is RegisterOperand) && (src is RegisterOperand)) return X86Instruction.Out32.R_R;
			throw new ArgumentException(@"No opcode for operand type.");
		}

		/// <summary>
		/// XCHG
		/// </summary>
		/// <param name="dest">The dest.</param>
		/// <param name="src">The SRC.</param>
		/// <returns></returns>
		public static OpCode Xchg(Operand dest, Operand src)
		{
			if ((dest is RegisterOperand) && (src is MemoryOperand)) return X86Instruction.Xchg.R_M;
			if ((dest is RegisterOperand) && (src is RegisterOperand)) return X86Instruction.Xchg.R_R;
			if ((dest is MemoryOperand) && (src is RegisterOperand)) return X86Instruction.Xchg.M_R;
			throw new ArgumentException(@"No opcode for operand type.");
		}

		/// <summary>
		/// Xsave
		/// </summary>
		/// <param name="dest">The dest.</param>
		/// <returns></returns>
		public static OpCode Xsave(Operand dest)
		{
			if (dest is MemoryOperand) return X86Instruction.Xsave.M;
			throw new ArgumentException(@"No opcode for operand type.");
		}

		/// <summary>
		/// Dec
		/// </summary>
		/// <param name="dest">The dest.</param>
		/// <returns></returns>
		public static OpCode Dec(Operand dest)
		{
			if (dest is RegisterOperand) return X86Instruction.Dec.R;
			if (dest is MemoryOperand) return X86Instruction.Dec.M;
			throw new ArgumentException(@"No opcode for operand type.");
		}

		/// <summary>
		/// Inc
		/// </summary>
		/// <param name="dest">The dest.</param>
		/// <returns></returns>
		public static OpCode Inc(Operand dest)
		{
			if (dest is RegisterOperand) return X86Instruction.Inc.R;
			if (dest is MemoryOperand) return X86Instruction.Inc.M;
			throw new ArgumentException(@"No opcode for operand type.");
		}

		/// <summary>
		/// Not
		/// </summary>
		/// <param name="dest">The dest.</param>
		/// <returns></returns>
		public static OpCode Not(Operand dest)
		{
			if (dest is RegisterOperand) return X86Instruction.Not.R;
			if (dest is MemoryOperand) return X86Instruction.Not.M;
			throw new ArgumentException(@"No opcode for operand type.");
		}

		/// <summary>
		/// CMP
		/// </summary>
		/// <param name="dest">The dest.</param>
		/// <param name="src">The SRC.</param>
		/// <returns></returns>
		public static OpCode Cmp(Operand dest, Operand src)
		{
			if ((dest is MemoryOperand) && (src is RegisterOperand))
				if (IsByte(dest))
					return X86Instruction.Cmp.M_R_8;
				else
					return X86Instruction.Cmp.M_R;

			if ((dest is RegisterOperand) && (src is MemoryOperand))
				if (IsByte(src))
					return X86Instruction.Cmp.R_M_8;
				else
					return X86Instruction.Cmp.R_M;

			if ((dest is RegisterOperand) && (src is RegisterOperand)) return X86Instruction.Cmp.R_R;
			if ((dest is MemoryOperand) && (src is ConstantOperand)) return X86Instruction.Cmp.M_C;
			if ((dest is RegisterOperand) && (src is ConstantOperand)) return X86Instruction.Cmp.R_C;
			throw new ArgumentException(@"No opcode for operand type.");
		}

		/// <summary>
		/// CMPXCHG
		/// </summary>
		/// <param name="dest">The dest.</param>
		/// <param name="src">The SRC.</param>
		/// <returns></returns>
		public static OpCode Cmpxchg(Operand dest, Operand src)
		{
			if ((dest is RegisterOperand) && (src is RegisterOperand)) return X86Instruction.Cmpxchg.R_R;<commit_msg>- Fixed NOT U2 and CMP U2 handling in Mosa.Platforms.X86 - 11 additional test cases now pass (NotC, LdlocaU2_CheckValue, LdargaU2_CheckValue) <commit_after>﻿/*
 * (c) 2008 MOSA - The Managed Operating System Alliance
 *
 * Licensed under the terms of the New BSD License.
 *
 * Authors:
 *  <NAME> (tgiphil) <<EMAIL>>
 */

using System;

using Mosa.Runtime.CompilerFramework;
using Mosa.Runtime.Metadata;

namespace Mosa.Platforms.x86
{
	/// <summary>
	/// Returns X86 opcodes.
	/// </summary>
	public static class X86
	{

		#region X86Intructions

#pragma warning disable 1591
		/// <summary>
		/// This class contains OpCodes for every x86 asm instruction
		/// used by the x86 backend.
		/// 
		/// Note: When 16 bit register/memory usage is needed, 
		///       the opcode for 32 bit is used, prefixed by 0x66.
		///       This forces the CPU to fall back to 16 bit register/memory
		///       usage.
		/// </summary>
		public static class X86Instruction
		{
			public static class Add
			{
				public static OpCode R_C = new OpCode(new byte[] { 0x81 }, 0);
				public static OpCode R_R = new OpCode(new byte[] { 0x03 });
				public static OpCode R_M = new OpCode(new byte[] { 0x03 });
				public static OpCode M_R = new OpCode(new byte[] { 0x01 });
				public static OpCode R_M_U8 = new OpCode(new byte[] { 0x02 }); // Add r/m8 to r8
				public static OpCode M_R_U8 = new OpCode(new byte[] { 0x00 }); // Add r8 to r/m8
			}
			public static class And
			{
				public static OpCode R_C = new OpCode(new byte[] { 0x81 }, 4);
				public static OpCode M_C = new OpCode(new byte[] { 0x81 }, 4);
				public static OpCode R_M = new OpCode(new byte[] { 0x23 });
				public static OpCode R_R = new OpCode(new byte[] { 0x23 });
				public static OpCode M_R = new OpCode(new byte[] { 0x21 });
			}
			public static class Div
			{
				public static OpCode R = new OpCode(new byte[] { 0xF7 }, 6);
				public static OpCode M = new OpCode(new byte[] { 0xF7 }, 6);
			}
			public static class Mov
			{
				public static OpCode R_C = new OpCode(new byte[] { 0xC7 }, 0); // Move imm32 to r/m32
				public static OpCode R_C_16 = new OpCode(new byte[] { 0x66, 0xC7 }, 0);
				public static OpCode M_C = new OpCode(new byte[] { 0xC7 }, 0);
				public static OpCode M_C_16 = new OpCode(new byte[] { 0x66, 0xC7 }, 0);
				public static OpCode R_R = new OpCode(new byte[] { 0x8B });
				public static OpCode R_R_16 = new OpCode(new byte[] { 0x66, 0x8B });
				public static OpCode R_M = new OpCode(new byte[] { 0x8B }); // Move r/m32 to R32
				public static OpCode R_M_16 = new OpCode(new byte[] { 0x66, 0x8B });
				public static OpCode M_R = new OpCode(new byte[] { 0x89 });
				public static OpCode M_R_16 = new OpCode(new byte[] { 0x66, 0x89 });
				public static OpCode M_R_U8 = new OpCode(new byte[] { 0x88 }); // Move R8 to r/rm8
				public static OpCode R_M_U8 = new OpCode(new byte[] { 0x8A }); // Move r/m8 to R8
			}
			public static class Neg
			{
				public static OpCode R = new OpCode(new byte[] { 0xF7 }, 3);
				public static OpCode M = new OpCode(new byte[] { 0xF7 }, 3);
			}
			public static class Or
			{
				public static OpCode R_C = new OpCode(new byte[] { 0x81 }, 1);
				public static OpCode M_C = new OpCode(new byte[] { 0x81 }, 1);
				public static OpCode R_M = new OpCode(new byte[] { 0x0B });
				public static OpCode R_R = new OpCode(new byte[] { 0x0B });
				public static OpCode M_R = new OpCode(new byte[] { 0x09 });
			}
			public static class Shl
			{
				public static OpCode R = new OpCode(new byte[] { 0xD3 }, 4);
				public static OpCode M = new OpCode(new byte[] { 0xD3 }, 4);
				public static OpCode R_C = new OpCode(new byte[] { 0xC1 }, 4);
				public static OpCode M_C = new OpCode(new byte[] { 0xC1 }, 4);
			}
			public static class Shr
			{
				public static OpCode R = new OpCode(new byte[] { 0xD3 }, 5);
				public static OpCode M = new OpCode(new byte[] { 0xD3 }, 5);
				public static OpCode R_C = new OpCode(new byte[] { 0xC1 }, 5);
				public static OpCode M_C = new OpCode(new byte[] { 0xC1 }, 5);
			}
			public static class Sub
			{
				public static OpCode O_C = new OpCode(new byte[] { 0x81 }, 5);
				public static OpCode R_O = new OpCode(new byte[] { 0x2B });
				public static OpCode R_O_16 = new OpCode(new byte[] { 0x66, 0x2B });
				public static OpCode M_R = new OpCode(new byte[] { 0x29 });

			}
			public static class Xor
			{
				public static OpCode R_C = new OpCode(new byte[] { 0x81 }, 6);
				public static OpCode R_M = new OpCode(new byte[] { 0x33 });
				public static OpCode R_R = new OpCode(new byte[] { 0x33 });
				public static OpCode M_R = new OpCode(new byte[] { 0x31 });
			}
			public static class Cwd
			{
				public static OpCode ALL = new OpCode(new byte[] { 0x99 });
			}
			public static class Adc
			{
				public static OpCode R_C = new OpCode(new byte[] { 0x81 });
				public static OpCode R_R = new OpCode(new byte[] { 0x11 });
				public static OpCode R_M = new OpCode(new byte[] { 0x13 });
				public static OpCode M_R = new OpCode(new byte[] { 0x11 });
			}
			public static class Out8
			{
				public static OpCode C_R = new OpCode(new byte[] { 0xE6 });
				public static OpCode R_R = new OpCode(new byte[] { 0xEE });
			}
			public static class Out32
			{
				public static OpCode C_R = new OpCode(new byte[] { 0xE7 });
				public static OpCode R_R = new OpCode(new byte[] { 0xEF });
			}
			public static class Xchg
			{
				public static OpCode R_M = new OpCode(new byte[] { 0x87 });
				public static OpCode R_R = new OpCode(new byte[] { 0x87 });
				public static OpCode M_R = new OpCode(new byte[] { 0x87 });
			}
			public static class Xsave
			{
				public static OpCode M = new OpCode(new byte[] { 0x0F, 0xAE }, 4);
			}
			public static class Dec
			{
				public static OpCode R = new OpCode(new byte[] { 0xFF }, 1);
				public static OpCode M = new OpCode(new byte[] { 0xFF }, 1);
			}
			public static class Inc
			{
				public static OpCode R = new OpCode(new byte[] { 0xFF }, 0);
				public static OpCode M = new OpCode(new byte[] { 0xFF }, 0);
			}
			public static class Not
			{
				public static OpCode MR_8 = new OpCode(new byte[] { 0xF6 }, 2);
				public static OpCode MR_16 = new OpCode(new byte[] { 0x66, 0xF7 }, 2);
				public static OpCode MR = new OpCode(new byte[] { 0xF7 }, 2);
			}
			public static class Cmp
			{
				public static OpCode M_R = new OpCode(new byte[] { 0x39 });
				public static OpCode R_M = new OpCode(new byte[] { 0x3B });
				public static OpCode R_R = new OpCode(new byte[] { 0x3B });
				public static OpCode M_C = new OpCode(new byte[] { 0x81 }, 7);
				public static OpCode R_C = new OpCode(new byte[] { 0x81 }, 7);
				public static OpCode M_R_8 = new OpCode(new byte[] { 0x38 });
				public static OpCode R_M_8 = new OpCode(new byte[] { 0x3A });
				public static OpCode M_R_16 = new OpCode(new byte[] { 0x66, 0x39 });
				public static OpCode R_M_16 = new OpCode(new byte[] { 0x66, 0x3B });
			}
			public static class Cmpxchg
			{
				public static OpCode R_R = new OpCode(new byte[] { 0x0F, 0xB1 });
				public static OpCode M_R = new OpCode(new byte[] { 0x0F, 0xB1 });
			}
			public static class Mul
			{
				public static OpCode R = new OpCode(new byte[] { 0xF7 }, 4);
				public static OpCode M = new OpCode(new byte[] { 0xF7 }, 4);
			}
			public static class Sar
			{
				public static OpCode R = new OpCode(new byte[] { 0xD3 }, 7);
				public static OpCode M = new OpCode(new byte[] { 0xD3 }, 7);
				public static OpCode R_C = new OpCode(new byte[] { 0xC1 }, 7);
				public static OpCode M_C = new OpCode(new byte[] { 0xC1 }, 7);
			}
			public static class Sfence
			{
				public static OpCode ALL = new OpCode(new byte[] { 0x0F, 0xAE }, 7);
			}
			public static class Sgdt
			{
				public static OpCode M = new OpCode(new byte[] { 0x0F, 0x01 }, 0);
			}
			public static class Sidt
			{
				public static OpCode M = new OpCode(new byte[] { 0x0F, 0x01 }, 1);
			}
			public static class Sldt
			{
				public static OpCode M = new OpCode(new byte[] { 0x0F, 0x00 }, 0);
			}
			public static class Smsw
			{
				public static OpCode M = new OpCode(new byte[] { 0x0F, 0x01 }, 4);
				public static OpCode R = new OpCode(new byte[] { 0x0F, 0x01 }, 4);
			}
			public static class Stmxcsr
			{
				public static OpCode M = new OpCode(new byte[] { 0x0F, 0xAE }, 3);
			}
			public static class Shr_const
			{
				public static OpCode R = new OpCode(new byte[] { 0xD1 }, 5);
				public static OpCode M = new OpCode(new byte[] { 0xD1 }, 5);
			}
			public static class Rcr
			{
				public static OpCode R = new OpCode(new byte[] { 0xD1 }, 3);
				public static OpCode M = new OpCode(new byte[] { 0xD1 }, 3);
			}
			public static class Idiv
			{
				public static OpCode R = new OpCode(new byte[] { 0xF7 }, 7);
				public static OpCode M = new OpCode(new byte[] { 0xF7 }, 7);
			}
			public static class In8
			{
				public static OpCode R_C = new OpCode(new byte[] { 0xE4 });
				public static OpCode R_R = new OpCode(new byte[] { 0xEC });
			}
			public static class In32
			{
				public static OpCode R_C = new OpCode(new byte[] { 0xE5 });
				public static OpCode R_R = new OpCode(new byte[] { 0xED });
			}
			public static class Lgdt
			{
				public static OpCode M = new OpCode(new byte[] { 0x0F, 0x01 }, 2);
			}
			public static class Lidt
			{
				public static OpCode M = new OpCode(new byte[] { 0x0F, 0x01 }, 3);
			}
			public static class Lldt
			{
				public static OpCode R = new OpCode(new byte[] { 0x0F, 0x00 }, 2);
				public static OpCode M = new OpCode(new byte[] { 0x0F, 0x00 }, 2);
			}
			public static class Lmsw
			{
				public static OpCode R = new OpCode(new byte[] { 0x0F, 0x01 }, 6);
				public static OpCode M = new OpCode(new byte[] { 0x0F, 0x01 }, 6);
			}
			public static class Movsx8
			{
				public static OpCode R_R = new OpCode(new byte[] { 0x0F, 0xBE });
				public static OpCode R_M = new OpCode(new byte[] { 0x0F, 0xBE });
			}
			public static class Movsx16
			{
				public static OpCode R_R = new OpCode(new byte[] { 0x0F, 0xBF });
				public static OpCode R_M = new OpCode(new byte[] { 0x0F, 0xBF });
			}
			public static class Movzx8
			{
				public static OpCode R_R = new OpCode(new byte[] { 0x0F, 0xB6 });
				public static OpCode R_M = new OpCode(new byte[] { 0x0F, 0xB6 });
			}
			public static class Movzx16
			{
				public static OpCode R_R = new OpCode(new byte[] { 0x0F, 0xB7 });
				public static OpCode R_M = new OpCode(new byte[] { 0x0F, 0xB7 });
			}
			public static class Sbb
			{
				public static OpCode R_C = new OpCode(new byte[] { 0x81 }, 3);
				public static OpCode M_C = new OpCode(new byte[] { 0x81 }, 3);
				public static OpCode R_R = new OpCode(new byte[] { 0x19 });
				public static OpCode M_R = new OpCode(new byte[] { 0x19 });
				public static OpCode R_M = new OpCode(new byte[] { 0x1B });
			}
			public static class Movsd
			{
				public static OpCode R_L = new OpCode(new byte[] { 0xF2, 0x0F, 0x10 });
				public static OpCode R_M = new OpCode(new byte[] { 0xF2, 0x0F, 0x10 });
				public static OpCode R_R = new OpCode(new byte[] { 0xF2, 0x0F, 0x10 });
				public static OpCode M_R = new OpCode(new byte[] { 0xF2, 0x0F, 0x11 });
			}
			public static class Movss
			{
				public static OpCode R_L = new OpCode(new byte[] { 0xF3, 0x0F, 0x10 });
				public static OpCode R_M = new OpCode(new byte[] { 0xF3, 0x0F, 0x10 });
				public static OpCode R_R = new OpCode(new byte[] { 0xF3, 0x0F, 0x10 });
				public static OpCode M_R = new OpCode(new byte[] { 0xF3, 0x0F, 0x11 });
			}
			public static class Cvtsd2ss
			{
				public static OpCode R_R = new OpCode(new byte[] { 0xF2, 0x0F, 0x5A });
				public static OpCode R_M = new OpCode(new byte[] { 0xF2, 0x0F, 0x5A });
			}
			public static class Cvtsi2sd
			{
				public static OpCode R_R = new OpCode(new byte[] { 0xF2, 0x0F, 0x2A });
				public static OpCode R_M = new OpCode(new byte[] { 0xF2, 0x0F, 0x2A });
			}
			public static class Cvtsi2ss
			{
				public static OpCode R_R = new OpCode(new byte[] { 0xF3, 0x0F, 0x2A });
				public static OpCode R_M = new OpCode(new byte[] { 0xF3, 0x0F, 0x2A });
			}
			public static class Cvttsd2si
			{
				public static OpCode R_R = new OpCode(new byte[] { 0xF2, 0x0F, 0x2C });
				public static OpCode R_M = new OpCode(new byte[] { 0xF2, 0x0F, 0x2C });
			}
			public static class Cvttss2si
			{
				public static OpCode R_R = new OpCode(new byte[] { 0xF3, 0x0F, 0x2C });
				public static OpCode R_M = new OpCode(new byte[] { 0xF3, 0x0F, 0x2C });
			}
			public static class Cvtss2sd
			{
				public static OpCode R_L = new OpCode(new byte[] { 0xF3, 0x0F, 0x5A });
				public static OpCode R_M = new OpCode(new byte[] { 0xF3, 0x0F, 0x5A });
				public static OpCode R_R = new OpCode(new byte[] { 0xF3, 0x0F, 0x5A });
			}
			public static class Addsd
			{
				public static OpCode R_R = new OpCode(new byte[] { 0xF2, 0x0F, 0x58 });
				public static OpCode R_M = new OpCode(new byte[] { 0xF2, 0x0F, 0x58 });
				public static OpCode R_L = new OpCode(new byte[] { 0xF2, 0x0F, 0x58 });
			}
			public static class Addss
			{
				public static OpCode R_R = new OpCode(new byte[] { 0xF3, 0x0F, 0x58 });
				public static OpCode R_M = new OpCode(new byte[] { 0xF3, 0x0F, 0x58 });
				public static OpCode R_L = new OpCode(new byte[] { 0xF3, 0x0F, 0x58 });
			}
			public static class Subsd
			{
				public static OpCode R_R = new OpCode(new byte[] { 0xF2, 0x0F, 0x5C });
				public static OpCode R_M = new OpCode(new byte[] { 0xF2, 0x0F, 0x5C });
				public static OpCode R_L = new OpCode(new byte[] { 0xF2, 0x0F, 0x5C });
			}
			public static class Mulsd
			{
				public static OpCode R_R = new OpCode(new byte[] { 0xF2, 0x0F, 0x59 });
				public static OpCode R_M = new OpCode(new byte[] { 0xF2, 0x0F, 0x59 });
				public static OpCode R_L = new OpCode(new byte[] { 0xF2, 0x0F, 0x59 });
			}
			public static class Divsd
			{
				public static OpCode R_R = new OpCode(new byte[] { 0xF2, 0x0F, 0x5E });
				public static OpCode R_M = new OpCode(new byte[] { 0xF2, 0x0F, 0x5E });
			}
			public static class Cmpsd
			{
				public static OpCode R_R = new OpCode(new byte[] { 0xF2, 0x0F, 0xC2 });
				public static OpCode R_M = new OpCode(new byte[] { 0xF2, 0x0F, 0xC2 });
				public static OpCode R_L = new OpCode(new byte[] { 0xF2, 0x0F, 0xC2 });
				public static OpCode R_C = new OpCode(new byte[] { 0xF2, 0x0F, 0xC2 });
			}
			public static class Comisd
			{
				public static OpCode R_R = new OpCode(new byte[] { 0x66, 0x0F, 0x2F });
				public static OpCode R_M = new OpCode(new byte[] { 0x66, 0x0F, 0x2F });
				public static OpCode R_L = new OpCode(new byte[] { 0x66, 0x0F, 0x2F });
				public static OpCode R_C = new OpCode(new byte[] { 0x66, 0x0F, 0x2F });
			}
			public static class Comiss
			{
				public static OpCode R_R = new OpCode(new byte[] { 0x0F, 0x2F });
				public static OpCode R_M = new OpCode(new byte[] { 0x0F, 0x2F });
				public static OpCode R_L = new OpCode(new byte[] { 0x0F, 0x2F });
				public static OpCode R_C = new OpCode(new byte[] { 0x0F, 0x2F });
			}
			public static class Ucomisd
			{
				public static OpCode R_R = new OpCode(new byte[] { 0x66, 0x0F, 0x2E });
				public static OpCode R_M = new OpCode(new byte[] { 0x66, 0x0F, 0x2E });
				public static OpCode R_L = new OpCode(new byte[] { 0x66, 0x0F, 0x2E });
				public static OpCode R_C = new OpCode(new byte[] { 0x66, 0x0F, 0x2E });
			}
			public static class Ucomiss
			{
				public static OpCode R_R = new OpCode(new byte[] { 0x0F, 0x2E });
				public static OpCode R_M = new OpCode(new byte[] { 0x0F, 0x2E });
				public static OpCode R_L = new OpCode(new byte[] { 0x0F, 0x2E });
				public static OpCode R_C = new OpCode(new byte[] { 0x0F, 0x2E });
			}
			public static class Shrd
			{
				public static OpCode R_R_C = new OpCode(new byte[] { 0x0F, 0xAC }, 4);
				public static OpCode M_R_C = new OpCode(new byte[] { 0x0F, 0xAC }, 4);
				public static OpCode R_R_R = new OpCode(new byte[] { 0x0F, 0xAD }, 4);
				public static OpCode M_R_R = new OpCode(new byte[] { 0x0F, 0xAD }, 4);
			}
			public static class Shld
			{
				public static OpCode R_R_C = new OpCode(new byte[] { 0x0F, 0xA4 }, 4);
				public static OpCode M_R_C = new OpCode(new byte[] { 0x0F, 0xA4 }, 4);
				public static OpCode R_R_R = new OpCode(new byte[] { 0x0F, 0xA5 }, 4);
				public static OpCode M_R_R = new OpCode(new byte[] { 0x0F, 0xA5 }, 4);
			}
		};
#pragma warning restore 1591

		#endregion

		#region Add
		/// <summary>
		/// Add
		/// </summary>
		/// <param name="dest">The dest.</param>
		/// <param name="src">The SRC.</param>
		/// <returns></returns>
		public static OpCode Add(Operand dest, Operand src)
		{
			if ((dest is RegisterOperand) && (src is ConstantOperand))
				return X86Instruction.Add.R_C;

			if ((dest is RegisterOperand) && (src is RegisterOperand))
				return X86Instruction.Add.R_R;

			if ((dest is RegisterOperand) && (src is MemoryOperand))
				if (IsUByte(dest))
					return X86Instruction.Add.R_M_U8;
				else
					return X86Instruction.Add.R_M;

			if ((dest is MemoryOperand) && (src is RegisterOperand))
				if (IsUByte(dest))
					return X86Instruction.Add.M_R_U8;
				else
					return X86Instruction.Add.M_R;

			throw new ArgumentException(@"No opcode for operand type.");
		}

		#endregion

		#region And
		/// <summary>
		/// And
		/// </summary>
		/// <param name="dest">The dest.</param>
		/// <param name="src">The SRC.</param>
		/// <returns></returns>
		public static OpCode And(Operand dest, Operand src)
		{
			if ((dest is RegisterOperand) && (src is ConstantOperand))
				return X86Instruction.And.R_C;

			if ((dest is MemoryOperand) && (src is ConstantOperand))
				return X86Instruction.And.M_C;

			if ((dest is RegisterOperand) && (src is MemoryOperand))
				return X86Instruction.And.R_M;

			if ((dest is RegisterOperand) && (src is RegisterOperand))
				return X86Instruction.And.R_R;

			if ((dest is MemoryOperand) && (src is RegisterOperand))
				return X86Instruction.And.M_C;

			throw new ArgumentException(@"No opcode for operand type.");
		}

		#endregion

		#region Div
		/// <summary>
		/// Returns the matching OpCode for DIV
		/// </summary>
		/// <param name="dest">Destination operand</param>
		/// <param name="src">Source Operand</param>
		/// <returns>The matching OpCode</returns>
		public static OpCode Div(Operand dest, Operand src)
		{
			if (src is RegisterOperand)
				return X86Instruction.Div.R;

			if (src is MemoryOperand)
				return X86Instruction.Div.M;

			throw new ArgumentException(@"No opcode for operand type.");
		}

		#endregion

		#region Move
		/// <summary>
		/// Move
		/// </summary>
		/// <param name="dest">The dest.</param>
		/// <param name="src">The SRC.</param>
		/// <returns></returns>
		public static OpCode Move(Operand dest, Operand src)
		{
			if ((dest is RegisterOperand) && (src is ConstantOperand)) {
				if (IsChar(src))
					return X86Instruction.Mov.R_C_16;
				else
					return X86Instruction.Mov.R_C;
			}

			if ((dest is MemoryOperand) && (src is ConstantOperand)) {
				if (IsChar(src))
					return X86Instruction.Mov.M_C_16;
				else
					return X86Instruction.Mov.M_C;
			}

			if ((dest is RegisterOperand) && (src is RegisterOperand)) {
				if (IsChar(src))
					return X86Instruction.Mov.R_R_16;
				else
					return X86Instruction.Mov.R_R;
			}

			if ((dest is RegisterOperand) && (src is MemoryOperand)) {
				if (IsByte(dest))
					return X86Instruction.Mov.R_M_U8;
				else if (IsChar(dest))
					return X86Instruction.Mov.R_M_16;
				else
					return X86Instruction.Mov.R_M;
			}

			if ((dest is MemoryOperand) && (src is RegisterOperand)) {
				if (IsByte(dest))
					return X86Instruction.Mov.M_R_U8;
				else if (IsChar(dest))
					return X86Instruction.Mov.M_R_16;
				else
					return X86Instruction.Mov.M_R;
			}

			throw new ArgumentException(@"No opcode for operand type. [" + dest.GetType() + ", " + src.GetType() + ")");
		}

		#endregion

		#region Neg
		/// <summary>
		/// Negate
		/// </summary>
		/// <param name="dest">The dest.</param>
		/// <returns></returns>
		public static OpCode Neg(Operand dest)
		{
			if (dest is RegisterOperand)
				return X86Instruction.Neg.R;

			if (dest is MemoryOperand)
				return X86Instruction.Neg.M;

			throw new ArgumentException(@"No opcode for operand type.");
		}

		#endregion

		#region Or
		/// <summary>
		/// Or
		/// </summary>
		/// <param name="dest">The dest.</param>
		/// <param name="src">The SRC.</param>
		/// <returns></returns>
		public static OpCode Or(Operand dest, Operand src)
		{
			if ((dest is RegisterOperand) && (src is ConstantOperand))
				return X86Instruction.Or.R_C;

			if ((dest is RegisterOperand) && (src is MemoryOperand))
				return X86Instruction.Or.R_M;

			if ((dest is RegisterOperand) && (src is RegisterOperand))
				return X86Instruction.Or.R_R;

			if ((dest is MemoryOperand) && (src is RegisterOperand))
				return X86Instruction.Or.M_R;

			throw new ArgumentException(@"No opcode for operand type.");
		}

		#endregion

		#region Shl
		/// <summary>
		/// SHL
		/// </summary>
		/// <param name="dest">The dest.</param>
		/// <param name="src">The SRC.</param>
		/// <returns></returns>
		public static OpCode Shl(Operand dest, Operand src)
		{
			if ((dest is RegisterOperand) && (src is ConstantOperand))
				return X86Instruction.Shl.R_C;

			if ((dest is MemoryOperand) && (src is ConstantOperand))
				return X86Instruction.Shl.M_C;

			if (dest is RegisterOperand)
				return X86Instruction.Shl.R;

			if (dest is MemoryOperand)
				return X86Instruction.Shl.M;

			throw new ArgumentException(@"No opcode for operand type.");
		}

		#endregion

		#region Shr
		/// <summary>
		/// SHR
		/// </summary>
		/// <param name="dest">The dest.</param>
		/// <param name="src">The SRC.</param>
		/// <returns></returns>
		public static OpCode Shr(Operand dest, Operand src)
		{
			if ((dest is RegisterOperand) && (src is ConstantOperand))
				return X86Instruction.Shr.R_C;

			if ((dest is MemoryOperand) && (src is ConstantOperand))
				return X86Instruction.Shr.M_C;

			if (dest is RegisterOperand)
				return X86Instruction.Shr.R;

			if (dest is MemoryOperand)
				return X86Instruction.Shr.M;

			throw new ArgumentException(@"No opcode for operand type.");
		}

		#endregion

		#region Sub
		/// <summary>
		/// Sub
		/// </summary>
		/// <param name="dest">The dest.</param>
		/// <param name="src">The SRC.</param>
		/// <returns></returns>
		public static OpCode Sub(Operand dest, Operand src)
		{
			if ((dest is Operand) && (src is ConstantOperand))
				return X86Instruction.Sub.O_C;

			if ((dest is RegisterOperand) && (src is Operand)) {
				if (src.Type.Type == CilElementType.Char || dest.Type.Type == CilElementType.Char)
					return X86Instruction.Sub.R_O_16;
				else
					return X86Instruction.Sub.R_O;
			}

			if ((dest is MemoryOperand) && (src is RegisterOperand))
				return X86Instruction.Sub.M_R;

			throw new ArgumentException(@"No opcode for operand type.");
		}
		#endregion

		#region Xor
		/// <summary>
		/// Xor
		/// </summary>
		/// <param name="dest">The dest.</param>
		/// <param name="src">The SRC.</param>
		/// <returns></returns>
		public static OpCode Xor(Operand dest, Operand src)
		{
			if ((dest is RegisterOperand) && (src is ConstantOperand))
				return X86Instruction.Xor.R_C;

			if ((dest is RegisterOperand) && (src is MemoryOperand))
				return X86Instruction.Xor.R_M;

			if ((dest is RegisterOperand) && (src is RegisterOperand))
				return X86Instruction.Xor.R_R;

			if ((dest is MemoryOperand) && (src is RegisterOperand))
				return X86Instruction.Xor.M_R;

			throw new ArgumentException(@"No opcode for operand type.");
		}

		#endregion

		/// <summary>
		/// Adc
		/// </summary>
		/// <param name="dest">The dest.</param>
		/// <param name="src">The SRC.</param>
		/// <returns></returns>
		public static OpCode Adc(Operand dest, Operand src)
		{
			if ((dest is RegisterOperand) && (src is ConstantOperand)) return X86Instruction.Adc.R_C;
			if ((dest is RegisterOperand) && (src is RegisterOperand)) return X86Instruction.Adc.R_R;
			if ((dest is RegisterOperand) && (src is MemoryOperand)) return X86Instruction.Adc.R_M;
			if ((dest is MemoryOperand) && (src is RegisterOperand)) return X86Instruction.Adc.M_R;
			throw new ArgumentException(@"No opcode for operand type.");
		}

		/// <summary>
		/// Out8
		/// </summary>
		/// <param name="dest">The dest.</param>
		/// <param name="src">The SRC.</param>
		/// <returns></returns>
		public static OpCode Out8(Operand dest, Operand src)
		{
			if ((dest is ConstantOperand) && (src is RegisterOperand)) return X86Instruction.Out8.C_R;
			if ((dest is RegisterOperand) && (src is RegisterOperand)) return X86Instruction.Out8.R_R;
			throw new ArgumentException(@"No opcode for operand type.");
		}

		/// <summary>
		/// Out32
		/// </summary>
		/// <param name="dest">The dest.</param>
		/// <param name="src">The SRC.</param>
		/// <returns></returns>
		public static OpCode Out32(Operand dest, Operand src)
		{
			if ((dest is ConstantOperand) && (src is RegisterOperand)) return X86Instruction.Out32.C_R;
			if ((dest is RegisterOperand) && (src is RegisterOperand)) return X86Instruction.Out32.R_R;
			throw new ArgumentException(@"No opcode for operand type.");
		}

		/// <summary>
		/// XCHG
		/// </summary>
		/// <param name="dest">The dest.</param>
		/// <param name="src">The SRC.</param>
		/// <returns></returns>
		public static OpCode Xchg(Operand dest, Operand src)
		{
			if ((dest is RegisterOperand) && (src is MemoryOperand)) return X86Instruction.Xchg.R_M;
			if ((dest is RegisterOperand) && (src is RegisterOperand)) return X86Instruction.Xchg.R_R;
			if ((dest is MemoryOperand) && (src is RegisterOperand)) return X86Instruction.Xchg.M_R;
			throw new ArgumentException(@"No opcode for operand type.");
		}

		/// <summary>
		/// Xsave
		/// </summary>
		/// <param name="dest">The dest.</param>
		/// <returns></returns>
		public static OpCode Xsave(Operand dest)
		{
			if (dest is MemoryOperand) return X86Instruction.Xsave.M;
			throw new ArgumentException(@"No opcode for operand type.");
		}

		/// <summary>
		/// Dec
		/// </summary>
		/// <param name="dest">The dest.</param>
		/// <returns></returns>
		public static OpCode Dec(Operand dest)
		{
			if (dest is RegisterOperand) return X86Instruction.Dec.R;
			if (dest is MemoryOperand) return X86Instruction.Dec.M;
			throw new ArgumentException(@"No opcode for operand type.");
		}

		/// <summary>
		/// Inc
		/// </summary>
		/// <param name="dest">The dest.</param>
		/// <returns></returns>
		public static OpCode Inc(Operand dest)
		{
			if (dest is RegisterOperand) return X86Instruction.Inc.R;
			if (dest is MemoryOperand) return X86Instruction.Inc.M;
			throw new ArgumentException(@"No opcode for operand type.");
		}

		/// <summary>
		/// Not
		/// </summary>
		/// <param name="dest">The dest.</param>
		/// <returns></returns>
		public static OpCode Not(Operand dest)
		{
			if ((dest is RegisterOperand) || (dest is MemoryOperand))
				if (IsByte(dest))
					return X86Instruction.Not.MR_8;
				else if (IsChar(dest))
					return X86Instruction.Not.MR_16;
				else
					return X86Instruction.Not.MR;

			throw new ArgumentException(@"No opcode for operand type.");
		}

		/// <summary>
		/// CMP
		/// </summary>
		/// <param name="dest">The dest.</param>
		/// <param name="src">The SRC.</param>
		/// <returns></returns>
		public static OpCode Cmp(Operand dest, Operand src)
		{
			if ((dest is MemoryOperand) && (src is RegisterOperand))
				if (IsByte(dest))
					return X86Instruction.Cmp.M_R_8;
				else
					if (IsChar(dest))
						return X86Instruction.Cmp.M_R_16;
					else
						return X86Instruction.Cmp.M_R;

			if ((dest is RegisterOperand) && (src is MemoryOperand))
				if (IsByte(src))
					return X86Instruction.Cmp.R_M_8;
				else
					if (IsChar(src))
						return X86Instruction.Cmp.R_M_16;
					else
						return X86Instruction.Cmp.R_M;

			if ((dest is RegisterOperand) && (src is RegisterOperand)) return X86Instruction.Cmp.R_R;
			if ((dest is MemoryOperand) && (src is ConstantOperand)) return X86Instruction.Cmp.M_C;
			if ((dest is RegisterOperand) && (src is ConstantOperand)) return X86Instruction.Cmp.R_C;
			throw new ArgumentException(@"No opcode for operand type.");
		}

		/// <summary>
		/// CMPXCHG
		/// </summary>
		/// <param name="dest">The dest.</param>
		/// <param name="src">The SRC.</param>
		/// <returns></returns>
		public static OpCode Cmpxchg(Operand dest, Operand src)
		{
			if ((dest is RegisterOperand) && (src is RegisterOperand)) return X86Instruction.Cmpxchg.R_R;
{'fraction_non_alphanumeric': 0.13207747038364437, 'fraction_numerical': 0.03730513232464116, 'mean_word_length': 2.9353852567220176, 'pattern_counts': {'":': 0, '<': 317, '<?xml version=': 0, '>': 317, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5183997', 'n_tokens_mistral': 24286, 'n_tokens_neox': 20199, 'n_words': 6233}