Beispiel #1
0
        /// <summary>
        /// Computes the opcode.
        /// </summary>
        /// <param name="destination">The destination operand.</param>
        /// <param name="source">The source operand.</param>
        /// <param name="third">The third operand.</param>
        /// <returns></returns>
        protected override OpCode ComputeOpCode(Operand destination, Operand source, Operand third)
        {
            if (source.IsMemoryAddress && third.IsRegister)
            {
                if (source.IsByte || third.IsByte)
                    return M_R_8;
                if (source.IsChar || third.IsChar)
                    return M_R_16;
                if (source.IsShort || third.IsShort)
                    return M_R_16;
                return M_R;
            }

            if (source.IsRegister && third.IsRegister) return R_R;

            if (source.IsMemoryAddress && third.IsConstant) return M_C;

            if (source.IsRegister && third.IsConstant)
            {
                if (third.IsByte || source.IsByte)
                    return R_C_8;
                if (third.IsChar || source.IsChar)
                    return R_C_16;
                if (third.IsShort || source.IsShort)
                    return R_C_16;
                return R_C;
            }

            throw new ArgumentException(String.Format(@"x86.Test: No opcode for operand types {0} and {1}.", source, third));
        }
Beispiel #2
0
        /// <summary>
        /// Computes the opcode.
        /// </summary>
        /// <param name="size">The size.</param>
        /// <param name="destination">The destination operand.</param>
        /// <param name="source">The source operand.</param>
        /// <returns></returns>
        /// <exception cref="NotImplementCompilerException"></exception>
        private OpCode ComputeOpCode(InstructionSize size, Operand destination, Operand source)
        {
            Debug.Assert(destination.IsConstant || destination.IsCPURegister);
            Debug.Assert(size != InstructionSize.None);
            Debug.Assert(size != InstructionSize.Native);

            //size = BaseMethodCompilerStage.GetInstructionSize(size, destination);

            if (destination.IsCPURegister)
            {
                if (size == InstructionSize.Size8)
                    return R_8;

                if (size == InstructionSize.Size16)
                    return R_16;

                return R_32;
            }

            if (destination.IsConstant)
            {
                if (size == InstructionSize.Size8)
                    return C_8;

                if (size == InstructionSize.Size16)
                    return C_16;

                return C_32;
            }

            throw new NotImplementCompilerException();
        }
Beispiel #3
0
 /// <summary>
 /// Computes the opcode.
 /// </summary>
 /// <param name="destination">The destination operand.</param>
 /// <param name="source">The source operand.</param>
 /// <param name="third">The third operand.</param>
 /// <returns></returns>
 protected override OpCode ComputeOpCode(Operand destination, Operand source, Operand third)
 {
     if ((source.IsRegister) && (third.IsRegister)) return opcode;
     if ((source.IsRegister) && (third.IsMemoryAddress)) return opcode;
     if ((source.IsRegister) && (third.IsConstant)) return opcode;
     throw new ArgumentException(@"No opcode for operand type.");
 }
