Exemple #1
1
		private static BasicBlock InlineIR(this CALLInstruction call,
			IList<BasicBlockInstruction> preamble,
			BasicBlock backend,
			Dictionary<Subprogram, Dictionary<VirtualRegister, VirtualRegister>> inlineRegMaps)
		{
			Dictionary<VirtualRegister, VirtualRegister> inlineRegMap;
			if (!inlineRegMaps.TryGetValue(call.Target, out inlineRegMap))
			{
				inlineRegMap = call.Target.LocalVariables.Select(lv => 
					new KeyValuePair<VirtualRegister, VirtualRegister>(lv, new VirtualRegister(lv.UnderlyingType, lv.StateSpace))).
					ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
				inlineRegMaps.Add(call.Target, inlineRegMap);
			}
			inlineRegMap = inlineRegMap.Concat(call.Target.FormalParameters.Zip(call.Arguments,
				(formal, actual) => new KeyValuePair<VirtualRegister, VirtualRegister>(formal,
				(actual is VirtualRegister) ? (actual as VirtualRegister) : 
				(formal.StateSpace != StateSpaces.REG) ? new VirtualRegister(formal.UnderlyingType, formal.StateSpace) :
				new VirtualRegister(formal.DataType)))).
				ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
			
			Dictionary<BasicBlock, BasicBlock> cfgmap = call.Target.GetBasicBlocks().Select(bb => 
			{
				VirtualRegister flag = (bb.Trailer is JumpIfInstruction) ?
					(bb.Trailer as JumpIfInstruction).Flag.MapOperand(inlineRegMap) : null;
				
				ControlFlowInstruction trailer;
				
				switch (bb.Trailer.OpCode)
				{
				case IROpCodes.RET:
					trailer = new JMPInstruction() { Target = backend };
					break;
				case IROpCodes.JMP:
					trailer = new JMPInstruction();
					break;
				case IROpCodes.JT:
					trailer = new JTInstruction(flag);
					break;
				case IROpCodes.JF:
					trailer = new JFInstruction(flag);
					break;
				default:
					throw new NotSupportedException();
				}
				
				return new KeyValuePair<BasicBlock, BasicBlock>(bb,
					new BasicBlock(bb.Code.Select(bbi => bbi.MapInstruction(inlineRegMap)).ToList(), trailer));
				
			}).ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
			
			foreach (KeyValuePair<BasicBlock, BasicBlock> bbmap in cfgmap)
			{
				if (bbmap.Key.Successor != null)
					bbmap.Value.Successor = cfgmap[bbmap.Key.Successor];
				if (bbmap.Key.Target != null)
					bbmap.Value.Target = cfgmap[bbmap.Key.Target];
			}
			
			BasicBlock root = cfgmap[call.Target.CFGRoot];
			return new BasicBlock(preamble.Concat(root.Code).ToList(), root.Trailer);
		}
Exemple #2
0
        private static BasicBlock InlineIR(this BasicBlock bb,
                                           Func <Subprogram, bool> permitInline,
                                           Dictionary <VirtualRegister, VirtualRegister> copyRegMap,
                                           Dictionary <Subprogram, Dictionary <VirtualRegister, VirtualRegister> > inlineRegMaps,
                                           IList <Subprogram> subprograms,
                                           Dictionary <BasicBlock, BasicBlock> basicBlockMap)
        {
            BasicBlock result;

            if (!basicBlockMap.TryGetValue(bb, out result))
            {
                VirtualRegister flag = (bb.Trailer is JumpIfInstruction) ?
                                       (bb.Trailer as JumpIfInstruction).Flag.MapOperand(copyRegMap) : null;

                ControlFlowInstruction trailer;
                switch (bb.Trailer.OpCode)
                {
                case IROpCodes.RET:
                    trailer = new RETInstruction();
                    break;

                case IROpCodes.JMP:
                    trailer = new JMPInstruction();
                    break;

                case IROpCodes.JT:
                    trailer = new JTInstruction(flag);
                    break;

                case IROpCodes.JF:
                    trailer = new JFInstruction(flag);
                    break;

                default:
                    throw new NotSupportedException();
                }

                BasicBlock backend;
                result = bb.Code.InlineIR(trailer, permitInline, copyRegMap, inlineRegMaps, subprograms, out backend);
                basicBlockMap.Add(bb, result);

                if (bb.Successor != null)
                {
                    backend.Successor = bb.Successor.InlineIR(permitInline, copyRegMap, inlineRegMaps, subprograms, basicBlockMap);
                }
                if (bb.Target != null)
                {
                    backend.Target = bb.Target.InlineIR(permitInline, copyRegMap, inlineRegMaps, subprograms, basicBlockMap);
                }
            }

            return(result);
        }
