Пример #1
0
        public static Program BuildIR(this MethodInfo method)
        {
            IList <SpecialRegister>             srpool = SpecialRegister.CreatePool();
            Dictionary <MethodInfo, Subprogram> spmap  = new Dictionary <MethodInfo, Subprogram>();

            return(new Program(new Kernel[] { method.BuildIR(srpool, spmap, true) as Kernel }, srpool));
        }
Пример #2
0
        public void BlockMutation()
        {
            AssemblyName    assemblyName    = new AssemblyName("UniGPUTestFixture");
            AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.RunAndSave);
            ModuleBuilder   moduleBuilder   = assemblyBuilder.DefineDynamicModule(assemblyName.Name, assemblyName.Name + ".dll");
            TypeBuilder     typeBuilder     = moduleBuilder.DefineType("CILBBTypeMutation", TypeAttributes.Public);
            MethodBuilder   methodBuilder   = typeBuilder.DefineMethod("TestCase", MethodAttributes.Public | MethodAttributes.Static,
                                                                       typeof(void), new Type[] { typeof(int), typeof(int[]) });

            methodBuilder.DefineParameter(1, ParameterAttributes.None, "arg");
            methodBuilder.DefineParameter(2, ParameterAttributes.None, "addr");

            ILGenerator il = methodBuilder.GetILGenerator();

            LocalBuilder lb = il.DeclareLocal(typeof(float));

            Label ZERO             = il.DefineLabel();
            Label LOOP             = il.DefineLabel();
            Label LOOP_FLT_MUTATOR = il.DefineLabel();
            Label LOOP_INT_MUTATOR = il.DefineLabel();

            il.Emit(OpCodes.Ldarg_1);
            il.Emit(OpCodes.Ldc_I4_0);

            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Brfalse, ZERO);

            il.MarkLabel(LOOP);
            il.Emit(OpCodes.Conv_I2);
            il.Emit(OpCodes.Starg, 0);
            il.Emit(OpCodes.Ldarga, 0);
            il.Emit(OpCodes.Dup);
            il.Emit(OpCodes.Ldind_I4);
            il.Emit(OpCodes.Dup);
            il.Emit(OpCodes.Ldc_I4_2);
            il.Emit(OpCodes.Rem);
            il.Emit(OpCodes.Not);
            il.Emit(OpCodes.Ldc_I4_1);
            il.Emit(OpCodes.And);
            il.Emit(OpCodes.Brtrue, LOOP_FLT_MUTATOR);

            il.MarkLabel(LOOP_INT_MUTATOR);
            il.Emit(OpCodes.Conv_I4);
            il.Emit(OpCodes.Starg, 0);
            il.Emit(OpCodes.Ldind_I4);
            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Add);
            il.Emit(OpCodes.Ldc_I4_2);
            il.Emit(OpCodes.Div);
            il.Emit(OpCodes.Ldc_I4_M1);
            il.Emit(OpCodes.Neg);
            il.Emit(OpCodes.Sub);
            il.Emit(OpCodes.Dup);
            il.Emit(OpCodes.Ldc_I4_1);
            il.Emit(OpCodes.Bge, LOOP);

            il.Emit(OpCodes.Br, ZERO);

            il.MarkLabel(LOOP_FLT_MUTATOR);
            il.Emit(OpCodes.Conv_R4);
            il.Emit(OpCodes.Stloc_0);
            il.Emit(OpCodes.Pop);
            il.Emit(OpCodes.Ldloc_0);
            il.Emit(OpCodes.Ldc_R4, 1.0f);
            il.Emit(OpCodes.Sub);
            il.Emit(OpCodes.Dup);
            il.Emit(OpCodes.Ldc_R4, 1.0f);
            il.Emit(OpCodes.Bge, LOOP);

            il.Emit(OpCodes.Conv_I4);

            il.MarkLabel(ZERO);
            il.Emit(OpCodes.Ldc_I4_1);
            il.Emit(OpCodes.Add);
            il.Emit(OpCodes.Stelem_I4);
            il.Emit(OpCodes.Ret);

            MethodInfo method = typeBuilder.CreateType().GetMethod(methodBuilder.Name);

            int[] res = { 0 };

            method.Invoke(null, new object[] { 8, res });

            //Assert.AreEqual(1, res[0]);

            Cl.Program program = method.BuildIR().ToGPUClProgram(device, context);
            clSafeCall(Cl.BuildProgram(program, 1, new[] { device }, string.Empty, null, IntPtr.Zero));
            Assert.AreEqual(Cl.BuildStatus.Success, Cl.GetProgramBuildInfo(program, device, Cl.ProgramBuildInfo.Status, out error).
                            CastTo <Cl.BuildStatus>());

            Cl.Kernel kernel = Cl.CreateKernel(program, "TestCase", out error);
            clSafeCall(error);

            Cl.Mem cl_res = Cl.CreateBuffer(context, Cl.MemFlags.WriteOnly, (IntPtr)sizeof(int), IntPtr.Zero, out error);
            clSafeCall(error);

            Cl.CommandQueue cmdQueue = Cl.CreateCommandQueue(context, device, (Cl.CommandQueueProperties) 0, out error);
            clSafeCall(error);

            clSafeCall(Cl.SetKernelArg(kernel, 0, 8));
            clSafeCall(Cl.SetKernelArg(kernel, 1, cl_res));

            clSafeCall(Cl.EnqueueNDRangeKernel(cmdQueue, kernel, 1, null, new[] { (IntPtr)1 }, null, 0, null, out clevent));

            clSafeCall(Cl.EnqueueReadBuffer(cmdQueue, cl_res, Cl.Bool.True, IntPtr.Zero, (IntPtr)sizeof(int), res, 0, null, out clevent));

            clSafeCall(Cl.Finish(cmdQueue));

            clSafeCall(Cl.ReleaseMemObject(cl_res));

            program.Dispose();

            Assert.AreEqual(1, res[0]);
        }