Beispiel #4
0
        /// <summary>
        /// Computes the opcode.
        /// </summary>
        /// <param name="destination">The destination operand.</param>
        /// <param name="source">The source operand.</param>
        /// <param name="third">The third operand.</param>
        /// <returns></returns>
        protected override OpCode ComputeOpCode(Operand destination, Operand source, Operand third)
        {
            if (!(destination.IsRegister))
                throw new ArgumentException(@"Destination must be RegisterOperand.", @"destination");
            if (source.IsConstant)
                throw new ArgumentException(@"Source must not be ConstantOperand.", @"source");

            switch (source.Type.Type)
            {
                case CilElementType.Boolean: goto case CilElementType.I1;
                case CilElementType.U1: goto case CilElementType.I1;
                case CilElementType.I1:
                    {
                        if ((destination.IsRegister) && (source.IsRegister)) return R_X8;
                        if ((destination.IsRegister) && (source.IsMemoryAddress)) return R_X8;
                    }
                    break;

                case CilElementType.Char: goto case CilElementType.U2;
                case CilElementType.U2: goto case CilElementType.I2;
                case CilElementType.I2:
                    if ((destination.IsRegister) && (source.IsRegister)) return R_X16;
                    if ((destination.IsRegister) && (source.IsMemoryAddress)) return R_X16;
                    break;

                default:
                    break;
            }

            throw new ArgumentException(@"No opcode for operand type. [" + destination.GetType() + ", " + source.GetType() + ")");
        }
        /// <summary>
        /// This function emits a constant variable into the read-only data section.
        /// </summary>
        /// <param name="op">The operand to emit as a constant.</param>
        /// <returns>An operand, which represents the reference to the read-only constant.</returns>
        /// <remarks>
        /// This function checks if the given operand needs to be moved into the read-only data
        /// section of the executable. For x86 this concerns only floating point operands, as these
        /// can't be specified in inline assembly.<para/>
        /// This function checks if the given operand needs to be moved and rewires the operand, if
        /// it must be moved.
        /// </remarks>
        protected Operand EmitConstant(Operand cop)
        {
            if (!cop.IsConstant)
                return cop;

            if (!(cop.StackType == StackTypeCode.F || cop.StackType == StackTypeCode.Int64))
                return cop;

            int size, alignment;
            architecture.GetTypeRequirements(cop.Type, out size, out alignment);

            string name = String.Format("C_{0}", Guid.NewGuid());
            using (Stream stream = methodCompiler.Linker.Allocate(name, SectionKind.ROData, size, alignment))
            {
                using (BinaryWriter writer = new BinaryWriter(stream))
                {
                    switch (cop.Type.Type)
                    {
                        case CilElementType.R4: writer.Write((float)cop.Value); break;
                        case CilElementType.R8: writer.Write((double)cop.Value); break;
                        case CilElementType.I8: writer.Write((long)cop.Value); break;
                        case CilElementType.U8: writer.Write((ulong)cop.Value); break;
                        default: throw new NotSupportedException();
                    }
                }
            }
            // FIXME: Attach the label operand to the linker symbol
            // FIXME: Rename the operand to SymbolOperand
            // FIXME: Use the provided name to link
            return Operand.CreateLabel(cop.Type, name);
        }
        /// <summary>
        /// Emits the given code.
        /// </summary>
        /// <param name="opCode">The op code.</param>
        /// <param name="dest">The destination operand.</param>
        /// <param name="src">The source operand.</param>
        public void Emit(OpCode opCode, Operand dest, Operand src)
        {
            // Write the opcode
            codeStream.Write(opCode.Code, 0, opCode.Code.Length);

            if (dest == null && src == null)
                return;

            byte? sib = null, modRM = null;
            Operand displacement = null;

            // Write the mod R/M byte
            modRM = CalculateModRM(opCode.RegField, dest, src, out sib, out displacement);
            if (modRM != null)
            {
                codeStream.WriteByte(modRM.Value);
                if (sib.HasValue)
                    codeStream.WriteByte(sib.Value);
            }

            // Add displacement to the code
            if (displacement != null)
                WriteDisplacement(displacement);

            // Add immediate bytes
            if (dest.IsConstant)
                WriteImmediate(dest);
            else if (dest.IsSymbol)
                WriteDisplacement(dest);
            else if (src != null && src.IsConstant)
                WriteImmediate(src);
            else if (src != null && src.IsSymbol)
                WriteDisplacement(src);
        }
Beispiel #7
0
        /// <summary>
        /// Computes the opcode.
        /// </summary>
        /// <param name="destination">The destination operand.</param>
        /// <param name="source">The source operand.</param>
        /// <param name="third">The third operand.</param>
        /// <returns></returns>
        protected override OpCode ComputeOpCode(Operand destination, Operand source, Operand third)
        {
            if (destination.IsCPURegister && third.IsConstant) return R_C;
            if (destination.IsCPURegister && third.IsCPURegister) return R_R;

            throw new ArgumentException(@"No opcode for operand type.");
        }
Beispiel #8
0
        /// <summary>
        /// Computes the opcode.
        /// </summary>
        /// <param name="destination">The destination operand.</param>
        /// <param name="source">The source operand.</param>
        /// <param name="third">The third operand.</param>
        /// <returns></returns>
        protected override OpCode ComputeOpCode(Operand destination, Operand source, Operand third)
        {
            if (destination.IsRegister) return R_RM;
            if (destination.IsMemoryAddress) return RM_R;

            throw new ArgumentException(@"No opcode for operand type. [" + destination.GetType() + ", " + source.GetType() + ")");
        }