Exemple #3
0
		private static BasicBlock InlineIR(this BasicBlock bb,
			Func<Subprogram, bool> permitInline,
			Dictionary<VirtualRegister, VirtualRegister> copyRegMap,
			Dictionary<Subprogram, Dictionary<VirtualRegister, VirtualRegister>> inlineRegMaps,
			IList<Subprogram> subprograms,
			Dictionary<BasicBlock, BasicBlock> basicBlockMap)
		{
			BasicBlock result;
			
			if (!basicBlockMap.TryGetValue(bb, out result))
			{
				VirtualRegister flag = (bb.Trailer is JumpIfInstruction) ?
					(bb.Trailer as JumpIfInstruction).Flag.MapOperand(copyRegMap) : null;
					
				ControlFlowInstruction trailer;
				switch (bb.Trailer.OpCode)
				{
				case IROpCodes.RET:
					trailer = new RETInstruction();
					break;
				case IROpCodes.JMP:
					trailer = new JMPInstruction();
					break;
				case IROpCodes.JT:
					trailer = new JTInstruction(flag);
					break;
				case IROpCodes.JF:
					trailer = new JFInstruction(flag);
					break;
				default:
					throw new NotSupportedException();
				}
				
				BasicBlock backend;
				result = bb.Code.InlineIR(trailer, permitInline, copyRegMap, inlineRegMaps, subprograms, out backend);
				basicBlockMap.Add(bb, result);
				
				if (bb.Successor != null)
					backend.Successor = bb.Successor.InlineIR(permitInline, copyRegMap, inlineRegMaps, subprograms, basicBlockMap);
				if (bb.Target != null)
					backend.Target = bb.Target.InlineIR(permitInline, copyRegMap, inlineRegMaps, subprograms, basicBlockMap);
			}
			
			return result;
		}
Exemple #4
0
        private static BasicBlock InlineIR(this CALLInstruction call,
                                           IList <BasicBlockInstruction> preamble,
                                           BasicBlock backend,
                                           Dictionary <Subprogram, Dictionary <VirtualRegister, VirtualRegister> > inlineRegMaps)
        {
            Dictionary <VirtualRegister, VirtualRegister> inlineRegMap;

            if (!inlineRegMaps.TryGetValue(call.Target, out inlineRegMap))
            {
                inlineRegMap = call.Target.LocalVariables.Select(lv =>
                                                                 new KeyValuePair <VirtualRegister, VirtualRegister>(lv, new VirtualRegister(lv.UnderlyingType, lv.StateSpace))).
                               ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
                inlineRegMaps.Add(call.Target, inlineRegMap);
            }
            inlineRegMap = inlineRegMap.Concat(call.Target.FormalParameters.Zip(call.Arguments,
                                                                                (formal, actual) => new KeyValuePair <VirtualRegister, VirtualRegister>(formal,
                                                                                                                                                        (actual is VirtualRegister) ? (actual as VirtualRegister) :
                                                                                                                                                        (formal.StateSpace != StateSpaces.REG) ? new VirtualRegister(formal.UnderlyingType, formal.StateSpace) :
                                                                                                                                                        new VirtualRegister(formal.DataType)))).
                           ToDictionary(kvp => kvp.Key, kvp => kvp.Value);

            Dictionary <BasicBlock, BasicBlock> cfgmap = call.Target.GetBasicBlocks().Select(bb =>
            {
                VirtualRegister flag = (bb.Trailer is JumpIfInstruction) ?
                                       (bb.Trailer as JumpIfInstruction).Flag.MapOperand(inlineRegMap) : null;

                ControlFlowInstruction trailer;

                switch (bb.Trailer.OpCode)
                {
                case IROpCodes.RET:
                    trailer = new JMPInstruction()
                    {
                        Target = backend
                    };
                    break;

                case IROpCodes.JMP:
                    trailer = new JMPInstruction();
                    break;

                case IROpCodes.JT:
                    trailer = new JTInstruction(flag);
                    break;

                case IROpCodes.JF:
                    trailer = new JFInstruction(flag);
                    break;

                default:
                    throw new NotSupportedException();
                }

                return(new KeyValuePair <BasicBlock, BasicBlock>(bb,
                                                                 new BasicBlock(bb.Code.Select(bbi => bbi.MapInstruction(inlineRegMap)).ToList(), trailer)));
            }).ToDictionary(kvp => kvp.Key, kvp => kvp.Value);

            foreach (KeyValuePair <BasicBlock, BasicBlock> bbmap in cfgmap)
            {
                if (bbmap.Key.Successor != null)
                {
                    bbmap.Value.Successor = cfgmap[bbmap.Key.Successor];
                }
                if (bbmap.Key.Target != null)
                {
                    bbmap.Value.Target = cfgmap[bbmap.Key.Target];
                }
            }

            BasicBlock root = cfgmap[call.Target.CFGRoot];

            return(new BasicBlock(preamble.Concat(root.Code).ToList(), root.Trailer));
        }
		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();
		}