Пример #3
0
        public InstructionSelector(IList <Instruction> cilbbcode,
                                   Stack <Tuple <Tuple <GenericOperand, bool>, InstructionSelector> > stack,
                                   IList <FormalParameter> parameters,
                                   IList <VirtualRegister> variables,
                                   bool result,
                                   IList <SpecialRegister> srpool,
                                   IDictionary <MethodInfo, Subprogram> spmap,
                                   Func <Type, StateSpaces, DynamicRegister> regalloc)
        {
            this.stack    = stack;
            this.regalloc = regalloc;

            bool skipnext = false;

            foreach (Instruction cilinstr in cilbbcode)
            {
                if (skipnext)
                {
                    skipnext = false;
                    continue;
                }

                if (Trailer != null)
                {
                    throw new ArgumentException("No instruction is permitted after trailing control flow one", "cilbbcode");
                }

                GenericOperand  left     = null;
                GenericOperand  right    = null;
                GenericOperand  extra    = null;
                VirtualRegister regleft  = null;
                VirtualRegister regright = null;
                VirtualRegister target   = null;
                FormalParameter arg      = null;
                VirtualRegister loc      = null;

                CILOpCodes cilopcode = (CILOpCodes)cilinstr.OpCode.Value;

                bool isArithmetic = cilopcode >= CILOpCodes.Add && cilopcode <= CILOpCodes.Xor;
                bool isCompare    = cilopcode >= CILOpCodes.Ceq && cilopcode <= CILOpCodes.Clt_Un;
                bool isCompBranch = cilopcode >= CILOpCodes.Beq_S && cilopcode <= CILOpCodes.Blt_Un_S ||
                                    cilopcode >= CILOpCodes.Beq && cilopcode <= CILOpCodes.Blt_Un;

                if (isArithmetic || isCompare || isCompBranch)
                {
                    right = RetrieveOperand();
                    left  = RetrieveOperand();
                    if (cilopcode == CILOpCodes.Mul &&
                        cilinstr.Next != null &&
                        (CILOpCodes)cilinstr.Next.OpCode.Value == CILOpCodes.Add)
                    {
                        extra = RetrieveOperand();
                    }
                    Type targetType = ArithmeticMapping[left.DataType][right.DataType];

                    right = ConvertOperand(right, targetType);
                    left  = ConvertOperand(left, targetType);
                    if (extra != null)
                    {
                        extra = ConvertOperand(extra, targetType);
                    }

                    ReleaseOperand(right);
                    ReleaseOperand(left);
                    if (extra != null)
                    {
                        ReleaseOperand(extra);
                    }

                    target = AllocateRegister(isArithmetic ? targetType : typeof(int));

                    if (!isCompBranch)
                    {
                        PushByVal(target);
                    }
                }

                switch (cilopcode)
                {
                // Method arguments loading
                case CILOpCodes.Ldarg_0:
                case CILOpCodes.Ldarg_1:
                case CILOpCodes.Ldarg_2:
                case CILOpCodes.Ldarg_3:
                case CILOpCodes.Ldarg_S:
                case CILOpCodes.Ldarg:
                    arg = parameters[(cilinstr.Operand == null) ? (cilopcode - CILOpCodes.Ldarg_0) :
                                     (cilinstr.Operand as ParameterInfo).Position];
                    if (arg.PassingStyle == PassingStyles.VAL)
                    {
                        target = AllocateRegister(arg.StateSpace != StateSpaces.REG ? arg.UnderlyingType : arg.DataType, arg.StateSpace);
                        code.Add(new UnaryOperation(IROpCodes.MOV, target, arg));
                        PushByVal(target);
                    }
                    else
                    {
                        PushByRef(arg);
                    }
                    break;

                case CILOpCodes.Ldarga_S:
                case CILOpCodes.Ldarga:
                    arg = parameters[(cilinstr.Operand as ParameterInfo).Position];
                    PushByRef(arg);
                    break;

                // Local variables loading
                case CILOpCodes.Ldloc_0:
                case CILOpCodes.Ldloc_1:
                case CILOpCodes.Ldloc_2:
                case CILOpCodes.Ldloc_3:
                case CILOpCodes.Ldloc_S:
                case CILOpCodes.Ldloc:
                    loc = variables[(cilinstr.Operand == null) ? (cilopcode - CILOpCodes.Ldloc_0) :
                                    (cilinstr.Operand as LocalVariableInfo).LocalIndex];
                    target = AllocateRegister(loc.UnderlyingType, loc.StateSpace);
                    code.Add(new UnaryOperation(IROpCodes.MOV, target, loc));
                    PushByVal(target);
                    break;

                case CILOpCodes.Ldloca_S:
                case CILOpCodes.Ldloca:
                    loc = variables[(cilinstr.Operand as LocalVariableInfo).LocalIndex];
                    PushByRef(loc);
                    break;

                // Method arguments storing
                case CILOpCodes.Starg_S:
                case CILOpCodes.Starg:
                    arg   = parameters[(cilinstr.Operand as ParameterInfo).Position];
                    right = RetrieveOperand();
                    if (arg.DataType != right.DataType)
                    {
                        code.Add(new UnaryOperation(IROpCodes.CVT, arg, right));
                    }
                    else
                    {
                        code.Add(new UnaryOperation(IROpCodes.MOV, arg, right));
                    }
                    ReleaseOperand(right);
                    break;

                // Local variables storing
                case CILOpCodes.Stloc_0:
                case CILOpCodes.Stloc_1:
                case CILOpCodes.Stloc_2:
                case CILOpCodes.Stloc_3:
                case CILOpCodes.Stloc_S:
                case CILOpCodes.Stloc:
                    loc = variables[(cilinstr.Operand == null) ? (cilopcode - CILOpCodes.Stloc_0) :
                                    (cilinstr.Operand as LocalVariableInfo).LocalIndex];
                    right = RetrieveOperand();
                    if (loc.DataType != right.DataType)
                    {
                        code.Add(new UnaryOperation(IROpCodes.CVT, loc, right));
                    }
                    else
                    {
                        code.Add(new UnaryOperation(IROpCodes.MOV, loc, right));
                    }
                    ReleaseOperand(right);
                    break;

                // Constants storing
                case CILOpCodes.Ldnull:
                    PushByRef(new ImmediateValue((int)0));
                    break;

                case CILOpCodes.Ldc_I4_M1:
                case CILOpCodes.Ldc_I4_0:
                case CILOpCodes.Ldc_I4_1:
                case CILOpCodes.Ldc_I4_2:
                case CILOpCodes.Ldc_I4_3:
                case CILOpCodes.Ldc_I4_4:
                case CILOpCodes.Ldc_I4_5:
                case CILOpCodes.Ldc_I4_6:
                case CILOpCodes.Ldc_I4_7:
                case CILOpCodes.Ldc_I4_8:
                case CILOpCodes.Ldc_I4_S:
                case CILOpCodes.Ldc_I4:
                case CILOpCodes.Ldc_I8:
                case CILOpCodes.Ldc_R4:
                case CILOpCodes.Ldc_R8:
                    PushByRef(new ImmediateValue((cilinstr.Operand == null) ?
                                                 (int)(cilopcode - CILOpCodes.Ldc_I4_0) : (ValueType)Convert.ChangeType(cilinstr.Operand,
                                                                                                                        UpconvertMapping[cilinstr.Operand.GetType()])));
                    break;

                // Array elements loading
                case CILOpCodes.Ldelem_I1:
                case CILOpCodes.Ldelem_U1:
                case CILOpCodes.Ldelem_I2:
                case CILOpCodes.Ldelem_U2:
                case CILOpCodes.Ldelem_I4:
                case CILOpCodes.Ldelem_U4:
                case CILOpCodes.Ldelem_I8:
                case CILOpCodes.Ldelem_R4:
                case CILOpCodes.Ldelem_R8:
                case CILOpCodes.Ldelem:
                    regright = MapToRegister(RetrieveOperand());                     // index
                    regleft  = RetrieveOperand() as VirtualRegister;                 // array
                    VirtualRegister address = CalculateAddress(regleft, regright);
                    target = AllocateRegister(UpconvertMapping[regleft.UnderlyingType]);
                    code.Add(new LDInstruction(target, address));
                    ReleaseOperand(address);
                    PushByVal(target);
                    break;

                case CILOpCodes.Ldelema:
                    regright = MapToRegister(RetrieveOperand());                     // index
                    regleft  = RetrieveOperand() as VirtualRegister;                 // array
                    PushByVal(CalculateAddress(regleft, regright));
                    break;

                // Array elements storing
                case CILOpCodes.Stelem_I1:
                case CILOpCodes.Stelem_I2:
                case CILOpCodes.Stelem_I4:
                case CILOpCodes.Stelem_I8:
                case CILOpCodes.Stelem_R4:
                case CILOpCodes.Stelem_R8:
                case CILOpCodes.Stelem:
                    GenericOperand val = RetrieveOperand();                     // value
                    regright = MapToRegister(RetrieveOperand());                // index
                    regleft  = RetrieveOperand() as VirtualRegister;            // array
                    IEnumerable <Type> compatible = regleft.UnderlyingType.CompatibleTypes().Where(type => type.SizeOf() >= sizeof(int));
                    target = !compatible.Contains(val.DataType) ?
                             ConvertOperand(val, compatible.First()) as VirtualRegister : MapToRegister(val);
                    address = CalculateAddress(regleft, regright);
                    code.Add(new STInstruction(address, target));
                    ReleaseOperand(address);
                    ReleaseOperand(target);
                    break;

                // Indirect loads
                case CILOpCodes.Ldobj:
                case CILOpCodes.Ldind_I1:
                case CILOpCodes.Ldind_U1:
                case CILOpCodes.Ldind_I2:
                case CILOpCodes.Ldind_U2:
                case CILOpCodes.Ldind_I4:
                case CILOpCodes.Ldind_U4:
                case CILOpCodes.Ldind_I8:
                case CILOpCodes.Ldind_R4:
                case CILOpCodes.Ldind_R8:
                    // pointer (induced by ldelema) / variable (induced by ldloca) / parameter (induced by ldarga or pass-by-ref ldarg)
                    regright = RetrieveOperand() as VirtualRegister;
                    if (regright.StateSpace == StateSpaces.REG)
                    {
                        target = AllocateRegister(regright.DataType);
                        code.Add(new UnaryOperation(IROpCodes.MOV, target, regright));
                    }
                    else
                    {
                        target = AllocateRegister(UpconvertMapping[regright.UnderlyingType]);
                        code.Add(new LDInstruction(target, regright));
                    }
                    ReleaseOperand(regright);
                    PushByVal(target);
                    break;

                case CILOpCodes.Ldind_Ref:
                    regright = RetrieveOperand() as VirtualRegister;                     // pointer (induced by pass-by-ref ldarg)
                    target   = AllocateRegister(regright.UnderlyingType, regright.StateSpace);
                    code.Add(new UnaryOperation(IROpCodes.MOV, target, regright));
                    ReleaseOperand(regright);
                    PushByVal(target);
                    break;

                // Indirect stores
                case CILOpCodes.Stobj:
                case CILOpCodes.Stind_I1:
                case CILOpCodes.Stind_I2:
                case CILOpCodes.Stind_I4:
                case CILOpCodes.Stind_I8:
                case CILOpCodes.Stind_R4:
                case CILOpCodes.Stind_R8:
                    right = RetrieveOperand();                     // value
                    // pointer (induced by ldelema) / variable (induced by ldloca) / parameter (induced by ldarga or pass-by-ref ldarg)
                    regleft = RetrieveOperand() as VirtualRegister;
                    if (regleft.StateSpace == StateSpaces.REG)
                    {
                        if (regleft.DataType != right.DataType)
                        {
                            code.Add(new UnaryOperation(IROpCodes.CVT, regleft, right));
                        }
                        else
                        {
                            code.Add(new UnaryOperation(IROpCodes.MOV, regleft, right));
                        }
                        ReleaseOperand(right);
                    }
                    else
                    {
                        compatible = regleft.UnderlyingType.CompatibleTypes().Where(type => type.SizeOf() >= sizeof(int));
                        regright   = !compatible.Contains(right.DataType) ?
                                     ConvertOperand(right, compatible.First()) as VirtualRegister : MapToRegister(right);
                        code.Add(new STInstruction(regleft, regright));
                        ReleaseOperand(regright);
                    }
                    ReleaseOperand(regleft);
                    break;

                case CILOpCodes.Stind_Ref:
                    regright = RetrieveOperand() as VirtualRegister;                    // source pointer (induced by ldarg or pass-by-ref ldarg)
                    regleft  = RetrieveOperand() as VirtualRegister;                    // target pointer (induced by pass-by-ref ldarg)
                    code.Add(new UnaryOperation(IROpCodes.MOV, regleft, regright));
                    ReleaseOperand(regleft);
                    ReleaseOperand(regright);
                    break;

                // Comparison branches
                case CILOpCodes.Beq:
                case CILOpCodes.Beq_S:
                    code.Add(new BinaryOperation(IROpCodes.EQ, target, left, right));
                    goto case CILOpCodes.Brtrue;

                case CILOpCodes.Bne_Un:
                case CILOpCodes.Bne_Un_S:
                    code.Add(new BinaryOperation(IROpCodes.NE, target, left, right));
                    goto case CILOpCodes.Brtrue;

                case CILOpCodes.Bge_S:
                case CILOpCodes.Bge_Un_S:
                case CILOpCodes.Bge:
                case CILOpCodes.Bge_Un:
                    code.Add(new BinaryOperation(IROpCodes.GE, target, left, right));
                    goto case CILOpCodes.Brtrue;

                case CILOpCodes.Bgt_S:
                case CILOpCodes.Bgt_Un_S:
                case CILOpCodes.Bgt:
                case CILOpCodes.Bgt_Un:
                    code.Add(new BinaryOperation(IROpCodes.GT, target, left, right));
                    goto case CILOpCodes.Brtrue;

                case CILOpCodes.Ble_S:
                case CILOpCodes.Ble_Un_S:
                case CILOpCodes.Ble:
                case CILOpCodes.Ble_Un:
                    code.Add(new BinaryOperation(IROpCodes.LE, target, left, right));
                    goto case CILOpCodes.Brtrue;

                case CILOpCodes.Blt_S:
                case CILOpCodes.Blt_Un_S:
                case CILOpCodes.Blt:
                case CILOpCodes.Blt_Un:
                    code.Add(new BinaryOperation(IROpCodes.LT, target, left, right));
                    goto case CILOpCodes.Brtrue;

                // Basic branches (the last instructions in basic block)
                case CILOpCodes.Br_S:
                case CILOpCodes.Br:
                    Trailer = new JMPInstruction();
                    break;

                case CILOpCodes.Brfalse_S:
                case CILOpCodes.Brfalse:
                    regleft = MapToRegister(ConvertOperand(RetrieveOperand(), typeof(int)));
                    Trailer = new JFInstruction(regleft);
                    ReleaseOperand(regleft);
                    break;

                case CILOpCodes.Brtrue_S:
                case CILOpCodes.Brtrue:
                    regleft = isCompBranch ? target : MapToRegister(ConvertOperand(RetrieveOperand(), typeof(int)));
                    Trailer = new JTInstruction(regleft);
                    ReleaseOperand(regleft);
                    break;

                // Call stuff.
                case CILOpCodes.Call:
                    MethodInfo   method   = cilinstr.Operand as MethodInfo;
                    PropertyInfo property = method.DeclaringType.GetProperty(method.Name.Replace("get_", ""));
                    if (property != null)
                    {
                        // Handle predefined value access.
                        PredefinedValueAttribute pva = Attribute.GetCustomAttribute(property,
                                                                                    typeof(PredefinedValueAttribute)) as PredefinedValueAttribute;
                        if (pva != null)
                        {
                            PushByVal(MapToRegister(srpool.Single(sr => sr.Value == pva.Value)));
                        }
                        else
                        {
                            throw new NotSupportedException(method.DeclaringType.FullName + "." + property.Name);
                        }
                    }
                    else
                    {
                        // Handle intrinsic function call.
                        IntrinsicFunctionAttribute ifa = Attribute.GetCustomAttribute(method,
                                                                                      typeof(IntrinsicFunctionAttribute)) as IntrinsicFunctionAttribute;
                        if (ifa != null)
                        {
                            switch (ifa.OpCode)
                            {
                            case IROpCodes.SYNC:
                                code.Add(new SYNCInstruction());
                                break;

                            case IROpCodes.ABS:
                            case IROpCodes.SQRT:
                            case IROpCodes.RSQRT:
                            case IROpCodes.SIN:
                            case IROpCodes.COS:
                            case IROpCodes.LG2:
                            case IROpCodes.EX2:
                                right = ConvertOperand(RetrieveOperand(), UpconvertMapping[method.ReturnType]);
                                ReleaseOperand(right);
                                target = AllocateRegister(right.DataType);
                                code.Add(new UnaryOperation(ifa.OpCode, target, right));
                                PushByVal(target);
                                break;

                            case IROpCodes.MIN:
                            case IROpCodes.MAX:
                                right = ConvertOperand(RetrieveOperand(), UpconvertMapping[method.ReturnType]);
                                left  = ConvertOperand(RetrieveOperand(), right.DataType);
                                ReleaseOperand(right);
                                ReleaseOperand(left);
                                target = AllocateRegister(right.DataType);
                                code.Add(new BinaryOperation(ifa.OpCode, target, left, right));
                                PushByVal(target);
                                break;

                            default:
                                throw new NotSupportedException(ifa.OpCode.ToString());
                            }
                        }
                        else
                        {
                            // Handle subprogram call.
                            Subprogram sp;
                            spmap.TryGetValue(method, out sp);
                            if (sp == null)
                            {
                                sp = method.BuildIR(srpool, spmap);
                            }

                            List <GenericOperand> actualParameters = new List <GenericOperand>();
                            List <Tuple <VirtualRegister, VirtualRegister> > wrappedRefElements =
                                new List <Tuple <VirtualRegister, VirtualRegister> >();

                            if (method.ReturnType != typeof(void))
                            {
                                arg    = sp.FormalParameters.Last();
                                target = AllocateRegister(arg.StateSpace != StateSpaces.REG ?
                                                          arg.UnderlyingType : arg.DataType, arg.StateSpace);
                                PushByVal(target);
                            }

                            foreach (FormalParameter fp in sp.FormalParameters.Reverse())
                            {
                                GenericOperand ap = RetrieveOperand();
                                if (fp.StateSpace == StateSpaces.REG)
                                {
                                    VirtualRegister regap = ap as VirtualRegister;
                                    if (regap != null && regap.StateSpace != StateSpaces.REG)
                                    {
                                        // Passing array element by reference.

                                        // Create wrapping register.
                                        regright = AllocateRegister(fp.DataType);
                                        // Load array element value to wrapping register.
                                        if (fp.PassingStyle == PassingStyles.REF)
                                        {
                                            code.Add(new LDInstruction(regright, regap));
                                        }
                                        // Remember address-to-register mapping.
                                        wrappedRefElements.Add(new Tuple <VirtualRegister, VirtualRegister>(regap, regright));

                                        // Replace original actual parameter with wrapping register.
                                        ap = regright;
                                    }
                                    else if (fp.PassingStyle == PassingStyles.VAL)
                                    {
                                        // Perform implicit parameter conversion.
                                        ap = ConvertOperand(ap, fp.DataType);
                                    }
                                }
                                actualParameters.Insert(0, ap);
                            }

                            code.Add(new CALLInstruction(sp, actualParameters));

                            // Update values of wrapped array elements.
                            code.AddRange(wrappedRefElements.Select(we => new STInstruction(we.Item1, we.Item2)));

                            foreach (VirtualRegister ap in actualParameters)
                            {
                                ReleaseOperand(ap);
                            }
                            foreach (Tuple <VirtualRegister, VirtualRegister> we in wrappedRefElements)
                            {
                                ReleaseOperand(we.Item1);
                            }

                            if (method.ReturnType != typeof(void))
                            {
                                PushByVal(target);
                                (target as DynamicRegister).Live = true;
                            }
                        }
                    }
                    break;

                // Arithmetic operations
                case CILOpCodes.Add:
                    code.Add(new BinaryOperation(IROpCodes.ADD, target, left, right));
                    break;

                case CILOpCodes.Sub:
                    code.Add(new BinaryOperation(IROpCodes.SUB, target, left, right));
                    break;

                case CILOpCodes.Mul:
                    if (extra != null)
                    {
                        code.Add(new MADOperation(target, left, right, extra));
                        skipnext = true;
                    }
                    else
                    {
                        code.Add(new BinaryOperation(IROpCodes.MUL, target, left, right));
                    }
                    break;

                case CILOpCodes.Div:
                case CILOpCodes.Div_Un:
                    code.Add(new BinaryOperation(IROpCodes.DIV, target, left, right));
                    break;

                case CILOpCodes.Rem:
                case CILOpCodes.Rem_Un:
                    code.Add(new BinaryOperation(IROpCodes.REM, target, left, right));
                    break;

                case CILOpCodes.And:
                    code.Add(new BinaryOperation(IROpCodes.AND, target, left, right));
                    break;

                case CILOpCodes.Or:
                    code.Add(new BinaryOperation(IROpCodes.OR, target, left, right));
                    break;

                case CILOpCodes.Xor:
                    code.Add(new BinaryOperation(IROpCodes.XOR, target, left, right));
                    break;

                case CILOpCodes.Neg:
                    right = RetrieveOperand();
                    right = ConvertOperand(right, NegMapping[right.DataType]);
                    ReleaseOperand(right);
                    target = AllocateRegister(right.DataType);
                    code.Add(new UnaryOperation(IROpCodes.NEG, target, right));
                    PushByVal(target);
                    break;

                case CILOpCodes.Not:
                    right = RetrieveOperand();
                    right = ConvertOperand(right, NotMapping[right.DataType]);
                    ReleaseOperand(right);
                    target = AllocateRegister(right.DataType);
                    code.Add(new UnaryOperation(IROpCodes.NOT, target, right));
                    PushByVal(target);
                    break;

                // Convert operations
                case CILOpCodes.Conv_I1:
                case CILOpCodes.Conv_Ovf_I1:
                case CILOpCodes.Conv_Ovf_I1_Un:
                    PushByVal(MapToRegister(ConvertOperand(RetrieveOperand(), typeof(sbyte))));
                    break;

                case CILOpCodes.Conv_I2:
                case CILOpCodes.Conv_Ovf_I2:
                case CILOpCodes.Conv_Ovf_I2_Un:
                    PushByVal(MapToRegister(ConvertOperand(RetrieveOperand(), typeof(short))));
                    break;

                case CILOpCodes.Conv_I:
                case CILOpCodes.Conv_Ovf_I:
                case CILOpCodes.Conv_Ovf_I_Un:
                case CILOpCodes.Conv_U:
                case CILOpCodes.Conv_Ovf_U:
                case CILOpCodes.Conv_Ovf_U_Un:
                case CILOpCodes.Conv_I4:
                case CILOpCodes.Conv_Ovf_I4:
                case CILOpCodes.Conv_Ovf_I4_Un:
                    PushByVal(MapToRegister(ConvertOperand(RetrieveOperand(), typeof(int))));
                    break;

                case CILOpCodes.Conv_I8:
                case CILOpCodes.Conv_Ovf_I8:
                case CILOpCodes.Conv_Ovf_I8_Un:
                    PushByVal(MapToRegister(ConvertOperand(RetrieveOperand(), typeof(long))));
                    break;

                case CILOpCodes.Conv_U1:
                case CILOpCodes.Conv_Ovf_U1:
                case CILOpCodes.Conv_Ovf_U1_Un:
                    PushByVal(MapToRegister(ConvertOperand(RetrieveOperand(), typeof(byte))));
                    break;

                case CILOpCodes.Conv_U2:
                case CILOpCodes.Conv_Ovf_U2:
                case CILOpCodes.Conv_Ovf_U2_Un:
                    PushByVal(MapToRegister(ConvertOperand(RetrieveOperand(), typeof(ushort))));
                    break;

                case CILOpCodes.Conv_U4:
                case CILOpCodes.Conv_Ovf_U4:
                case CILOpCodes.Conv_Ovf_U4_Un:
                    PushByVal(MapToRegister(ConvertOperand(RetrieveOperand(), typeof(uint))));
                    break;

                case CILOpCodes.Conv_U8:
                case CILOpCodes.Conv_Ovf_U8:
                case CILOpCodes.Conv_Ovf_U8_Un:
                    PushByVal(MapToRegister(ConvertOperand(RetrieveOperand(), typeof(ulong))));
                    break;

                case CILOpCodes.Conv_R4:
                case CILOpCodes.Conv_R_Un:
                    PushByVal(MapToRegister(ConvertOperand(RetrieveOperand(), typeof(float))));
                    break;

                case CILOpCodes.Conv_R8:
                    PushByVal(MapToRegister(ConvertOperand(RetrieveOperand(), typeof(double))));
                    break;

                // Compare operations
                case CILOpCodes.Ceq:
                    code.Add(new BinaryOperation(IROpCodes.EQ, target, left, right));
                    break;

                case CILOpCodes.Cgt:
                case CILOpCodes.Cgt_Un:
                    code.Add(new BinaryOperation(IROpCodes.GT, target, left, right));
                    break;

                case CILOpCodes.Clt:
                case CILOpCodes.Clt_Un:
                    code.Add(new BinaryOperation(IROpCodes.LT, target, left, right));
                    break;

                // Stack manipulation
                case CILOpCodes.Pop:
                    ReleaseOperand(RetrieveOperand());
                    break;

                case CILOpCodes.Dup:
                    bool byref = stack.Peek().Item1.Item2;
                    right = RetrieveOperand();
                    if (byref)
                    {
                        PushByRef(right);
                        PushByRef(right);
                    }
                    else
                    {
                        regright = right as VirtualRegister;
                        PushByVal(regright);
                        target = AllocateRegister(regright.UnderlyingType, regright.StateSpace);
                        code.Add(new UnaryOperation(IROpCodes.MOV, target, regright));
                        PushByVal(target);
                    }
                    break;

                case CILOpCodes.Ret:
                    if (result)
                    {
                        arg   = parameters.Last();
                        right = RetrieveOperand();
                        if (arg.DataType != right.DataType)
                        {
                            code.Add(new UnaryOperation(IROpCodes.CVT, arg, right));
                        }
                        else
                        {
                            code.Add(new UnaryOperation(IROpCodes.MOV, arg, right));
                        }
                        ReleaseOperand(right);
                    }
                    Trailer = new RETInstruction();
                    break;

                case CILOpCodes.Nop:
                    break;

                default:
                    throw new NotSupportedException(cilinstr.OpCode.Name);
                }

                if (isCompare)
                {
                    code.Add(new UnaryOperation(IROpCodes.NEG, target, target));
                }
            }
            if (Trailer == null)
            {
                Trailer = new JMPInstruction();
            }
        }