Beispiel #9
0
 /// <summary>
 /// Computes the opcode.
 /// </summary>
 /// <param name="destination">The destination operand.</param>
 /// <param name="source">The source operand.</param>
 /// <param name="third">The third operand.</param>
 /// <returns></returns>
 protected override OpCode ComputeOpCode(Operand destination, Operand source, Operand third)
 {
     if (third.IsConstant)
         return RM_C;
     else
         return RM_R;
 }
Beispiel #10
0
        /// <summary>
        /// Computes the opcode.
        /// </summary>
        /// <param name="destination">The destination operand.</param>
        /// <param name="source">The source operand.</param>
        /// <param name="third">The third operand.</param>
        /// <returns></returns>
        protected override OpCode ComputeOpCode(Operand destination, Operand source, Operand third)
        {
            if (destination.Register is ControlRegister) return CR_R;
            if (source.Register is ControlRegister) return R_CR;

            throw new ArgumentException(@"No opcode for operand type. [" + destination + ", " + source + ")");
        }
Beispiel #11
0
        /// <summary>
        /// Computes the opcode.
        /// </summary>
        /// <param name="destination">The destination operand.</param>
        /// <param name="source">The source operand.</param>
        /// <param name="third">The third operand.</param>
        /// <returns></returns>
        protected override OpCode ComputeOpCode(Operand destination, Operand source, Operand third)
        {
            //if (source.Type.Type == CilElementType.R4) return DIVSS;
            return opcode;

            //return DIVSD;
        }
 public static X86Instruction GetMove(Operand Destination, Operand Source)
 {
     if (Source.IsR8 && Destination.IsR8)
     {
         return X86.Movsd;
     }
     else if (Source.IsR4 && Destination.IsR4)
     {
         return X86.Movss;
     }
     else if (Source.IsR4 && Destination.IsR8)
     {
         return X86.Cvtss2sd;
     }
     else if (Source.IsR8 && Destination.IsR4)
     {
         return X86.Cvtsd2ss;
     }
     else if (Source.IsR8 && Destination.IsMemoryAddress)
     {
         return X86.Movsd;
     }
     else if (Source.IsR4 && Destination.IsMemoryAddress)
     {
         return X86.Movss;
     }
     else
     {
         return X86.Mov;
     }
 }
        /// <summary>
        /// Initializes a new instance of the <see cref="BaseMethodCompiler" /> class.
        /// </summary>
        /// <param name="compiler">The assembly compiler.</param>
        /// <param name="method">The method to compile by this instance.</param>
        /// <param name="basicBlocks">The basic blocks.</param>
        /// <param name="threadID">The thread identifier.</param>
        protected BaseMethodCompiler(BaseCompiler compiler, MosaMethod method, BasicBlocks basicBlocks, int threadID)
        {
            Compiler = compiler;
            Method = method;
            Type = method.DeclaringType;
            Scheduler = compiler.CompilationScheduler;
            Architecture = compiler.Architecture;
            TypeSystem = compiler.TypeSystem;
            TypeLayout = compiler.TypeLayout;
            Trace = compiler.CompilerTrace;
            Linker = compiler.Linker;
            BasicBlocks = basicBlocks ?? new BasicBlocks();
            Pipeline = new CompilerPipeline();
            LocalStack = new List<Operand>();

            ConstantZero = Operand.CreateConstant(TypeSystem, 0);
            StackFrame = Operand.CreateCPURegister(TypeSystem.BuiltIn.Pointer, Architecture.StackFrameRegister);

            Parameters = new Operand[method.Signature.Parameters.Count + (method.HasThis || method.HasExplicitThis ? 1 : 0)];
            VirtualRegisters = new VirtualRegisters(Architecture);
            LocalVariables = emptyOperandList;
            ThreadID = threadID;
            DominanceAnalysis = new Dominance(Compiler.CompilerOptions.DominanceAnalysisFactory, BasicBlocks);
            PluggedMethod = compiler.PlugSystem.GetPlugMethod(Method);
            stop = false;

            MethodData = compiler.CompilerData.GetCompilerMethodData(Method);
            MethodData.Counters.Clear();

            EvaluateParameterOperands();
        }
Beispiel #14
0
        public void Emit(OpcodeEncoder opcode, Operand symbolOperand, int symbolOffset)
        {
            int pos = (int)codeStream.Position + symbolOffset;

            Emit(opcode);

            if (symbolOperand.IsLabel)
            {
                linker.Link(LinkType.AbsoluteAddress, PatchType.I4, MethodName, SectionKind.Text, pos, 0, symbolOperand.Name, SectionKind.ROData, 0);
            }
            else if (symbolOperand.IsField)
            {
                var section = symbolOperand.Field.Data != null ? SectionKind.ROData : SectionKind.BSS;

                linker.Link(LinkType.AbsoluteAddress, PatchType.I4, MethodName, SectionKind.Text, pos, 0, symbolOperand.Field.FullName, section, (int)symbolOperand.Displacement);
            }
            else if (symbolOperand.IsSymbol)
            {
                var section = symbolOperand.Method != null ? SectionKind.Text : SectionKind.ROData;

                var symbol = linker.GetSymbol(symbolOperand.Name, section);

                if (symbol == null)
                {
                    symbol = linker.FindSymbol(symbolOperand.Name);
                }

                linker.Link(LinkType.AbsoluteAddress, PatchType.I4, MethodName, SectionKind.Text, pos, 0, symbol, 0);
            }
        }
Beispiel #15
0
        /// <summary>
        /// Computes the opcode.
        /// </summary>
        /// <param name="size">The size.</param>
        /// <param name="destination">The destination operand.</param>
        /// <param name="source">The source operand.</param>
        /// <returns></returns>
        /// <exception cref="System.ArgumentException">@No opcode for operand type. [ + destination + ,  + source + )</exception>
        private OpCode ComputeOpCode(InstructionSize size, Operand destination, Operand source)
        {
            Debug.Assert(destination.IsMemoryAddress);
            Debug.Assert(source.IsRegister || source.IsConstant || source.IsSymbol);

            size = BaseMethodCompilerStage.GetInstructionSize(size, destination);

            if (source.IsSymbol)
                return RM_C;

            if (source.IsConstant)
            {
                if (size == InstructionSize.Size8)
                    return RM_C_U8;

                if (size == InstructionSize.Size16)
                    return M_C_16;

                return RM_C;
            }

            if (source.IsRegister)
            {
                if (size == InstructionSize.Size8)
                    return RM_R_U8;

                if (size == InstructionSize.Size16)
                    return M_R_16;

                return M_R;
            }

            throw new ArgumentException(@"No opcode for operand type. [" + destination + ", " + source + ")");
        }
        /// <summary>
        /// Emits the given code.
        /// </summary>
        /// <param name="opCode">The op code.</param>
        /// <param name="dest">The destination operand.</param>
        /// <param name="src">The source operand.</param>
        public void Emit(OpCode opCode, Operand dest, Operand src)
        {
            // Write the opcode
            codeStream.Write(opCode.Code, 0, opCode.Code.Length);

            Debug.Assert(!(dest == null && src == null));

            byte? modRM = null;

            // Write the mod R/M byte
            modRM = CalculateModRM(opCode.RegField, dest, src);
            if (modRM != null)
            {
                codeStream.WriteByte(modRM.Value);
            }

            // Add immediate bytes
            if (dest.IsConstant)
                WriteImmediate(dest);
            else if (dest.IsSymbol)
                WriteDisplacement(dest);
            else if (src != null && src.IsResolvedConstant)
                WriteImmediate(src);
            else if (src != null && (src.IsSymbol || src.IsStaticField))
                WriteDisplacement(src);
        }
Beispiel #17
0
        /// <summary>
        /// Computes the opcode.
        /// </summary>
        /// <param name="destination">The destination operand.</param>
        /// <param name="source">The source operand.</param>
        /// <param name="third">The third operand.</param>
        /// <returns></returns>
        protected override OpCode ComputeOpCode(Operand destination, Operand source, Operand third)
        {
            if (IsByte(destination)) return DEC8;
            if (IsShort(destination) || IsChar(destination)) return DEC16;
            if (IsInt(destination)) return DEC32;

            throw new ArgumentException(@"No opcode for operand type.");
        }
Beispiel #18
0
        /// <summary>
        /// Computes the opcode.
        /// </summary>
        /// <param name="destination">The destination operand.</param>
        /// <param name="source">The source operand.</param>
        /// <param name="third">The third operand.</param>
        /// <returns></returns>
        protected override OpCode ComputeOpCode(Operand destination, Operand source, Operand third)
        {
            if (destination.IsByte) return INC8;
            if (destination.IsShort || destination.IsChar) return INC16;
            if (destination.IsInt) return INC32;

            throw new ArgumentException(@"No opcode for operand type.");
        }
Beispiel #19
0
        /// <summary>
        /// Computes the opcode.
        /// </summary>
        /// <param name="destination">The destination operand.</param>
        /// <param name="source">The source operand.</param>
        /// <param name="third">The third operand.</param>
        /// <returns></returns>
        protected override OpCode ComputeOpCode(Operand destination, Operand source, Operand third)
        {
            if (destination.IsShort && source.IsShort && destination.IsRegister && source.IsRegister) return R_R_16;
            if (destination.IsRegister && source.IsMemoryAddress) return R_M;
            if (destination.IsRegister && source.IsRegister) return R_R;
            if (destination.IsMemoryAddress && source.IsRegister) return M_R;

            throw new ArgumentException(@"No opcode for operand type.");
        }
Beispiel #20
0
        /// <summary>
        /// Computes the opcode.
        /// </summary>
        /// <param name="destination">The destination operand.</param>
        /// <param name="source">The source operand.</param>
        /// <param name="third">The third operand.</param>
        /// <returns></returns>
        protected override OpCode ComputeOpCode(Operand destination, Operand source, Operand third)
        {
            if (destination.IsRegister && destination.Register is SegmentRegister) return SR_R;

            if (source.IsRegister && source.Register is SegmentRegister)
                throw new ArgumentException(@"TODO: No opcode for move sourcee segment register");

            if (destination.IsRegister && source.IsConstant) return RM_C;

            if (destination.IsMemoryAddress && source.IsConstant)
            {
                if (destination.IsByte || destination.IsBoolean) return RM_C_U8;
                if (destination.IsChar || destination.IsShort) return M_C_16;
                return RM_C;
            }

            if (destination.IsRegister && source.IsSymbol) return RM_C;

            if (destination.IsMemoryAddress && source.IsSymbol) return RM_C;

            if (destination.IsRegister && source.IsRegister)
            {
                Debug.Assert(!((source.IsByte || destination.IsByte) && (source.Register == GeneralPurposeRegister.ESI || source.Register == GeneralPurposeRegister.EDI)), source.ToString());

                if (source.IsByte || destination.IsByte) return R_M_U8;
                if (source.IsChar || destination.IsChar || source.IsShort || destination.IsShort) return R_RM_16;
                return R_RM;
            }

            if (destination.IsRegister && source.IsMemoryAddress)
            {
                if (destination.IsByte) return R_M_U8;
                if (destination.IsChar || destination.IsShort) return R_RM_16;
                return R_RM;
            }

            if (destination.IsMemoryAddress && source.IsRegister)
            {
                if (destination.IsPointer && !source.IsPointer && destination.Type.ElementType != null)
                {
                    if (destination.Type.ElementType.IsUI1 || destination.Type.ElementType.IsBoolean) return RM_R_U8;
                    if (destination.Type.ElementType.IsChar || destination.Type.ElementType.IsUI2) return M_R_16;
                }
                if (destination.IsByte) return RM_R_U8;
                if (destination.IsChar || destination.IsShort) return M_R_16;
                return M_R;
            }

            if (destination.IsSymbol && source.IsRegister)
            {
                if (destination.IsByte || destination.IsBoolean) return RM_C_U8;
                if (destination.IsChar || destination.IsShort) return M_C_16;
                return RM_C;
            }

            throw new ArgumentException(@"No opcode for operand type. [" + destination + ", " + source + ")");
        }
Beispiel #21
0
        /// <summary>
        /// Computes the opcode.
        /// </summary>
        /// <param name="destination">The destination operand.</param>
        /// <param name="source">The source operand.</param>
        /// <param name="third">The third operand.</param>
        /// <returns></returns>
        protected override OpCode ComputeOpCode(Operand destination, Operand source, Operand third)
        {
            Debug.Assert(source.IsMemoryAddress);

            if (source.IsR4)
                return m32fp;
            else
                return m64fp;
        }
        public override void GetStackRequirements(MosaTypeLayout typeLayout, Operand stackOperand, out int size, out int alignment)
        {
            // Special treatment for some stack types
            // FIXME: Handle the size and alignment requirements of value types
            architecture.GetTypeRequirements(typeLayout, stackOperand.Type, out size, out alignment);

            if (size < alignment)
                size = alignment;
        }
        public static OpcodeEncoder AppendConditionalDisplacement(this OpcodeEncoder encoder, Operand displacement, bool include)
        {
            if (!include)
                return encoder;

            if (Is8BitDisplacement(displacement))
                return encoder.AppendByteValue((byte)displacement.ConstantUnsignedInteger);

            return encoder.AppendIntegerValue(displacement.ConstantUnsignedInteger);
        }
        protected override void Setup()
        {
            base.Setup();

            ConstantZero = Operand.CreateConstant(MethodCompiler.TypeSystem, 0);

            visitationDictionary = new Dictionary<BaseInstruction, VisitationDelegate>();

            PopulateVisitationDictionary();
        }
        public static OpcodeEncoder AppendInteger(this OpcodeEncoder encoder, Operand operand, InstructionSize size)
        {
            if (size == InstructionSize.Size32)
                return encoder.AppendIntegerValue(operand.ConstantUnsignedInteger);
            if (size == InstructionSize.Size8)
                return encoder.AppendByteValue((byte)operand.ConstantUnsignedInteger);
            if (size == InstructionSize.Size16)
                return encoder.AppendShortValue((ushort)operand.ConstantUnsignedInteger);

            throw new InvalidCompilerException("Instruction size invalid");
        }
Beispiel #26
0
        /// <summary>
        /// Computes the opcode.
        /// </summary>
        /// <param name="destination">The destination operand.</param>
        /// <param name="source">The source operand.</param>
        /// <param name="third">The third operand.</param>
        /// <returns></returns>
        protected override OpCode ComputeOpCode(Operand destination, Operand source, Operand third)
        {
            if ((destination.IsRegister) || (destination.IsMemoryAddress))
            {
                if (IsByte(destination)) return MR_8;
                if (IsChar(destination)) return MR_16;
                return MR;
            }

            throw new ArgumentException(@"No opcode for operand type.");
        }
Beispiel #27
0
        /// <summary>
        /// Computes the opcode.
        /// </summary>
        /// <param name="destination">The destination operand.</param>
        /// <param name="source">The source operand.</param>
        /// <param name="third">The third operand.</param>
        /// <returns></returns>
        protected override OpCode ComputeOpCode(Operand destination, Operand source, Operand third)
        {
            if (destination.IsCPURegister)
            {
                if (destination.IsByte) return MR_8;
                if (destination.IsChar) return MR_16;
                return MR;
            }

            throw new ArgumentException(@"No opcode for operand type.");
        }
        /// <summary>
        /// Calls the specified target.
        /// </summary>
        /// <param name="symbolOperand">The symbol operand.</param>
        public void Call(Operand symbolOperand)
        {
            linker.Link(
                LinkType.RelativeOffset | LinkType.NativeI4,
                compiler.Method.ToString(),
                (int)(codeStream.Position - codeStreamBasePosition),
                (int)(codeStream.Position - codeStreamBasePosition) + 4,
                symbolOperand.Name,
                IntPtr.Zero
            );

            codeStream.Position += 4;
        }
Beispiel #29
0
        /// <summary>
        /// Computes the opcode.
        /// </summary>
        /// <param name="destination">The destination operand.</param>
        /// <param name="source">The source operand.</param>
        /// <param name="third">The third operand.</param>
        /// <returns></returns>
        protected override OpCode ComputeOpCode(Operand destination, Operand source, Operand third)
        {
            if (third.IsConstant)
                return O_C;

            if (destination.IsRegister)
            {
                if (third.IsChar)
                    return R_O_16;
                else
                    return R_O;
            }
            if ((destination.IsMemoryAddress) && (third.IsRegister)) return M_R;

            throw new ArgumentException(@"No opcode for operand type.");
        }
Beispiel #30
0
        /// <summary>
        /// Computes the opcode.
        /// </summary>
        /// <param name="destination">The destination operand.</param>
        /// <param name="source">The source operand.</param>
        /// <param name="third">The third operand.</param>
        /// <returns></returns>
        protected override OpCode ComputeOpCode(Operand destination, Operand source, Operand third)
        {
            if (destination.IsRegister)
            {
                if (source.IsMemoryAddress) return R_M;
                if (source.IsRegister) return R_R;
                if (source.IsConstant) return R_C;
            }
            else if (destination.IsMemoryAddress)
            {
                if (source.IsRegister) return M_R;
                if (source.IsConstant) return M_C;
            }

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