Beispiel #1
0
        public void KillReg(SsaRegister reg, StreamWriter writer)
        {
            if (!IsRegScopable(reg))
                return;

            bool anyMatch = false;
            foreach (Entry e in m_regStack)
            {
                if (e.SsaReg == reg)
                {
                    e.Kill();
                    anyMatch = true;
                    break;
                }
            }

            if (!anyMatch)
                throw new Exception("Killed an untracked register");

            while (m_regStack.Count > 0)
            {
                Entry top = m_regStack.Peek();
                if (top.IsAlive)
                    break;

                m_regStack.Pop();

                m_indent = m_indent.Substring(0, m_indent.Length - 1);
                writer.Write(m_indent);
                writer.WriteLine("}");
            }
        }
Beispiel #2
0
        public void LivenReg(SsaRegister reg, CppBuilder builder)
        {
            if (!IsRegScopable(reg))
                return;

            AddReg(reg);
        }
Beispiel #3
0
 public MidInstruction(OpcodeEnum opcode, CodeLocationTag codeLocation, SsaRegister regArg, SsaRegister regArg2)
 {
     Opcode = opcode;
     CodeLocation = codeLocation;
     RegArg = regArg;
     RegArg2 = regArg2;
 }
Beispiel #4
0
 public MidInstruction(OpcodeEnum opcode, CodeLocationTag codeLocation, SsaRegister regArg, CfgOutboundEdge[] cfgEdgesArg)
 {
     Opcode = opcode;
     CodeLocation = codeLocation;
     RegArg = regArg;
     CfgEdgesArg = cfgEdgesArg;
 }
Beispiel #5
0
 public MidInstruction(OpcodeEnum opcode, CodeLocationTag codeLocation, SsaRegister regArg, SsaRegister regArg2, string strArg, CLRTypeSpec typeSpecArg, CLRTypeSpec typeSpecArg2)
 {
     Opcode = opcode;
     CodeLocation = codeLocation;
     RegArg = regArg;
     RegArg2 = regArg2;
     StrArg = strArg;
     TypeSpecArg = typeSpecArg;
     TypeSpecArg2 = typeSpecArg2;
 }
Beispiel #6
0
        public CfgOutboundEdgePrototype GenerateCfgEdge()
        {
            VType[] types = new VType[m_regs.Count];
            SsaRegister[] ssaRegs = new SsaRegister[m_regs.Count];

            for (int i = 0; i < types.Length; i++)
            {
                types[i] = m_regs[i].VType;
                ssaRegs[i] = m_regs[i];
            }
            return new CfgOutboundEdgePrototype(types, ssaRegs);
        }
Beispiel #7
0
        private void EmitCfgNode(CfgNode cfgNode)
        {
            // Build predecessor list
            List<CppTranslatedOutboundEdge> predecessorEdges = new List<CppTranslatedOutboundEdge>();
            foreach (CfgNode pred in cfgNode.Predecessors)
            {
                // Find the successor edge
                CppTranslatedOutboundEdge edge = null;
                foreach (CfgOutboundEdge outEdge in pred.Successors)
                {
                    if (outEdge.SuccessorNode == cfgNode)
                    {
                        edge = InternOutboundEdge(pred, outEdge);
                        break;
                    }
                }

                if (edge == null)
                    throw new Exception("Mismatched CFG edge");

                predecessorEdges.Add(edge);
            }

            List<Clarity.Rpa.HighInstruction> outInstructions = new List<Clarity.Rpa.HighInstruction>();
            List<Clarity.Rpa.HighPhi> outPhis = new List<Clarity.Rpa.HighPhi>();

            Clarity.Rpa.HighCfgNodeHandle highNode = m_nodesToEmittedNodes[cfgNode];
            CppCfgNodeOutline outline = m_nodeOutlines[cfgNode];
            List<SsaRegister> leakedRegs = new List<SsaRegister>();

            int numContinuedRegs = 0;

            int debugInstrNum = -1;
            MidInstruction[] midInstrs = cfgNode.MidInstructions;

            bool fallthroughMerged = false;

            foreach (MidInstruction midInstr in midInstrs)
            {
                debugInstrNum++;
                switch (midInstr.Opcode)
                {
                    case MidInstruction.OpcodeEnum.AllocObject:
                        {
                            Clarity.Rpa.HighSsaRegister dest = InternSsaRegister(midInstr.RegArg);
                            Clarity.Rpa.TypeSpecTag type = RpaTagFactory.CreateTypeTag(midInstr.TypeSpecArg);
                            outInstructions.Add(new Clarity.Rpa.Instructions.AllocObjInstruction(midInstr.CodeLocation, dest, type));
                        }
                        break;
                    case MidInstruction.OpcodeEnum.CallMethod:
                    case MidInstruction.OpcodeEnum.CallConstructor:
                    case MidInstruction.OpcodeEnum.ConstrainedCallMethod:
                        {
                            CppMethodSpec methodSpec = midInstr.MethodSpecArg;
                            CppMethod cppMethod = methodSpec.CppMethod;
                            CppClass thisClass = m_builder.GetCachedClass(cppMethod.DeclaredInClassSpec);

                            SsaRegister returnReg = midInstr.RegArg;
                            SsaRegister thisReg = midInstr.RegArg2;
                            List<Clarity.Rpa.HighSsaRegister> parameters = new List<Clarity.Rpa.HighSsaRegister>();

                            if (!cppMethod.MethodDef.Static && midInstr.Opcode != MidInstruction.OpcodeEnum.ConstrainedCallMethod)
                                thisReg = EmitPassiveConversion_PermitRefs(midInstr.CodeLocation, thisReg, cppMethod.DeclaredInClassSpec, outline, outInstructions);

                            // CLARITYTODO: Verify that this works with generic method parameters
                            for (int pIdx = 0; pIdx < midInstr.RegArgs.Length; pIdx++)
                            {
                                SsaRegister inReg = EmitPassiveConversion_PermitRefs(midInstr.CodeLocation, midInstr.RegArgs[pIdx], cppMethod.MethodSignature.ParamTypes[pIdx].Type, outline, outInstructions);
                                parameters.Add(InternSsaRegister(inReg));
                            }

                            Clarity.Rpa.HighSsaRegister outDestReg = null;

                            if (returnReg != null)
                                outDestReg = InternSsaRegister(returnReg);

                            Clarity.Rpa.TypeSpecTag constraintTag = null;

                            if (midInstr.Opcode == MidInstruction.OpcodeEnum.ConstrainedCallMethod)
                                constraintTag = RpaTagFactory.CreateTypeTag(midInstr.TypeSpecArg);

                            Clarity.Rpa.HighSsaRegister instanceReg = null;
                            if (!cppMethod.MethodDef.Static)
                                instanceReg = InternSsaRegister(thisReg);

                            CLR.CLRMethodSignatureInstance methodSig = cppMethod.MethodSignature;

                            int numParams = parameters.Count;
                            if (numParams != methodSig.ParamTypes.Length)
                                throw new Exception("Internal error: CallMethod param count mismatch");

                            if (midInstr.Opcode == MidInstruction.OpcodeEnum.CallMethod || midInstr.Opcode == MidInstruction.OpcodeEnum.CallConstructor)
                            {
                                if (cppMethod.MethodDef.Static)
                                {
                                    outInstructions.Add(new Clarity.Rpa.Instructions.CallStaticMethodInstruction(
                                        midInstr.CodeLocation,
                                        outDestReg,
                                        RpaTagFactory.CreateMethodSpec(Clarity.Rpa.MethodSlotType.Static, methodSpec),
                                        parameters.ToArray()
                                        ));
                                }
                                else
                                {
                                    outInstructions.Add(new Clarity.Rpa.Instructions.CallInstanceMethodInstruction(
                                        midInstr.CodeLocation,
                                        outDestReg,
                                        RpaTagFactory.CreateMethodSpec(Clarity.Rpa.MethodSlotType.Instance, methodSpec),
                                        instanceReg,
                                        parameters.ToArray()
                                        ));
                                }
                            }
                            else if (midInstr.Opcode == MidInstruction.OpcodeEnum.ConstrainedCallMethod)
                            {
                                outInstructions.Add(new Clarity.Rpa.Instructions.CallConstrainedMethodInstruction(
                                    midInstr.CodeLocation,
                                    outDestReg,
                                    constraintTag,
                                    RpaTagFactory.CreateMethodSpec(Clarity.Rpa.MethodSlotType.Instance, methodSpec),
                                    instanceReg,
                                    parameters.ToArray()
                                    ));
                            }
                        }
                        break;
                    case MidInstruction.OpcodeEnum.CallVirtualMethod:
                    case MidInstruction.OpcodeEnum.ConstrainedCallVirtualMethod:
                        {
                            CppMethodSpec methodSpec = midInstr.MethodSpecArg;
                            CppMethod cppMethod = methodSpec.CppMethod;
                            CppClass thisClass = m_builder.GetCachedClass(cppMethod.DeclaredInClassSpec);

                            Clarity.Rpa.HighSsaRegister returnReg = InternSsaRegister(midInstr.RegArg);
                            Clarity.Rpa.HighSsaRegister thisReg = null;
                            List<Clarity.Rpa.HighSsaRegister> paramRegs = new List<Clarity.Rpa.HighSsaRegister>();

                            if (midInstr.Opcode != MidInstruction.OpcodeEnum.ConstrainedCallVirtualMethod)
                                thisReg = InternSsaRegister(EmitPassiveConversion_PermitRefs(midInstr.CodeLocation, midInstr.RegArg2, cppMethod.DeclaredInClassSpec, outline, outInstructions));
                            else
                                thisReg = InternSsaRegister(midInstr.RegArg2);

                            for (int pIdx = 0; pIdx < midInstr.RegArgs.Length; pIdx++)
                                paramRegs.Add(InternSsaRegister(EmitPassiveConversion_PermitRefs(midInstr.CodeLocation, midInstr.RegArgs[pIdx], cppMethod.MethodSignature.ParamTypes[pIdx].Type, outline, outInstructions)));

                            CppVtableSlot vtableSlot = cppMethod.CreatesSlot;
                            if (vtableSlot == null)
                                vtableSlot = cppMethod.ReplacesStandardSlot;
                            if (vtableSlot == null)
                                throw new Exception("Internal error: Couldn't resolve vtable slot for method");

                            Clarity.Rpa.TypeSpecTag constraintType = null;
                            if (midInstr.Opcode == MidInstruction.OpcodeEnum.ConstrainedCallVirtualMethod)
                                constraintType = RpaTagFactory.CreateTypeTag(midInstr.TypeSpecArg);

                            if (cppMethod.MethodDef.Static)
                                throw new Exception();

                            CLR.CLRMethodSignatureInstance methodSig = cppMethod.MethodSignature;

                            int numParams = paramRegs.Count;
                            if (numParams != methodSig.ParamTypes.Length)
                                throw new Exception("Internal error: CallMethod param count mismatch");

                            if (midInstr.Opcode == MidInstruction.OpcodeEnum.CallVirtualMethod)
                            {
                                outInstructions.Add(new Clarity.Rpa.Instructions.CallVirtualMethodInstruction(
                                    midInstr.CodeLocation,
                                    returnReg,
                                    RpaTagFactory.CreateMethodSpec(Clarity.Rpa.MethodSlotType.Virtual, methodSpec),
                                    thisReg,
                                    paramRegs.ToArray()
                                ));
                            }
                            else if (midInstr.Opcode == MidInstruction.OpcodeEnum.ConstrainedCallVirtualMethod)
                                outInstructions.Add(new Clarity.Rpa.Instructions.CallConstrainedVirtualMethodInstruction(
                                    midInstr.CodeLocation,
                                    returnReg,
                                    constraintType,
                                    RpaTagFactory.CreateMethodSpec(Clarity.Rpa.MethodSlotType.Virtual, methodSpec),
                                    thisReg,
                                    paramRegs.ToArray()
                                    ));
                        }
                        break;
                    case MidInstruction.OpcodeEnum.KillReg:
                        break;
                    case MidInstruction.OpcodeEnum.LivenReg:
                        {
                            SsaRegister reg = midInstr.RegArg;
                            reg.GenerateUniqueID(m_regAllocator);
                            reg.MakeUsable();
                        }
                        break;
                    case MidInstruction.OpcodeEnum.Return:
                        outInstructions.Add(new Clarity.Rpa.Instructions.ReturnInstruction(midInstr.CodeLocation));
                        break;
                    case MidInstruction.OpcodeEnum.ReturnValue:
                        {
                            SsaRegister returnRegister = EmitPassiveConversion(midInstr.CodeLocation, midInstr.RegArg, midInstr.TypeSpecArg, outline, outInstructions);

                            outInstructions.Add(new Clarity.Rpa.Instructions.ReturnValueInstruction(
                                midInstr.CodeLocation,
                                InternSsaRegister(returnRegister)));
                        }
                        break;
                    case MidInstruction.OpcodeEnum.LoadReg_ManagedPtr:
                        {
                            Clarity.Rpa.HighLocal lcl = m_localLookup[midInstr.VRegArg];
                            Clarity.Rpa.HighSsaRegister dest = InternSsaRegister(midInstr.RegArg);
                            outInstructions.Add(new Clarity.Rpa.Instructions.LoadLocalInstruction(
                                midInstr.CodeLocation,
                                dest,
                                lcl
                                ));
                        }
                        break;
                    case MidInstruction.OpcodeEnum.LoadReg_Value:
                        {
                            CLR.CLRTypeSpec srcSpec = midInstr.VRegArg.VType.TypeSpec;
                            CLR.CLRTypeSpec destSpec = midInstr.RegArg.VType.TypeSpec;
                            if (srcSpec.Equals(destSpec))
                            {
                                outInstructions.Add(new Clarity.Rpa.Instructions.LoadLocalInstruction(
                                    midInstr.CodeLocation,
                                    InternSsaRegister(midInstr.RegArg),
                                    m_localLookup[midInstr.VRegArg]
                                    ));
                            }
                            else
                            {
                                SsaRegister tempReg = new SsaRegister(midInstr.VRegArg.VType);
                                tempReg.MakeUsable();
                                tempReg.GenerateUniqueID(m_regAllocator);

                                outline.AddRegister(tempReg);

                                outInstructions.Add(new Clarity.Rpa.Instructions.LoadLocalInstruction(
                                    midInstr.CodeLocation,
                                    InternSsaRegister(tempReg),
                                    m_localLookup[midInstr.VRegArg]
                                    ));

                                outInstructions.Add(new Clarity.Rpa.Instructions.PassiveConvertInstruction(
                                    midInstr.CodeLocation,
                                    InternSsaRegister(midInstr.RegArg),
                                    InternSsaRegister(tempReg)
                                    ));
                            }
                        }
                        break;
                    case MidInstruction.OpcodeEnum.StoreReg_ManagedPtr:
                        outInstructions.Add(new Clarity.Rpa.Instructions.StoreLocalInstruction(
                            midInstr.CodeLocation,
                            m_localLookup[midInstr.VRegArg],
                            InternSsaRegister(midInstr.RegArg)
                            ));
                        break;
                    case MidInstruction.OpcodeEnum.StoreReg_Value:
                        {
                            SsaRegister srcReg = EmitPassiveConversion(midInstr.CodeLocation, midInstr.RegArg, midInstr.VRegArg.VType.TypeSpec, outline, outInstructions);

                            outInstructions.Add(new Clarity.Rpa.Instructions.StoreLocalInstruction(
                                midInstr.CodeLocation,
                                m_localLookup[midInstr.VRegArg],
                                InternSsaRegister(srcReg)
                                ));
                        }
                        break;
                    case MidInstruction.OpcodeEnum.beq_ref:
                    case MidInstruction.OpcodeEnum.bne_ref:
                        {
                            fallthroughMerged = true;
                            CppTranslatedOutboundEdge edgeA = InternOutboundEdge(cfgNode, midInstr.CfgEdgeArg);
                            CppTranslatedOutboundEdge edgeB = InternOutboundEdge(cfgNode, cfgNode.FallThroughEdge);

                            CppTranslatedOutboundEdge trueEdge, falseEdge;
                            if (midInstr.Opcode == MidInstruction.OpcodeEnum.beq_ref)
                            {
                                trueEdge = edgeA;
                                falseEdge = edgeB;
                            }
                            else if (midInstr.Opcode == MidInstruction.OpcodeEnum.bne_ref)
                            {
                                trueEdge = edgeB;
                                falseEdge = edgeA;
                            }
                            else
                                throw new Exception();

                            Clarity.Rpa.HighSsaRegister regA = InternSsaRegister(midInstr.RegArg);
                            Clarity.Rpa.HighSsaRegister regB = InternSsaRegister(midInstr.RegArg2);

                            outInstructions.Add(new Clarity.Rpa.Instructions.BranchCompareRefsInstruction(midInstr.CodeLocation, regA, regB, trueEdge.NextNode, falseEdge.NextNode));
                        }
                        break;
                    case MidInstruction.OpcodeEnum.cne_ref:
                    case MidInstruction.OpcodeEnum.ceq_ref:
                        {
                            int trueValue, falseValue;
                            Clarity.Rpa.HighSsaRegister destReg = InternSsaRegister(midInstr.RegArg);

                            if (midInstr.Opcode == MidInstruction.OpcodeEnum.ceq_ref)
                            {
                                trueValue = 1;
                                falseValue = 0;
                            }
                            else if (midInstr.Opcode == MidInstruction.OpcodeEnum.cne_ref)
                            {
                                trueValue = 0;
                                falseValue = 1;
                            }
                            else
                                throw new Exception();

                            Clarity.Rpa.HighSsaRegister regA = InternSsaRegister(midInstr.RegArg2);
                            Clarity.Rpa.HighSsaRegister regB = InternSsaRegister(midInstr.RegArg3);

                            outInstructions.Add(new Clarity.Rpa.Instructions.CompareRefsInstruction(midInstr.CodeLocation, destReg, regA, regB, trueValue, falseValue));
                        }
                        break;
                    case MidInstruction.OpcodeEnum.beq_val:
                    case MidInstruction.OpcodeEnum.bne_val:
                    case MidInstruction.OpcodeEnum.bge:
                    case MidInstruction.OpcodeEnum.bgt:
                    case MidInstruction.OpcodeEnum.ble:
                    case MidInstruction.OpcodeEnum.blt:
                    case MidInstruction.OpcodeEnum.clt:
                    case MidInstruction.OpcodeEnum.cgt:
                    case MidInstruction.OpcodeEnum.ceq_numeric:
                        {
                            bool isBranch;
                            SsaRegister leftReg, rightReg;

                            switch (midInstr.Opcode)
                            {
                                case MidInstruction.OpcodeEnum.beq_val:
                                case MidInstruction.OpcodeEnum.bne_val:
                                case MidInstruction.OpcodeEnum.bge:
                                case MidInstruction.OpcodeEnum.bgt:
                                case MidInstruction.OpcodeEnum.ble:
                                case MidInstruction.OpcodeEnum.blt:
                                    isBranch = true;
                                    leftReg = midInstr.RegArg;
                                    rightReg = midInstr.RegArg2;
                                    break;
                                case MidInstruction.OpcodeEnum.clt:
                                case MidInstruction.OpcodeEnum.cgt:
                                case MidInstruction.OpcodeEnum.ceq_numeric:
                                    isBranch = false;
                                    leftReg = midInstr.RegArg2;
                                    rightReg = midInstr.RegArg3;
                                    break;
                                default:
                                    throw new Exception();
                            }

                            bool isUnsigned = midInstr.FlagArg;
                            bool isReversed = false;

                            NumericStackType nst = NumericStackTypeForNumericBinaryOp(leftReg, rightReg);

                            if (isUnsigned && (nst == NumericStackType.Float32 || nst == NumericStackType.Float64))
                            {
                                isUnsigned = false;
                                isReversed = true;
                            }

                            CLR.CLRTypeSpec comparisonSpec = this.TypeSpecForNumericBinaryOp(leftReg, rightReg, isUnsigned);

                            Clarity.Rpa.HighSsaRegister leftHighReg = InternSsaRegister(EmitPassiveConversion(midInstr.CodeLocation, leftReg, comparisonSpec, outline, outInstructions));
                            Clarity.Rpa.HighSsaRegister rightHighReg = InternSsaRegister(EmitPassiveConversion(midInstr.CodeLocation, rightReg, comparisonSpec, outline, outInstructions));

                            Clarity.Rpa.Instructions.NumberCompareOperation op;

                            switch (midInstr.Opcode)
                            {
                                case MidInstruction.OpcodeEnum.blt:
                                case MidInstruction.OpcodeEnum.clt:
                                    op = isReversed ?
                                        Clarity.Rpa.Instructions.NumberCompareOperation.GreaterOrEqual :
                                        Clarity.Rpa.Instructions.NumberCompareOperation.LessThan;
                                    break;
                                case MidInstruction.OpcodeEnum.bgt:
                                case MidInstruction.OpcodeEnum.cgt:
                                    op = isReversed ?
                                        Clarity.Rpa.Instructions.NumberCompareOperation.LessOrEqual :
                                        Clarity.Rpa.Instructions.NumberCompareOperation.GreaterThan;
                                    break;
                                case MidInstruction.OpcodeEnum.ble:
                                    op = isReversed ?
                                        Clarity.Rpa.Instructions.NumberCompareOperation.GreaterThan :
                                        Clarity.Rpa.Instructions.NumberCompareOperation.LessOrEqual;
                                    break;
                                case MidInstruction.OpcodeEnum.bge:
                                    op = isReversed ?
                                        Clarity.Rpa.Instructions.NumberCompareOperation.LessThan :
                                        Clarity.Rpa.Instructions.NumberCompareOperation.GreaterOrEqual;
                                    break;
                                case MidInstruction.OpcodeEnum.beq_val:
                                case MidInstruction.OpcodeEnum.ceq_numeric:
                                    op = isReversed ?
                                        Clarity.Rpa.Instructions.NumberCompareOperation.NotEqual :
                                        Clarity.Rpa.Instructions.NumberCompareOperation.Equal;
                                    break;
                                case MidInstruction.OpcodeEnum.bne_val:
                                    op = isReversed ?
                                        Clarity.Rpa.Instructions.NumberCompareOperation.Equal :
                                        Clarity.Rpa.Instructions.NumberCompareOperation.NotEqual;
                                    break;
                                default:
                                    throw new ArgumentException();
                            }

                            Clarity.Rpa.Instructions.NumberArithType numType;

                            switch (nst)
                            {
                                case NumericStackType.Float32:
                                    numType = Clarity.Rpa.Instructions.NumberArithType.Float32;
                                    break;
                                case NumericStackType.Float64:
                                    numType = Clarity.Rpa.Instructions.NumberArithType.Float64;
                                    break;
                                case NumericStackType.Int32:
                                    numType = isUnsigned ?
                                        Clarity.Rpa.Instructions.NumberArithType.UInt32 :
                                        Clarity.Rpa.Instructions.NumberArithType.Int32;
                                    break;
                                case NumericStackType.Int64:
                                    numType = isUnsigned ?
                                        Clarity.Rpa.Instructions.NumberArithType.UInt64 :
                                        Clarity.Rpa.Instructions.NumberArithType.Int64;
                                    break;
                                case NumericStackType.NativeInt:
                                    numType = isUnsigned ?
                                        Clarity.Rpa.Instructions.NumberArithType.NativeUInt :
                                        Clarity.Rpa.Instructions.NumberArithType.NativeInt;
                                    break;
                                default:
                                    throw new ArgumentException();
                            }

                            if (isBranch)
                            {
                                fallthroughMerged = true;
                                CppTranslatedOutboundEdge trueEdge = InternOutboundEdge(cfgNode, midInstr.CfgEdgeArg);
                                CppTranslatedOutboundEdge falseEdge = InternOutboundEdge(cfgNode, cfgNode.FallThroughEdge);

                                if (isReversed)
                                {
                                    CppTranslatedOutboundEdge temp = trueEdge;
                                    trueEdge = falseEdge;
                                    falseEdge = temp;
                                }

                                outInstructions.Add(new Clarity.Rpa.Instructions.BranchCompareNumbersInstruction(
                                    midInstr.CodeLocation,
                                    op,
                                    numType,
                                    leftHighReg,
                                    rightHighReg,
                                    trueEdge.NextNode,
                                    falseEdge.NextNode
                                    ));
                            }
                            else
                            {
                                int trueValue = 0;
                                int falseValue = 1;

                                if (isReversed)
                                {
                                    trueValue = 0;
                                    falseValue = 1;
                                }

                                Clarity.Rpa.HighSsaRegister destReg = InternSsaRegister(midInstr.RegArg);

                                outInstructions.Add(new Clarity.Rpa.Instructions.CompareNumbersInstruction(
                                midInstr.CodeLocation,
                                    destReg,
                                    op,
                                    numType,
                                    leftHighReg,
                                    rightHighReg,
                                    trueValue,
                                    falseValue
                                    ));
                            }
                        }
                        break;
                    case MidInstruction.OpcodeEnum.LoadArgA_Value:
                        {
                            Clarity.Rpa.HighSsaRegister dest = InternSsaRegister(midInstr.RegArg);
                            Clarity.Rpa.HighLocal src = m_localLookup[midInstr.VRegArg];

                            outInstructions.Add(new Clarity.Rpa.Instructions.GetLocalPtrInstruction(
                                midInstr.CodeLocation,
                                dest,
                                src
                                ));
                        }
                        break;
                    case MidInstruction.OpcodeEnum.brzero:
                    case MidInstruction.OpcodeEnum.brnotzero:
                        {
                            SsaRegister inReg = midInstr.RegArg;
                            CLR.CLRTypeSpec targetType;
                            object zeroValue;

                            CLR.CLRTypeSpecClass cls = (CLR.CLRTypeSpecClass)inReg.VType.TypeSpec;
                            string typeName = cls.TypeDef.TypeName;
                            Clarity.Rpa.Instructions.NumberArithType arithType;

                            if (typeName == "Char" || typeName == "Boolean" ||
                                typeName == "Byte" || typeName == "UInt16" ||
                                typeName == "UInt32")
                            {
                                targetType = TypeSpecForNumericStackType(NumericStackType.Int32, true);
                                zeroValue = (uint)0;
                                arithType = Clarity.Rpa.Instructions.NumberArithType.UInt32;
                            }
                            else if (typeName == "SByte" || typeName == "Int16" || typeName == "Int32")
                            {
                                targetType = TypeSpecForNumericStackType(NumericStackType.Int32, false);
                                zeroValue = (int)0;
                                arithType = Clarity.Rpa.Instructions.NumberArithType.Int32;
                            }
                            else if (typeName == "UInt64")
                            {
                                targetType = TypeSpecForNumericStackType(NumericStackType.Int64, true);
                                zeroValue = (ulong)0;
                                arithType = Clarity.Rpa.Instructions.NumberArithType.UInt64;
                            }
                            else if (typeName == "Int64")
                            {
                                targetType = TypeSpecForNumericStackType(NumericStackType.Int64, false);
                                zeroValue = (long)0;
                                arithType = Clarity.Rpa.Instructions.NumberArithType.Int64;
                            }
                            else if (typeName == "IntPtr")
                            {
                                targetType = TypeSpecForNumericStackType(NumericStackType.NativeInt, false);
                                zeroValue = (long)0;
                                arithType = Clarity.Rpa.Instructions.NumberArithType.NativeInt;
                            }
                            else if (typeName == "UIntPtr")
                            {
                                targetType = TypeSpecForNumericStackType(NumericStackType.NativeInt, true);
                                zeroValue = (ulong)0;
                                arithType = Clarity.Rpa.Instructions.NumberArithType.NativeUInt;
                            }
                            else if (typeName == "Single")
                            {
                                targetType = TypeSpecForNumericStackType(NumericStackType.Float32, false);
                                zeroValue = (float)0;
                                arithType = Clarity.Rpa.Instructions.NumberArithType.Float32;
                            }
                            else if (typeName == "Double")
                            {
                                targetType = TypeSpecForNumericStackType(NumericStackType.Float64, false);
                                zeroValue = (double)0;
                                arithType = Clarity.Rpa.Instructions.NumberArithType.Float64;
                            }
                            else
                                throw new Exception();

                            fallthroughMerged = true;
                            CppTranslatedOutboundEdge trueEdge = InternOutboundEdge(cfgNode, midInstr.CfgEdgeArg);
                            CppTranslatedOutboundEdge falseEdge = InternOutboundEdge(cfgNode, cfgNode.FallThroughEdge);

                            Clarity.Rpa.Instructions.NumberCompareOperation compareOp;
                            if (midInstr.Opcode == MidInstruction.OpcodeEnum.brzero)
                                compareOp = Clarity.Rpa.Instructions.NumberCompareOperation.Equal;
                            else if (midInstr.Opcode == MidInstruction.OpcodeEnum.brnotzero)
                                compareOp = Clarity.Rpa.Instructions.NumberCompareOperation.NotEqual;
                            else
                                throw new Exception();

                            SsaRegister converted = EmitPassiveConversion(midInstr.CodeLocation, inReg, targetType, outline, outInstructions);
                            Clarity.Rpa.TypeSpecTag typeTag = RpaTagFactory.CreateTypeTag(targetType);

                            outInstructions.Add(new Clarity.Rpa.Instructions.BranchCompareNumbersInstruction(
                                midInstr.CodeLocation,
                                compareOp,
                                arithType,
                                InternSsaRegister(converted),
                                new Clarity.Rpa.HighSsaRegister(Clarity.Rpa.HighValueType.ConstantValue, typeTag, zeroValue),
                                trueEdge.NextNode,
                                falseEdge.NextNode
                                ));
                        }
                        break;
                    case MidInstruction.OpcodeEnum.brnull:
                    case MidInstruction.OpcodeEnum.brnotnull:
                        {
                            fallthroughMerged = true;
                            CppTranslatedOutboundEdge isNullEdge = InternOutboundEdge(cfgNode, midInstr.CfgEdgeArg);
                            CppTranslatedOutboundEdge isNotNullEdge = InternOutboundEdge(cfgNode, cfgNode.FallThroughEdge);

                            if (midInstr.Opcode == MidInstruction.OpcodeEnum.brnotnull)
                            {
                                CppTranslatedOutboundEdge temp = isNullEdge;
                                isNullEdge = isNotNullEdge;
                                isNotNullEdge = temp;
                            }

                            outInstructions.Add(new Clarity.Rpa.Instructions.BranchRefNullInstruction(
                                midInstr.CodeLocation,
                                InternSsaRegister(midInstr.RegArg),
                                isNullEdge.NextNode,
                                isNotNullEdge.NextNode
                                ));
                        }
                        break;
                    case MidInstruction.OpcodeEnum.LeakReg:
                        {
                            leakedRegs.Add(midInstr.RegArg);
                        }
                        break;
                    case MidInstruction.OpcodeEnum.EntryReg:
                        {
                            SsaRegister reg = midInstr.RegArg;

                            reg.GenerateUniqueID(m_regAllocator);
                            reg.MakeUsable();

                            Clarity.Rpa.HighSsaRegister destReg = InternSsaRegister(reg);

                            // Blocks can have constants on entry if all predecessors have the same value
                            if (!destReg.IsConstant)
                            {
                                List<Clarity.Rpa.HighPhiLink> phiLinks = new List<Clarity.Rpa.HighPhiLink>();

                                foreach (CppTranslatedOutboundEdge predEdge in predecessorEdges)
                                    phiLinks.Add(new Clarity.Rpa.HighPhiLink(predEdge.PrevNode, predEdge.Regs[numContinuedRegs]));

                                outPhis.Add(new Clarity.Rpa.HighPhi(
                                    InternSsaRegister(reg),
                                    phiLinks.ToArray()
                                    ));
                            }

                            numContinuedRegs++;
                        }
                        break;
                    case MidInstruction.OpcodeEnum.Throw:
                        {
                            CLR.CLRTypeSpec objSpec = m_builder.Assemblies.InternVagueType(new CLR.CLRSigTypeSimple(CLR.CLRSigType.ElementType.OBJECT));

                            SsaRegister converted = EmitPassiveConversion(midInstr.CodeLocation, midInstr.RegArg, objSpec, outline, outInstructions);

                            outInstructions.Add(new Clarity.Rpa.Instructions.ThrowInstruction(
                                    midInstr.CodeLocation,
                                    InternSsaRegister(converted)
                                ));
                        }
                        break;
                    case MidInstruction.OpcodeEnum.NewSZArray:
                        {
                            NumericStackType indexNst = StackTypeForTypeSpec(midInstr.RegArg2.VType.TypeSpec);

                            CLR.CLRTypeSpec indexSpec = m_builder.Assemblies.InternVagueType(new CLR.CLRSigTypeSimple(CLR.CLRSigType.ElementType.I));

                            SsaRegister indexReg = EmitPassiveConversion(midInstr.CodeLocation, midInstr.RegArg2, indexSpec, outline, outInstructions);

                            outInstructions.Add(new Clarity.Rpa.Instructions.AllocArrayInstruction(
                                midInstr.CodeLocation,
                                    InternSsaRegister(midInstr.RegArg),
                                    new Clarity.Rpa.HighSsaRegister[] { InternSsaRegister(indexReg) },
                                    RpaTagFactory.CreateTypeTag(midInstr.RegArg2.VType.TypeSpec)
                                ));
                        }
                        break;
                    case MidInstruction.OpcodeEnum.LoadField_ManagedPtr:
                        {
                            Clarity.Rpa.HighSsaRegister destReg = InternSsaRegister(midInstr.RegArg2);
                            Clarity.Rpa.HighSsaRegister objReg = InternSsaRegister(midInstr.RegArg);
                            Clarity.Rpa.HighSsaRegister addrReg = new Clarity.Rpa.HighSsaRegister(Clarity.Rpa.HighValueType.ManagedPtr, destReg.Type, null);

                            outInstructions.Add(new Clarity.Rpa.Instructions.PtrFieldInstruction(
                                midInstr.CodeLocation,
                                addrReg,
                                objReg,
                                midInstr.StrArg
                                ));
                            outInstructions.Add(new Clarity.Rpa.Instructions.LoadPtrInstruction(
                                midInstr.CodeLocation,
                                destReg,
                                addrReg
                                ));
                        }
                        break;
                    case MidInstruction.OpcodeEnum.LoadFieldA_ManagedPtr:
                        {
                            Clarity.Rpa.HighSsaRegister destReg = InternSsaRegister(midInstr.RegArg2);
                            Clarity.Rpa.HighSsaRegister objReg = InternSsaRegister(midInstr.RegArg);

                            outInstructions.Add(new Clarity.Rpa.Instructions.PtrFieldInstruction(
                                midInstr.CodeLocation,
                                destReg,
                                objReg,
                                midInstr.StrArg
                                ));
                        }
                        break;
                    case MidInstruction.OpcodeEnum.LoadField_Object:
                        {
                            Clarity.Rpa.HighSsaRegister destReg = InternSsaRegister(midInstr.RegArg2);
                            Clarity.Rpa.HighSsaRegister objReg = InternSsaRegister(EmitPassiveConversion(midInstr.CodeLocation, midInstr.RegArg, midInstr.TypeSpecArg, outline, outInstructions));
                            Clarity.Rpa.HighSsaRegister addrReg = new Clarity.Rpa.HighSsaRegister(Clarity.Rpa.HighValueType.ManagedPtr, destReg.Type, null);

                            outInstructions.Add(new Clarity.Rpa.Instructions.RefFieldInstruction(
                                midInstr.CodeLocation,
                                addrReg,
                                objReg,
                                midInstr.StrArg,
                                RpaTagFactory.CreateTypeTag(midInstr.TypeSpecArg)
                                ));
                            outInstructions.Add(new Clarity.Rpa.Instructions.LoadPtrInstruction(
                                midInstr.CodeLocation,
                                destReg,
                                addrReg
                                ));
                        }
                        break;
                    case MidInstruction.OpcodeEnum.LoadFieldA_Object:
                        {
                            Clarity.Rpa.HighSsaRegister destReg = InternSsaRegister(midInstr.RegArg2);
                            Clarity.Rpa.HighSsaRegister objReg = InternSsaRegister(EmitPassiveConversion(midInstr.CodeLocation, midInstr.RegArg, midInstr.TypeSpecArg, outline, outInstructions));

                            outInstructions.Add(new Clarity.Rpa.Instructions.RefFieldInstruction(
                                midInstr.CodeLocation,
                                destReg,
                                objReg,
                                midInstr.StrArg,
                                RpaTagFactory.CreateTypeTag(midInstr.TypeSpecArg)
                                ));
                        }
                        break;
                    case MidInstruction.OpcodeEnum.LoadField_Value:
                        {
                            Clarity.Rpa.HighSsaRegister destReg = InternSsaRegister(midInstr.RegArg2);
                            Clarity.Rpa.HighSsaRegister objReg = InternSsaRegister(midInstr.RegArg);

                            outInstructions.Add(new Clarity.Rpa.Instructions.LoadValueFieldInstruction(
                                midInstr.CodeLocation,
                                destReg,
                                objReg,
                                midInstr.StrArg
                                ));
                        }
                        break;
                    case MidInstruction.OpcodeEnum.LoadRegA:
                        {
                            Clarity.Rpa.HighLocal local = m_localLookup[midInstr.VRegArg];
                            Clarity.Rpa.HighSsaRegister dest = InternSsaRegister(midInstr.RegArg);

                            outInstructions.Add(new Clarity.Rpa.Instructions.GetLocalPtrInstruction(
                                midInstr.CodeLocation,
                                InternSsaRegister(midInstr.RegArg),
                                m_localLookup[midInstr.VRegArg]
                                ));
                        }
                        break;
                    case MidInstruction.OpcodeEnum.LoadArrayElem:
                        {
                            CLR.CLRTypeSpec indexSpec = m_builder.Assemblies.InternVagueType(new CLR.CLRSigTypeSimple(CLR.CLRSigType.ElementType.I));
                            Clarity.Rpa.HighSsaRegister arrayReg = InternSsaRegister(midInstr.RegArg);
                            Clarity.Rpa.HighSsaRegister indexReg = InternSsaRegister(EmitPassiveConversion(midInstr.CodeLocation, midInstr.RegArg2, indexSpec, outline, outInstructions));
                            Clarity.Rpa.HighSsaRegister destReg = InternSsaRegister(midInstr.RegArg3);
                            Clarity.Rpa.HighSsaRegister addrReg = new Clarity.Rpa.HighSsaRegister(Clarity.Rpa.HighValueType.ManagedPtr, destReg.Type, null);

                            outInstructions.Add(new Clarity.Rpa.Instructions.GetArrayElementPtrInstruction(
                                midInstr.CodeLocation,
                                addrReg,
                                arrayReg,
                                new Clarity.Rpa.HighSsaRegister[] { indexReg }
                                ));
                            outInstructions.Add(new Clarity.Rpa.Instructions.LoadPtrInstruction(
                                midInstr.CodeLocation,
                                destReg,
                                addrReg
                                ));
                        }
                        break;
                    case MidInstruction.OpcodeEnum.LoadArrayElemAddr:
                        {
                            CLR.CLRTypeSpec indexSpec = m_builder.Assemblies.InternVagueType(new CLR.CLRSigTypeSimple(CLR.CLRSigType.ElementType.I));
                            Clarity.Rpa.HighSsaRegister arrayReg = InternSsaRegister(midInstr.RegArg);
                            Clarity.Rpa.HighSsaRegister indexReg = InternSsaRegister(EmitPassiveConversion(midInstr.CodeLocation, midInstr.RegArg2, indexSpec, outline, outInstructions));
                            Clarity.Rpa.HighSsaRegister destReg = InternSsaRegister(midInstr.RegArg3);

                            outInstructions.Add(new Clarity.Rpa.Instructions.GetArrayElementPtrInstruction(
                                midInstr.CodeLocation,
                                destReg,
                                arrayReg,
                                new Clarity.Rpa.HighSsaRegister[] { indexReg }
                                ));
                        }
                        break;
                    case MidInstruction.OpcodeEnum.StoreField_ManagedPtr:
                        {
                            Clarity.Rpa.HighSsaRegister objReg = InternSsaRegister(midInstr.RegArg);
                            Clarity.Rpa.HighSsaRegister valueReg = InternSsaRegister(EmitPassiveConversion(midInstr.CodeLocation, midInstr.RegArg2, midInstr.TypeSpecArg2, outline, outInstructions));
                            Clarity.Rpa.HighSsaRegister addrReg = new Clarity.Rpa.HighSsaRegister(Clarity.Rpa.HighValueType.ManagedPtr, valueReg.Type, null);

                            outInstructions.Add(new Clarity.Rpa.Instructions.PtrFieldInstruction(
                                midInstr.CodeLocation,
                                addrReg,
                                objReg,
                                midInstr.StrArg));
                            outInstructions.Add(new Clarity.Rpa.Instructions.StorePtrInstruction(
                                midInstr.CodeLocation,
                                addrReg,
                                valueReg
                                ));
                        }
                        break;
                    case MidInstruction.OpcodeEnum.StoreField_Object:
                        {
                            Clarity.Rpa.HighSsaRegister objReg = InternSsaRegister(EmitPassiveConversion(midInstr.CodeLocation, midInstr.RegArg, midInstr.TypeSpecArg, outline, outInstructions));
                            Clarity.Rpa.HighSsaRegister valueReg = InternSsaRegister(EmitPassiveConversion(midInstr.CodeLocation, midInstr.RegArg2, midInstr.TypeSpecArg2, outline, outInstructions));
                            Clarity.Rpa.HighSsaRegister addrReg = new Clarity.Rpa.HighSsaRegister(Clarity.Rpa.HighValueType.ManagedPtr, valueReg.Type, null);

                            outInstructions.Add(new Clarity.Rpa.Instructions.RefFieldInstruction(
                                midInstr.CodeLocation,
                                addrReg,
                                objReg,
                                midInstr.StrArg,
                                RpaTagFactory.CreateTypeTag(midInstr.TypeSpecArg)
                                ));
                            outInstructions.Add(new Clarity.Rpa.Instructions.StorePtrInstruction(
                                midInstr.CodeLocation,
                                addrReg,
                                valueReg
                                ));
                        }
                        break;
                    case MidInstruction.OpcodeEnum.add:
                    case MidInstruction.OpcodeEnum.sub:
                    case MidInstruction.OpcodeEnum.mul:
                    case MidInstruction.OpcodeEnum.div:
                    case MidInstruction.OpcodeEnum.rem:
                    case MidInstruction.OpcodeEnum.and:
                    case MidInstruction.OpcodeEnum.or:
                    case MidInstruction.OpcodeEnum.xor:
                    case MidInstruction.OpcodeEnum.shl:
                    case MidInstruction.OpcodeEnum.shr: // [.un]
                        {
                            bool isUnsigned = (midInstr.ArithArg & MidInstruction.ArithEnum.Flags_Un) != 0;
                            bool isOvf = (midInstr.ArithArg & MidInstruction.ArithEnum.Flags_Ovf) != 0;
                            NumericStackType nst = NumericStackTypeForNumericBinaryOp(midInstr.RegArg, midInstr.RegArg2);

                            Clarity.Rpa.Instructions.NumberArithType arithType;

                            switch(nst)
                            {
                                case NumericStackType.Float32:
                                    arithType = Clarity.Rpa.Instructions.NumberArithType.Float32;
                                    break;
                                case NumericStackType.Float64:
                                    arithType = Clarity.Rpa.Instructions.NumberArithType.Float64;
                                    break;
                                case NumericStackType.Int32:
                                    arithType = isUnsigned ? Clarity.Rpa.Instructions.NumberArithType.UInt32 : Clarity.Rpa.Instructions.NumberArithType.Int32;
                                    break;
                                case NumericStackType.Int64:
                                    arithType = isUnsigned ? Clarity.Rpa.Instructions.NumberArithType.UInt64 : Clarity.Rpa.Instructions.NumberArithType.Int64;
                                    break;
                                case NumericStackType.NativeInt:
                                    arithType = isUnsigned ? Clarity.Rpa.Instructions.NumberArithType.NativeUInt : Clarity.Rpa.Instructions.NumberArithType.NativeInt;
                                    break;
                                default:
                                    throw new ArgumentException();
                            }

                            CLR.CLRTypeSpec opSpec = TypeSpecForNumericStackType(nst, isUnsigned);

                            Clarity.Rpa.Instructions.NumberArithOp arithOp;
                            bool canThrow = isOvf;
                            switch (midInstr.Opcode)
                            {
                                case MidInstruction.OpcodeEnum.add:
                                    arithOp = Clarity.Rpa.Instructions.NumberArithOp.Add;
                                    break;
                                case MidInstruction.OpcodeEnum.sub:
                                    arithOp = Clarity.Rpa.Instructions.NumberArithOp.Subtract;
                                    break;
                                case MidInstruction.OpcodeEnum.mul:
                                    arithOp = Clarity.Rpa.Instructions.NumberArithOp.Multiply;
                                    break;
                                case MidInstruction.OpcodeEnum.div:
                                    arithOp = Clarity.Rpa.Instructions.NumberArithOp.Divide;
                                    break;
                                case MidInstruction.OpcodeEnum.rem:
                                    arithOp = Clarity.Rpa.Instructions.NumberArithOp.Modulo;
                                    break;
                                case MidInstruction.OpcodeEnum.and:
                                    arithOp = Clarity.Rpa.Instructions.NumberArithOp.BitAnd;
                                    break;
                                case MidInstruction.OpcodeEnum.or:
                                    arithOp = Clarity.Rpa.Instructions.NumberArithOp.BitOr;
                                    break;
                                case MidInstruction.OpcodeEnum.xor:
                                    arithOp = Clarity.Rpa.Instructions.NumberArithOp.BitXor;
                                    break;
                                case MidInstruction.OpcodeEnum.shl:
                                    arithOp = Clarity.Rpa.Instructions.NumberArithOp.ShiftLeft;
                                    break;
                                case MidInstruction.OpcodeEnum.shr:
                                    arithOp = Clarity.Rpa.Instructions.NumberArithOp.ShiftRight;
                                    break;
                                default:
                                    throw new ArgumentException();
                            }

                            SsaRegister left = EmitPassiveConversion(midInstr.CodeLocation, midInstr.RegArg, opSpec, outline, outInstructions);
                            SsaRegister right = EmitPassiveConversion(midInstr.CodeLocation, midInstr.RegArg, opSpec, outline, outInstructions);

                            outInstructions.Add(new Clarity.Rpa.Instructions.ArithInstruction(
                                midInstr.CodeLocation,
                                InternSsaRegister(midInstr.RegArg3),
                                arithOp,
                                arithType,
                                InternSsaRegister(left),
                                InternSsaRegister(right),
                                isOvf
                                ));
                        }
                        break;
                    case MidInstruction.OpcodeEnum.neg:
                    case MidInstruction.OpcodeEnum.not:
                        {
                            Clarity.Rpa.HighSsaRegister srcReg = InternSsaRegister(EmitPassiveConversion(midInstr.CodeLocation, midInstr.RegArg, midInstr.RegArg2.VType.TypeSpec, outline, outInstructions));
                            Clarity.Rpa.HighSsaRegister destReg = InternSsaRegister(midInstr.RegArg2);

                            Clarity.Rpa.Instructions.NumberArithType arithType;
                            switch (midInstr.ArithArg)
                            {
                                case MidInstruction.ArithEnum.ArithType_Int32:
                                    arithType = Clarity.Rpa.Instructions.NumberArithType.Int32;
                                    break;
                                case MidInstruction.ArithEnum.ArithType_Int64:
                                    arithType = Clarity.Rpa.Instructions.NumberArithType.Int64;
                                    break;
                                case MidInstruction.ArithEnum.ArithType_NativeInt:
                                    arithType = Clarity.Rpa.Instructions.NumberArithType.NativeInt;
                                    break;
                                case MidInstruction.ArithEnum.ArithType_Float32:
                                    arithType = Clarity.Rpa.Instructions.NumberArithType.Float32;
                                    break;
                                case MidInstruction.ArithEnum.ArithType_Float64:
                                    arithType = Clarity.Rpa.Instructions.NumberArithType.Float64;
                                    break;
                                default:
                                    throw new Exception();
                            }

                            Clarity.Rpa.Instructions.NumberUnaryArithOp arithOp;
                            switch(midInstr.Opcode)
                            {
                                case MidInstruction.OpcodeEnum.neg:
                                    arithOp = Clarity.Rpa.Instructions.NumberUnaryArithOp.Negate;
                                    break;
                                case MidInstruction.OpcodeEnum.not:
                                    arithOp = Clarity.Rpa.Instructions.NumberUnaryArithOp.BitNot;
                                    break;
                                default:
                                    throw new Exception();
                            }

                            outInstructions.Add(new Clarity.Rpa.Instructions.UnaryArithInstruction(
                                midInstr.CodeLocation,
                                destReg,
                                arithOp,
                                arithType,
                                srcReg
                                ));
                        }
                        break;
                    case MidInstruction.OpcodeEnum.TryConvertObj:
                        {
                            outInstructions.Add(new Clarity.Rpa.Instructions.DynamicCastInstruction(
                                midInstr.CodeLocation,
                                InternSsaRegister(midInstr.RegArg2),
                                InternSsaRegister(midInstr.RegArg),
                                RpaTagFactory.CreateTypeTag(midInstr.RegArg2.VType.TypeSpec)
                                ));
                        }
                        break;
                    case MidInstruction.OpcodeEnum.Leave:
                        {
                            outInstructions.Add(new Clarity.Rpa.Instructions.LeaveRegionInstruction(
                                midInstr.CodeLocation,
                                midInstr.UIntArg
                                ));
                        }
                        break;
                    case MidInstruction.OpcodeEnum.DuplicateReg:
                        AliasSsaRegister(InternSsaRegister(midInstr.RegArg), midInstr.RegArg2);
                        break;
                    case MidInstruction.OpcodeEnum.StoreStaticField:
                        {
                            Clarity.Rpa.TypeSpecTag staticType = RpaTagFactory.CreateTypeTag(midInstr.TypeSpecArg);
                            string fieldName = midInstr.StrArg;

                            Clarity.Rpa.HighSsaRegister srcReg = InternSsaRegister(EmitPassiveConversion(midInstr.CodeLocation, midInstr.RegArg, midInstr.TypeSpecArg2, outline, outInstructions));

                            Clarity.Rpa.HighSsaRegister addrReg = new Clarity.Rpa.HighSsaRegister(Clarity.Rpa.HighValueType.ManagedPtr, srcReg.Type, null);

                            outInstructions.Add(new Clarity.Rpa.Instructions.GetStaticFieldAddrInstruction(
                                midInstr.CodeLocation,
                                addrReg,
                                staticType,
                                fieldName
                                ));
                            outInstructions.Add(new Clarity.Rpa.Instructions.StorePtrInstruction(
                                midInstr.CodeLocation,
                                addrReg,
                                srcReg
                                ));
                        }
                        break;
                    case MidInstruction.OpcodeEnum.LoadIndirect:
                        {
                            SsaRegister srcReg = EmitPassiveConversion(midInstr.CodeLocation, midInstr.RegArg, midInstr.RegArg2.VType.TypeSpec, outline, outInstructions);
                            SsaRegister destReg = midInstr.RegArg2;

                            outInstructions.Add(new Clarity.Rpa.Instructions.LoadPtrInstruction(
                                midInstr.CodeLocation,
                                InternSsaRegister(destReg),
                                InternSsaRegister(srcReg)
                                ));
                        }
                        break;
                    case MidInstruction.OpcodeEnum.LoadStaticField:
                        {
                            Clarity.Rpa.TypeSpecTag staticType = RpaTagFactory.CreateTypeTag(midInstr.TypeSpecArg);
                            string fieldName = midInstr.StrArg;

                            Clarity.Rpa.HighSsaRegister destReg = InternSsaRegister(midInstr.RegArg);
                            Clarity.Rpa.HighSsaRegister addrReg = new Clarity.Rpa.HighSsaRegister(Clarity.Rpa.HighValueType.ManagedPtr, destReg.Type, null);

                            outInstructions.Add(new Clarity.Rpa.Instructions.GetStaticFieldAddrInstruction(
                                midInstr.CodeLocation,
                                addrReg,
                                staticType,
                                fieldName
                                ));
                            outInstructions.Add(new Clarity.Rpa.Instructions.LoadPtrInstruction(
                                midInstr.CodeLocation,
                                destReg,
                                addrReg
                                ));
                        }
                        break;
                    case MidInstruction.OpcodeEnum.LoadStaticFieldAddr:
                        {
                            Clarity.Rpa.TypeSpecTag staticType = RpaTagFactory.CreateTypeTag(midInstr.TypeSpecArg);
                            string fieldName = midInstr.StrArg;

                            Clarity.Rpa.HighSsaRegister addrReg = InternSsaRegister(midInstr.RegArg);

                            outInstructions.Add(new Clarity.Rpa.Instructions.GetStaticFieldAddrInstruction(
                                midInstr.CodeLocation,
                                addrReg,
                                staticType,
                                fieldName
                                ));
                        }
                        break;
                    case MidInstruction.OpcodeEnum.Box:
                        {
                            outInstructions.Add(new Clarity.Rpa.Instructions.BoxInstruction(
                                midInstr.CodeLocation,
                                InternSsaRegister(midInstr.RegArg2),
                                InternSsaRegister(midInstr.RegArg)
                                ));
                        }
                        break;
                    case MidInstruction.OpcodeEnum.ConvertNumber:
                        {
                            bool isOvf = ((midInstr.ArithArg & MidInstruction.ArithEnum.Flags_Ovf) != 0);
                            bool isUn = ((midInstr.ArithArg & MidInstruction.ArithEnum.Flags_Un) != 0);

                            SsaRegister srcReg = midInstr.RegArg;
                            SsaRegister destReg = midInstr.RegArg2;

                            NumericStackType sourceNST = StackTypeForTypeSpec(midInstr.RegArg.VType.TypeSpec);
                            CLR.CLRTypeSpec srcSignAdjustedType = TypeSpecForNumericStackType(sourceNST, isUn);

                            srcReg = EmitPassiveConversion(midInstr.CodeLocation, srcReg, srcSignAdjustedType, outline, outInstructions);

                            outInstructions.Add(new Clarity.Rpa.Instructions.NumberConvertInstruction(
                                midInstr.CodeLocation,
                                InternSsaRegister(destReg),
                                InternSsaRegister(srcReg),
                                isOvf
                                ));
                        }
                        break;
                    case MidInstruction.OpcodeEnum.LoadArrayLength:
                        {
                            outInstructions.Add(new Clarity.Rpa.Instructions.GetArrayLengthInstruction(
                                midInstr.CodeLocation,
                                InternSsaRegister(midInstr.RegArg2),
                                InternSsaRegister(midInstr.RegArg)
                                ));
                        }
                        break;
                    case MidInstruction.OpcodeEnum.LoadTypeInfoHandle:
                        {
                            outInstructions.Add(new Clarity.Rpa.Instructions.GetTypeInfoInstruction(
                                midInstr.CodeLocation,
                                InternSsaRegister(midInstr.RegArg),
                                RpaTagFactory.CreateTypeTag(midInstr.TypeSpecArg)
                                ));
                        }
                        break;
                    case MidInstruction.OpcodeEnum.ConvertObj:
                        {
                            outInstructions.Add(new Clarity.Rpa.Instructions.ForceDynamicCastInstruction(
                                midInstr.CodeLocation,
                                InternSsaRegister(midInstr.RegArg2),
                                InternSsaRegister(midInstr.RegArg),
                                RpaTagFactory.CreateTypeTag(midInstr.RegArg2.VType.TypeSpec)
                                ));
                        }
                        break;
                    case MidInstruction.OpcodeEnum.StoreArrayElem:
                        {
                            CLR.CLRTypeSpec szArraySpec = midInstr.RegArg.VType.TypeSpec;
                            CLR.CLRTypeSpec subscriptType = ((CLR.CLRTypeSpecSZArray)szArraySpec).SubType;

                            SsaRegister arrayReg = midInstr.RegArg;
                            SsaRegister indexReg = midInstr.RegArg2;
                            SsaRegister valueReg = EmitPassiveConversion(midInstr.CodeLocation, midInstr.RegArg3, subscriptType, outline, outInstructions);

                            Clarity.Rpa.HighSsaRegister arrayRegHigh = InternSsaRegister(arrayReg);
                            Clarity.Rpa.HighSsaRegister indexRegHigh = InternSsaRegister(indexReg);
                            Clarity.Rpa.HighSsaRegister valueRegHigh = InternSsaRegister(valueReg);
                            Clarity.Rpa.HighSsaRegister addrReg = new Clarity.Rpa.HighSsaRegister(Clarity.Rpa.HighValueType.ManagedPtr, valueRegHigh.Type, null);

                            outInstructions.Add(new Clarity.Rpa.Instructions.GetArrayElementPtrInstruction(
                                midInstr.CodeLocation,
                                addrReg,
                                arrayRegHigh,
                                new Clarity.Rpa.HighSsaRegister[] { indexRegHigh }
                                ));
                            outInstructions.Add(new Clarity.Rpa.Instructions.StorePtrInstruction(
                                midInstr.CodeLocation,
                                addrReg,
                                valueRegHigh));
                        }
                        break;
                    case MidInstruction.OpcodeEnum.Switch:
                        {
                            CLR.CLRTypeSpec intType = m_builder.Assemblies.InternVagueType(new CLR.CLRSigTypeSimple(CLR.CLRSigType.ElementType.U4));

                            SsaRegister caseReg = EmitPassiveConversion(midInstr.CodeLocation, midInstr.RegArg, intType, outline, outInstructions);

                            int numCases = midInstr.CfgEdgesArg.Length;
                            Clarity.Rpa.HighCfgNodeHandle[] outNodes = new Clarity.Rpa.HighCfgNodeHandle[numCases];
                            for (int i = 0; i < numCases; i++)
                            {
                                CfgOutboundEdge edge = midInstr.CfgEdgesArg[i];
                                CfgNode caseNode = edge.SuccessorNode;

                                CppTranslatedOutboundEdge outEdge = InternOutboundEdge(cfgNode, edge);

                                outNodes[i] = outEdge.NextNode;
                            }

                            fallthroughMerged = true;
                            CppTranslatedOutboundEdge defaultEdge = InternOutboundEdge(cfgNode, cfgNode.FallThroughEdge);

                            outInstructions.Add(new Clarity.Rpa.Instructions.SwitchInstruction(
                                midInstr.CodeLocation,
                                InternSsaRegister(caseReg),
                                outNodes,
                                defaultEdge.NextNode
                                ));
                        }
                        break;
                    case MidInstruction.OpcodeEnum.StoreIndirect:
                        {
                            SsaRegister destReg = midInstr.RegArg;
                            SsaRegister valueReg = EmitPassiveConversion(midInstr.CodeLocation, midInstr.RegArg2, midInstr.RegArg.VType.TypeSpec, outline, outInstructions);

                            outInstructions.Add(new Clarity.Rpa.Instructions.StorePtrInstruction(
                                midInstr.CodeLocation,
                                InternSsaRegister(destReg),
                                InternSsaRegister(valueReg)
                                ));
                        }
                        break;
                    case MidInstruction.OpcodeEnum.LoadFieldInfoHandle:
                        {
                            outInstructions.Add(new Clarity.Rpa.Instructions.GetFieldInfoInstruction(
                                midInstr.CodeLocation,
                                InternSsaRegister(midInstr.RegArg),
                                RpaTagFactory.CreateTypeTag(midInstr.TypeSpecArg),
                                midInstr.StrArg,
                                midInstr.FlagArg
                                ));
                        }
                        break;
                    case MidInstruction.OpcodeEnum.UnboxPtr:
                        {
                            outInstructions.Add(new Clarity.Rpa.Instructions.UnboxPtrInstruction(
                                midInstr.CodeLocation,
                                InternSsaRegister(midInstr.RegArg2),
                                InternSsaRegister(midInstr.RegArg)
                                ));
                        }
                        break;
                    case MidInstruction.OpcodeEnum.UnboxValue:
                        {
                            outInstructions.Add(new Clarity.Rpa.Instructions.UnboxValueInstruction(
                                midInstr.CodeLocation,
                                InternSsaRegister(midInstr.RegArg2),
                                InternSsaRegister(midInstr.RegArg)
                                ));
                        }
                        break;
                    case MidInstruction.OpcodeEnum.ZeroFillPtr:
                        outInstructions.Add(new Clarity.Rpa.Instructions.ZeroFillPtrInstruction(
                            midInstr.CodeLocation,
                            InternSsaRegister(midInstr.RegArg)
                            ));
                        break;
                    case MidInstruction.OpcodeEnum.EnterProtectedBlock:
                        {
                            ExceptionHandlingCluster cluster = midInstr.EhClusterArg;

                            Clarity.Rpa.HighRegion tryRegion;
                            {
                                CppRegionEmitter tryEmitter = new CppRegionEmitter(m_builder, cluster.TryRegion, m_regAllocator, m_localLookup);
                                tryRegion = tryEmitter.Emit();
                            }

                            List<HighCatchHandler> catchHandlers = new List<HighCatchHandler>();
                            List<HighRegion> otherRegions = new List<HighRegion>();
                            foreach (ExceptionHandlingRegion handlerRegion in cluster.ExceptionHandlingRegions)
                            {
                                CppRegionEmitter hdlEmitter = new CppRegionEmitter(m_builder, handlerRegion, m_regAllocator, m_localLookup);
                                HighRegion hdlRegion = hdlEmitter.Emit();

                                switch (cluster.ClusterType)
                                {
                                    case ExceptionHandlingCluster.ClusterTypeEnum.TryCatch:
                                        {
                                            HighCfgNode entryNode = hdlRegion.EntryNode.Value;

                                            // Inject a catch landing instruction and recreate the phi node.
                                            // This is safe because III.1.7.5 disallows backward branches with stack,
                                            // so the only valid way to reach a catch handler is by catching, never via
                                            // a predecessor.
                                            if (entryNode.Phis.Length != 1 || entryNode.Phis[0].Links.Length != 0)
                                                throw new Exception("Catch handler should start with an unlinked phi node");

                                            HighSsaRegister exceptionReg = entryNode.Phis[0].Dest;

                                            CodeLocationTag codeLoc = entryNode.Instructions[0].CodeLocation;

                                            List<HighInstruction> catchLandingInstrs = new List<HighInstruction>();
                                            HighSsaRegister catchDest = new HighSsaRegister(HighValueType.ReferenceValue, exceptionReg.Type, null);
                                            catchLandingInstrs.Add(new Clarity.Rpa.Instructions.CatchInstruction(codeLoc, catchDest, exceptionReg.Type));
                                            catchLandingInstrs.Add(new Clarity.Rpa.Instructions.BranchInstruction(codeLoc, hdlRegion.EntryNode));

                                            HighCfgNode landingNode = new HighCfgNode(new HighCfgNodeHandle[0], new HighPhi[0], catchLandingInstrs.ToArray());

                                            HighCfgNodeHandle landingHandle = new HighCfgNodeHandle(landingNode);

                                            entryNode.Predecessors = new HighCfgNodeHandle[] { landingHandle };
                                            entryNode.Phis[0].Links = new HighPhiLink[] { new HighPhiLink(landingHandle, catchDest) };

                                            HighRegion replacementRegion = new HighRegion(landingHandle);

                                            catchHandlers.Add(new HighCatchHandler(
                                                RpaTagFactory.CreateTypeTag(handlerRegion.ExceptionType),
                                                replacementRegion
                                                ));
                                        }
                                        break;
                                    case ExceptionHandlingCluster.ClusterTypeEnum.TryFault:
                                    case ExceptionHandlingCluster.ClusterTypeEnum.TryFinally:
                                        otherRegions.Add(hdlRegion);
                                        break;
                                    default:
                                        throw new Exception();
                                }
                            }

                            List<Clarity.Rpa.HighEscapePathTerminator> terminators = new List<Clarity.Rpa.HighEscapePathTerminator>();
                            foreach (uint escapePath in cluster.EscapePaths)
                            {
                                CfgNode targetNode;
                                if (m_region.EscapeTerminators.TryGetValue(escapePath, out targetNode))
                                {
                                    Clarity.Rpa.HighCfgNodeHandle terminatorNode = InternHighCfgNode(targetNode);
                                    terminators.Add(new Clarity.Rpa.HighEscapePathTerminator(escapePath, terminatorNode));
                                }
                            }

                            Clarity.Rpa.HighProtectedRegion protRegion;
                            switch (cluster.ClusterType)
                            {
                                case ExceptionHandlingCluster.ClusterTypeEnum.TryCatch:
                                    protRegion = new Clarity.Rpa.HighTryCatchRegion(tryRegion, catchHandlers.ToArray());
                                    break;
                                case ExceptionHandlingCluster.ClusterTypeEnum.TryFault:
                                    protRegion = new Clarity.Rpa.HighTryFaultRegion(tryRegion, otherRegions[0]);
                                    break;
                                case ExceptionHandlingCluster.ClusterTypeEnum.TryFinally:
                                    protRegion = new Clarity.Rpa.HighTryFinallyRegion(tryRegion, otherRegions[0]);
                                    break;
                                default:
                                    throw new Exception();
                            }

                            Clarity.Rpa.HighEHCluster highCluster = new Clarity.Rpa.HighEHCluster(protRegion, terminators.ToArray());

                            outInstructions.Add(new Clarity.Rpa.Instructions.EnterProtectedBlockInstruction(
                                midInstr.CodeLocation,
                                highCluster
                                ));
                        }
                        break;
                    case MidInstruction.OpcodeEnum.ExitFinally:
                        outInstructions.Add(new Clarity.Rpa.Instructions.ReturnInstruction(midInstr.CodeLocation));
                        break;
                    case MidInstruction.OpcodeEnum.BindDelegate:
                        {
                            SsaRegister objReg = midInstr.RegArg;
                            CppMethodSpec methodSpec = (CppMethodSpec)midInstr.RegArg2.ConstantValue;
                            SsaRegister destReg = midInstr.RegArg3;

                            Clarity.Rpa.MethodSignatureTag sigTag = RpaTagFactory.CreateMethodSignature(methodSpec.CppMethod.MethodSignature);

                            Clarity.Rpa.HighSsaRegister destRegHigh = InternSsaRegister(destReg);

                            Clarity.Rpa.MethodSlotType slotType;

                            if (methodSpec.CppMethod.Static)
                                slotType = Clarity.Rpa.MethodSlotType.Static;
                            else
                            {
                                objReg = EmitPassiveConversion(midInstr.CodeLocation, objReg, methodSpec.CppMethod.DeclaredInClassSpec, outline, outInstructions);
                                if (midInstr.RegArg2.VType.ValType == VType.ValTypeEnum.DelegateSimpleMethod)
                                    slotType = Clarity.Rpa.MethodSlotType.Instance;
                                else if (midInstr.RegArg2.VType.ValType == VType.ValTypeEnum.DelegateVirtualMethod)
                                    slotType = Clarity.Rpa.MethodSlotType.Virtual;
                                else
                                    throw new ArgumentException();
                            }

                            Clarity.Rpa.MethodSpecTag methodSpecTag = RpaTagFactory.CreateMethodSpec(slotType, methodSpec);

                            if (methodSpec.CppMethod.Static)
                            {
                                outInstructions.Add(new Clarity.Rpa.Instructions.BindStaticDelegateInstruction(
                                    midInstr.CodeLocation,
                                    InternSsaRegister(destReg),
                                    methodSpecTag
                                    ));
                            }
                            else if (midInstr.RegArg2.VType.ValType == VType.ValTypeEnum.DelegateSimpleMethod)
                            {
                                outInstructions.Add(new Clarity.Rpa.Instructions.BindInstanceDelegateInstruction(
                                    midInstr.CodeLocation,
                                    InternSsaRegister(destReg),
                                    InternSsaRegister(objReg),
                                    methodSpecTag
                                    ));
                            }
                            else if (midInstr.RegArg2.VType.ValType == VType.ValTypeEnum.DelegateVirtualMethod)
                            {
                                outInstructions.Add(new Clarity.Rpa.Instructions.BindVirtualDelegateInstruction(
                                    midInstr.CodeLocation,
                                    InternSsaRegister(destReg),
                                    InternSsaRegister(objReg),
                                    methodSpecTag
                                    ));
                            }
                        }
                        break;
                    default:
                        throw new ArgumentException("Invalid mid IL opcode");
                }
            }

            if (cfgNode.FallThroughEdge != null && !fallthroughMerged)
            {
                CppTranslatedOutboundEdge outEdge = InternOutboundEdge(cfgNode, cfgNode.FallThroughEdge);

                outInstructions.Add(new Clarity.Rpa.Instructions.BranchInstruction(cfgNode.FallThroughEdge.CodeLocation, outEdge.NextNode));
            }

            List<HighCfgNodeHandle> highPreds = new List<HighCfgNodeHandle>();
            foreach (CppTranslatedOutboundEdge predEdge in predecessorEdges)
                highPreds.Add(predEdge.PrevNode);

            highNode.Value = new HighCfgNode(highPreds.ToArray(), outPhis.ToArray(), outInstructions.ToArray());
        }
Beispiel #8
0
        public void Compile()
        {
            CppMethod method = m_cfgNode.CfgBuilder.CppMethod;
            VReg[] locals = m_cfgNode.CfgBuilder.Locals;
            VReg[] args = m_cfgNode.CfgBuilder.Args;
            CfgBuilder cfgBuilder = m_cfgNode.CfgBuilder;

            CLR.CIL.Method cilMethod = method.MethodDef.Method;
            List<MidInstruction> midInstrs = new List<MidInstruction>();
            bool[] everTargeted = new bool[cilMethod.Instructions.Length];

            EvalStackTracker stackTracker = new EvalStackTracker();

            Clarity.Rpa.CodeLocationTag codeLocation = new Clarity.Rpa.CodeLocationTag(method.VtableSlotTag, cilMethod.OffsetForInstruction(m_cfgNode.StartInstr));

            foreach (VType entryType in m_cfgNode.EntryTypes)
            {
                SsaRegister reg = stackTracker.NewReg(entryType);
                reg.TrySpill();
                stackTracker.Push(reg);

                midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.EntryReg, codeLocation, reg));
            }

            int firstInstr = m_cfgNode.StartInstr;
            int nextInstr = firstInstr;

            bool isTerminalEdge = false;
            while (!isTerminalEdge)
            {
                int instrNum = nextInstr++;
                codeLocation = new Clarity.Rpa.CodeLocationTag(method.VtableSlotTag, cilMethod.OffsetForInstruction(instrNum));

                if (instrNum != firstInstr && cfgBuilder.InstrIsJumpTarget(instrNum))
                {
                    CfgOutboundEdgePrototype edgeProto = stackTracker.GenerateCfgEdge();
                    OutputFallThroughEdge = new CfgOutboundEdge(codeLocation, cfgBuilder.AddCfgTarget(this, instrNum, edgeProto.OutboundTypes), edgeProto);
                    break;
                }

                if (cfgBuilder.EhClusters.ContainsKey((uint)instrNum))
                {
                    if (stackTracker.Depth != 0)
                        throw new ParseFailedException("Stack not empty at protected block entry point");
                    ExceptionHandlingCluster cluster = cfgBuilder.EhClusters[(uint)instrNum];
                    midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.EnterProtectedBlock, codeLocation, cluster));

                    VType[] emptyTypesList = new VType[0];

                    foreach (uint escapePath in cluster.EscapePaths)
                    {
                        if (escapePath >= m_ehRegion.StartInstr && escapePath <= m_ehRegion.EndInstr)
                        {
                            CfgNode targetNode = cfgBuilder.AddCfgTarget(this, (int)escapePath, emptyTypesList);
                            m_ehRegion.AddLeaveTarget(escapePath, targetNode);
                        }
                        else
                            m_ehRegion.AddEscapePath(escapePath);
                    }

                    break;
                }

                CLR.CIL.HLInstruction instr = cilMethod.Instructions[instrNum];

                switch (instr.Opcode)
                {
                    case CLR.CIL.HLOpcode.nop:
                        break;
                    case CLR.CIL.HLOpcode.newobj:
                        {
                            CppMethodSpec ctorMethodSpec = CppBuilder.ResolveMethodDefOrRef((CLRTableRow)instr.Arguments.ObjValue);

                            if (ctorMethodSpec.GenericParameters != null)
                                throw new ArgumentException();

                            CppMethod ctorMethod = ctorMethodSpec.CppMethod;

                            int numParams = ctorMethod.MethodSignature.ParamTypes.Length;

                            CLRTypeSpec instanceSpec = ctorMethod.DeclaredInClassSpec;

                            VType.ValTypeEnum resultValType = CppCilExporter.ValTypeForTypeSpec(m_cppBuilder, instanceSpec);
                            SsaRegister instanceReg = stackTracker.NewReg(new VType(resultValType, instanceSpec));

                            // Allocate the instance into an SSA reg
                            midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.LivenReg, codeLocation, instanceReg));

                            stackTracker.SpillStack();

                            bool isDelegate = false;

                            if (numParams == 2)
                            {
                                SsaRegister param2 = stackTracker.GetFromTop(0);
                                if (param2.VType.ValType == VType.ValTypeEnum.DelegateSimpleMethod ||
                                    param2.VType.ValType == VType.ValTypeEnum.DelegateVirtualMethod)
                                    isDelegate = true;
                            }

                            // Determine the parameter set.
                            // Unlike when making calls, we don't spill here because we already spilled during the AllocObject call
                            SsaRegister[] passedParams = new SsaRegister[numParams];
                            for (int p = 0; p < numParams; p++)
                            {
                                SsaRegister paramReg = stackTracker.GetFromTop(numParams - 1 - p);
                                passedParams[p] = paramReg;
                            }

                            CppClass cls = CppBuilder.GetCachedClass(instanceSpec);
                            SsaRegister valueOutRegister = null;
                            VReg tempLocal = null;
                            if (cls.IsValueType)
                            {
                                valueOutRegister = instanceReg;

                                tempLocal = GetTemporary(new VType(VType.ValTypeEnum.ValueValue, instanceSpec));

                                SsaRegister tempClearAddr = new SsaRegister(new VType(VType.ValTypeEnum.ManagedPtr, instanceSpec));
                                midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.LivenReg, codeLocation, tempClearAddr));
                                midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.LoadRegA, codeLocation, tempLocal, tempClearAddr));
                                midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.ZeroFillPtr, codeLocation, tempClearAddr));
                                midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.KillReg, codeLocation, tempClearAddr));

                                SsaRegister tempUseAddr = new SsaRegister(new VType(VType.ValTypeEnum.ManagedPtr, instanceSpec));

                                midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.LivenReg, codeLocation, tempUseAddr));
                                midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.LoadRegA, codeLocation, tempLocal, tempUseAddr));

                                instanceReg = tempUseAddr;
                            }

                            if (isDelegate)
                                midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.BindDelegate, codeLocation, passedParams[0], passedParams[1], instanceReg));
                            else
                            {
                                // Allocate object
                                if (tempLocal == null)
                                    midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.AllocObject, codeLocation, instanceReg, instanceSpec));
                                // Make the actual ctor call
                                midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.CallConstructor, codeLocation, ctorMethodSpec, null, null, instanceReg, passedParams));
                            }

                            // Kill all of the parameter registers
                            for (int p = 0; p < numParams; p++)
                                midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.KillReg, codeLocation, stackTracker.Pop()));

                            if (valueOutRegister != null)
                            {
                                midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.LoadReg_Value, codeLocation, tempLocal, valueOutRegister));
                                midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.KillReg, codeLocation, instanceReg));

                                instanceReg = valueOutRegister;
                            }

                            // Push the return value on to the stack
                            stackTracker.Push(instanceReg);
                        }
                        break;
                    case CLR.CIL.HLOpcode.ret:
                        if (stackTracker.Depth == 1)
                        {
                            SsaRegister returnValue = stackTracker.Pop();
                            midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.ReturnValue, codeLocation, returnValue, method.MethodSignature.RetType));
                            midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.KillReg, codeLocation, returnValue));
                        }
                        else if (stackTracker.Depth == 0)
                            midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.Return, codeLocation));
                        else
                            throw new ArgumentException();

                        isTerminalEdge = true;
                        break;
                    case CLR.CIL.HLOpcode.ldarg:
                        {
                            VReg argReg = args[instr.Arguments.U32Value];

                            SsaRegister evalReg = stackTracker.NewReg(argReg.VType);

                            midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.LivenReg, codeLocation, evalReg));

                            string loadSrc = argReg.SlotName;
                            switch (argReg.VType.ValType)
                            {
                                case VType.ValTypeEnum.ManagedPtr:
                                    midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.LoadReg_ManagedPtr, codeLocation, argReg, evalReg));
                                    break;
                                case VType.ValTypeEnum.ReferenceValue:
                                case VType.ValTypeEnum.ValueValue:
                                    midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.LoadReg_Value, codeLocation, argReg, evalReg));
                                    break;
                                default:
                                    throw new ArgumentException();
                            }

                            stackTracker.Push(evalReg);
                        }
                        break;
                    case CLR.CIL.HLOpcode.ldarga:
                        {
                            VReg argReg = args[instr.Arguments.U32Value];

                            VType outEvalType;
                            MidInstruction.OpcodeEnum opcode;

                            switch (argReg.VType.ValType)
                            {
                                case VType.ValTypeEnum.ReferenceValue:
                                case VType.ValTypeEnum.ValueValue:
                                    opcode = MidInstruction.OpcodeEnum.LoadArgA_Value;
                                    outEvalType = new VType(VType.ValTypeEnum.ManagedPtr, argReg.VType.TypeSpec);
                                    break;
                                default:
                                    throw new ArgumentException();
                            }

                            SsaRegister evalReg = stackTracker.NewReg(outEvalType);
                            midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.LivenReg, codeLocation, evalReg));
                            midInstrs.Add(new MidInstruction(opcode, codeLocation, argReg, evalReg));

                            stackTracker.Push(evalReg);
                        }
                        break;
                    case CLR.CIL.HLOpcode.starg:
                        {
                            VReg argReg = args[instr.Arguments.U32Value];
                            SsaRegister valueReg = stackTracker.Pop();

                            switch (valueReg.VType.ValType)
                            {
                                case VType.ValTypeEnum.ConstantReference:
                                case VType.ValTypeEnum.ReferenceValue:
                                case VType.ValTypeEnum.Null:
                                case VType.ValTypeEnum.ValueValue:
                                case VType.ValTypeEnum.ConstantValue:
                                    midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.StoreReg_Value, codeLocation, argReg, valueReg));
                                    break;
                                case VType.ValTypeEnum.ManagedPtr:
                                    midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.StoreReg_ManagedPtr, codeLocation, argReg, valueReg));
                                    break;
                                default:
                                    throw new ArgumentException();
                            }

                            midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.KillReg, codeLocation, valueReg));
                        }
                        break;
                    case CLR.CIL.HLOpcode.call:
                    case CLR.CIL.HLOpcode.callvirt:
                        {
                            bool devirtualize = false;

                            CLRTypeSpec constraintType = null;
                            if (instrNum != 0)
                            {
                                CLR.CIL.HLInstruction prevInstr = cilMethod.Instructions[instrNum - 1];
                                if (prevInstr.Opcode == CLR.CIL.HLOpcode.constrained_pfx)
                                    constraintType = m_cppBuilder.Assemblies.InternTypeDefOrRefOrSpec((CLRTableRow)prevInstr.Arguments.ObjValue);
                            }

                            CppMethodSpec calledMethodSpec = CppBuilder.ResolveMethodDefOrRef((CLRTableRow)instr.Arguments.ObjValue);
                            CppMethod calledMethod = calledMethodSpec.CppMethod;

                            if (!calledMethod.Virtual)
                                devirtualize = true;

                            int numParams = calledMethod.MethodSignature.ParamTypes.Length;

                            SsaRegister returnReg = null;
                            SsaRegister thisReg = null;

                            if (!CppBuilder.TypeSpecIsVoid(calledMethod.MethodSignature.RetType))
                            {
                                CLRTypeSpec retType = calledMethod.MethodSignature.RetType;
                                returnReg = stackTracker.NewReg(new VType(CppCilExporter.ValTypeForTypeSpec(m_cppBuilder, retType), retType));
                                midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.LivenReg, codeLocation, returnReg));
                            }

                            if (!calledMethod.Static)
                                thisReg = stackTracker.GetFromTop(numParams);

                            MidInstruction.OpcodeEnum midOpcode;
                            if (instr.Opcode == CLR.CIL.HLOpcode.call || devirtualize)
                            {
                                if (constraintType != null)
                                    midOpcode = MidInstruction.OpcodeEnum.ConstrainedCallMethod;
                                else
                                    midOpcode = MidInstruction.OpcodeEnum.CallMethod;
                            }
                            else if (instr.Opcode == CLR.CIL.HLOpcode.callvirt)
                            {
                                if (constraintType != null)
                                    midOpcode = MidInstruction.OpcodeEnum.ConstrainedCallVirtualMethod;
                                else
                                {
                                    midOpcode = MidInstruction.OpcodeEnum.CallVirtualMethod;
                                    if (calledMethod.NumGenericParameters > 0)
                                    {
                                        if (calledMethod.DeclaredInClass.Semantics == CLRTypeDefRow.TypeSemantics.Interface)
                                            throw new NotSupportedException(method.DeclaredInClassSpec.ToString() + "." + method.Name + " contains an unconstrained call to an interface virtual method, which is not supported.");
                                        else if (calledMethod.DeclaredInClass.Semantics == CLRTypeDefRow.TypeSemantics.Class)
                                            midOpcode = MidInstruction.OpcodeEnum.CallMethod;
                                        else
                                            throw new ArgumentException();
                                    }
                                }
                            }
                            else
                                throw new ArgumentException();

                            SsaRegister[] passedParams = new SsaRegister[numParams];
                            for (int p = 0; p < numParams; p++)
                            {
                                SsaRegister paramReg = stackTracker.GetFromTop(numParams - 1 - p);
                                passedParams[p] = paramReg;
                            }

                            // Pop the parameters first so that we don't have to spill them into the caller frame.
                            // They won't actually be deadened until after the call.
                            stackTracker.Pop(numParams);

                            stackTracker.SpillStack();

                            // Emit the actual call
                            midInstrs.Add(new MidInstruction(midOpcode, codeLocation, calledMethodSpec, constraintType, returnReg, thisReg, passedParams));

                            // Emit parameter deadens (in stack order)
                            for (int p = 0; p < numParams; p++)
                                midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.KillReg, codeLocation, passedParams[numParams - 1 - p]));

                            // Emit "this" deaden and remove it from the stack
                            if (thisReg != null)
                            {
                                midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.KillReg, codeLocation, thisReg));
                                if (stackTracker.Pop() != thisReg)
                                    throw new ArgumentException();
                            }

                            // Push the return value
                            if (returnReg != null)
                                stackTracker.Push(returnReg);
                        }
                        break;
                    case CLR.CIL.HLOpcode.stloc:
                        {
                            SsaRegister evalVar = stackTracker.Pop();
                            VReg localVar = locals[instr.Arguments.U32Value];
                            switch (localVar.VType.ValType)
                            {
                                case VType.ValTypeEnum.ValueValue:
                                case VType.ValTypeEnum.ReferenceValue:
                                    midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.StoreReg_Value, codeLocation, localVar, evalVar));
                                    break;
                                case VType.ValTypeEnum.ManagedPtr:
                                    midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.StoreReg_ManagedPtr, codeLocation, localVar, evalVar));
                                    break;
                                default:
                                    throw new ArgumentException();
                            }
                            midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.KillReg, codeLocation, evalVar));
                        }
                        break;
                    case CLR.CIL.HLOpcode.ldloc:
                        {
                            VReg localVar = locals[instr.Arguments.U32Value];
                            SsaRegister evalReg = stackTracker.NewReg(localVar.VType);

                            midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.LivenReg, codeLocation, evalReg));

                            switch (localVar.VType.ValType)
                            {
                                case VType.ValTypeEnum.ManagedPtr:
                                    midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.LoadReg_ManagedPtr, codeLocation, localVar, evalReg));
                                    break;
                                case VType.ValTypeEnum.ValueValue:
                                case VType.ValTypeEnum.ReferenceValue:
                                    midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.LoadReg_Value, codeLocation, localVar, evalReg));
                                    break;
                                default:
                                    throw new ArgumentException();
                            }

                            stackTracker.Push(evalReg);
                        }
                        break;
                    case CLR.CIL.HLOpcode.ldloca:
                        {
                            VReg localVar = locals[instr.Arguments.U32Value];
                            SsaRegister evalReg = stackTracker.NewReg(new VType(VType.ValTypeEnum.ManagedPtr, localVar.VType.TypeSpec));

                            midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.LivenReg, codeLocation, evalReg));

                            switch (localVar.VType.ValType)
                            {
                                case VType.ValTypeEnum.ValueValue:
                                case VType.ValTypeEnum.ReferenceValue:
                                    midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.LoadRegA, codeLocation, localVar, evalReg));
                                    break;
                                default:
                                    throw new ArgumentException();
                            }

                            stackTracker.Push(evalReg);
                        }
                        break;
                    case CLR.CIL.HLOpcode.bne:    // [.un]
                        {
                            SsaRegister value2 = stackTracker.Pop();
                            SsaRegister value1 = stackTracker.Pop();

                            bool isRefComparison = IsComparisonReference(value1.VType, value2.VType);

                            CfgOutboundEdgePrototype edgeProto = stackTracker.GenerateCfgEdge();

                            CfgNode targetNode = cfgBuilder.AddCfgTarget(this, (int)instr.Arguments.U32Value, edgeProto.OutboundTypes);
                            CfgNode fallThroughNode = cfgBuilder.AddCfgTarget(this, nextInstr, edgeProto.OutboundTypes);

                            midInstrs.Add(new MidInstruction(isRefComparison ? MidInstruction.OpcodeEnum.bne_ref : MidInstruction.OpcodeEnum.bne_val, codeLocation, value1, value2, new CfgOutboundEdge(codeLocation, targetNode, edgeProto), (instr.Flags & CLR.CIL.HLOpFlags.Un) != 0));

                            midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.KillReg, codeLocation, value2));
                            midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.KillReg, codeLocation, value1));

                            OutputFallThroughEdge = new CfgOutboundEdge(codeLocation, fallThroughNode, edgeProto);

                            isTerminalEdge = true;
                        }
                        break;
                    case CLR.CIL.HLOpcode.beq:    // [.un]
                        {
                            SsaRegister value2 = stackTracker.Pop();
                            SsaRegister value1 = stackTracker.Pop();

                            CfgOutboundEdgePrototype edgeProto = stackTracker.GenerateCfgEdge();

                            bool isRefComparison = IsComparisonReference(value1.VType, value2.VType);

                            CfgNode targetNode = cfgBuilder.AddCfgTarget(this, (int)instr.Arguments.U32Value, edgeProto.OutboundTypes);
                            CfgNode fallThroughNode = cfgBuilder.AddCfgTarget(this, nextInstr, edgeProto.OutboundTypes);

                            midInstrs.Add(new MidInstruction(isRefComparison ? MidInstruction.OpcodeEnum.beq_ref : MidInstruction.OpcodeEnum.beq_val, codeLocation, value1, value2, new CfgOutboundEdge(codeLocation, targetNode, edgeProto), (instr.Flags & CLR.CIL.HLOpFlags.Un) != 0));

                            midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.KillReg, codeLocation, value2));
                            midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.KillReg, codeLocation, value1));

                            OutputFallThroughEdge = new CfgOutboundEdge(codeLocation, fallThroughNode, edgeProto);

                            isTerminalEdge = true;
                        }
                        break;
                    case CLR.CIL.HLOpcode.bge:    // [.un]
                    case CLR.CIL.HLOpcode.bgt:    // [.un]
                    case CLR.CIL.HLOpcode.ble:    // [.un]
                    case CLR.CIL.HLOpcode.blt:    // [.un]
                        {
                            SsaRegister value2 = stackTracker.Pop();
                            SsaRegister value1 = stackTracker.Pop();

                            CfgOutboundEdgePrototype edgeProto = stackTracker.GenerateCfgEdge();

                            CfgNode targetNode = cfgBuilder.AddCfgTarget(this, (int)instr.Arguments.U32Value, edgeProto.OutboundTypes);
                            CfgNode fallThroughNode = cfgBuilder.AddCfgTarget(this, nextInstr, edgeProto.OutboundTypes);

                            midInstrs.Add(new MidInstruction(SimpleTranslateInstr(instr.Opcode), codeLocation, value1, value2, new CfgOutboundEdge(codeLocation, targetNode, edgeProto), (instr.Flags & CLR.CIL.HLOpFlags.Un) != 0));

                            midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.KillReg, codeLocation, value2));
                            midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.KillReg, codeLocation, value1));

                            OutputFallThroughEdge = new CfgOutboundEdge(codeLocation, fallThroughNode, edgeProto);

                            isTerminalEdge = true;
                        }
                        break;
                    case CLR.CIL.HLOpcode.br:
                        {
                            CfgOutboundEdgePrototype edgeProto = stackTracker.GenerateCfgEdge();
                            CfgNode targetNode = cfgBuilder.AddCfgTarget(this, (int)instr.Arguments.U32Value, edgeProto.OutboundTypes);
                            OutputFallThroughEdge = new CfgOutboundEdge(codeLocation, targetNode, edgeProto);
                            isTerminalEdge = true;
                        }
                        break;
                    case CLR.CIL.HLOpcode.leave:
                        {
                            uint escapePath = instr.Arguments.U32Value;
                            m_ehRegion.AddEscapePath(instr.Arguments.U32Value);

                            midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.Leave, codeLocation, escapePath));

                            while (stackTracker.Depth > 0)
                                midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.KillReg, codeLocation, stackTracker.Pop()));
                            isTerminalEdge = true;
                        }
                        break;
                    case CLR.CIL.HLOpcode.ceq:
                        {
                            SsaRegister value2 = stackTracker.Pop();
                            SsaRegister value1 = stackTracker.Pop();
                            SsaRegister returnValue = stackTracker.NewReg(new VType(VType.ValTypeEnum.ValueValue, m_commonTypeLookup.Boolean));

                            bool isRefComparison = IsComparisonReference(value1.VType, value2.VType);

                            midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.LivenReg, codeLocation, returnValue));
                            midInstrs.Add(new MidInstruction(isRefComparison ? MidInstruction.OpcodeEnum.ceq_ref : MidInstruction.OpcodeEnum.ceq_numeric, codeLocation, returnValue, value1, value2, false));

                            midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.KillReg, codeLocation, value2));
                            midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.KillReg, codeLocation, value1));

                            stackTracker.Push(returnValue);
                        }
                        break;
                    case CLR.CIL.HLOpcode.cgt:    // [.un]
                        {
                            SsaRegister value2 = stackTracker.Pop();
                            SsaRegister value1 = stackTracker.Pop();
                            SsaRegister returnValue = stackTracker.NewReg(new VType(VType.ValTypeEnum.ValueValue, m_commonTypeLookup.Boolean));

                            // Per III.4, cgt.un is used for reference non-equality checks.
                            // For some reason there isn't a cne instruction...
                            bool isRefComparison = IsComparisonReference(value1.VType, value2.VType);

                            midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.LivenReg, codeLocation, returnValue));
                            midInstrs.Add(new MidInstruction(isRefComparison ? MidInstruction.OpcodeEnum.cne_ref : MidInstruction.OpcodeEnum.cgt, codeLocation, returnValue, value1, value2, (instr.Flags & CLR.CIL.HLOpFlags.Un) != 0));

                            midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.KillReg, codeLocation, value2));
                            midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.KillReg, codeLocation, value1));

                            stackTracker.Push(returnValue);
                        }
                        break;
                    case CLR.CIL.HLOpcode.clt:    // [.un]
                        {
                            SsaRegister value2 = stackTracker.Pop();
                            SsaRegister value1 = stackTracker.Pop();
                            SsaRegister returnValue = stackTracker.NewReg(new VType(VType.ValTypeEnum.ValueValue, m_commonTypeLookup.Boolean));

                            midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.LivenReg, codeLocation, returnValue));
                            midInstrs.Add(new MidInstruction(SimpleTranslateInstr(instr.Opcode), codeLocation, returnValue, value1, value2, (instr.Flags & CLR.CIL.HLOpFlags.Un) != 0));

                            midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.KillReg, codeLocation, value2));
                            midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.KillReg, codeLocation, value1));

                            stackTracker.Push(returnValue);
                        }
                        break;

                    case CLR.CIL.HLOpcode.ldc:
                        {
                            SsaRegister resultReg;

                            switch (instr.Arguments.ArgsType)
                            {
                                case CLR.CIL.HLArguments.ArgsTypeEnum.I32:
                                    resultReg = SsaRegister.Constant(new VType(VType.ValTypeEnum.ConstantValue, m_commonTypeLookup.I32, instr.Arguments.S32Value));
                                    break;
                                case CLR.CIL.HLArguments.ArgsTypeEnum.I64:
                                    resultReg = SsaRegister.Constant(new VType(VType.ValTypeEnum.ConstantValue, m_commonTypeLookup.I64, instr.Arguments.S64Value));
                                    break;
                                case CLR.CIL.HLArguments.ArgsTypeEnum.F32:
                                    resultReg = SsaRegister.Constant(new VType(VType.ValTypeEnum.ConstantValue, m_commonTypeLookup.F32, instr.Arguments.F32Value));
                                    break;
                                case CLR.CIL.HLArguments.ArgsTypeEnum.F64:
                                    resultReg = SsaRegister.Constant(new VType(VType.ValTypeEnum.ConstantValue, m_commonTypeLookup.F64, instr.Arguments.F64Value));
                                    break;
                                default:
                                    throw new ArgumentException();
                            }

                            midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.LivenReg, codeLocation, resultReg));
                            stackTracker.Push(resultReg);
                        }
                        break;
                    case CLR.CIL.HLOpcode.brfalse:
                    case CLR.CIL.HLOpcode.brtrue:
                        {
                            SsaRegister v = stackTracker.Pop();

                            CfgOutboundEdgePrototype edgeProto = stackTracker.GenerateCfgEdge();
                            CfgNode targetNode = cfgBuilder.AddCfgTarget(this, (int)instr.Arguments.U32Value, edgeProto.OutboundTypes);
                            CfgNode fallThroughNode = cfgBuilder.AddCfgTarget(this, nextInstr, edgeProto.OutboundTypes);

                            MidInstruction.OpcodeEnum opcode;
                            switch (v.VType.ValType)
                            {
                                case VType.ValTypeEnum.ConstantValue:
                                case VType.ValTypeEnum.ValueValue:
                                    if (instr.Opcode == CLR.CIL.HLOpcode.brtrue)
                                        opcode = MidInstruction.OpcodeEnum.brnotzero;
                                    else
                                        opcode = MidInstruction.OpcodeEnum.brzero;
                                    break;
                                case VType.ValTypeEnum.ConstantReference:
                                case VType.ValTypeEnum.Null:
                                case VType.ValTypeEnum.ReferenceValue:
                                    if (instr.Opcode == CLR.CIL.HLOpcode.brtrue)
                                        opcode = MidInstruction.OpcodeEnum.brnotnull;
                                    else
                                        opcode = MidInstruction.OpcodeEnum.brnull;
                                    break;
                                default:
                                    throw new Exception("Unsupported stack op type passed to brtrue or brfalse");
                            }
                            midInstrs.Add(new MidInstruction(opcode, codeLocation, v, new CfgOutboundEdge(codeLocation, targetNode, edgeProto)));
                            midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.KillReg, codeLocation, v));

                            OutputFallThroughEdge = new CfgOutboundEdge(codeLocation, fallThroughNode, edgeProto);

                            isTerminalEdge = true;
                        }
                        break;

                    case CLR.CIL.HLOpcode.ldnull:
                        {
                            SsaRegister constReg = SsaRegister.Constant(new VType(VType.ValTypeEnum.Null, m_commonTypeLookup.Object));
                            midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.LivenReg, codeLocation, constReg));
                            stackTracker.Push(constReg);
                        }
                        break;

                    case CLR.CIL.HLOpcode.@throw:
                        {
                            SsaRegister ex = stackTracker.Pop();
                            midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.Throw, codeLocation, ex));
                            midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.KillReg, codeLocation, ex));
                            isTerminalEdge = true;
                        }
                        break;

                    case CLR.CIL.HLOpcode.newarr:
                        {
                            CLRTableRow contentsType = (CLRTableRow)instr.Arguments.ObjValue;
                            CLRTypeSpec contentsTypeSpec = m_cppBuilder.Assemblies.InternTypeDefOrRefOrSpec(contentsType);

                            CLRTypeSpecSZArray arrayTS = new CLRTypeSpecSZArray(contentsTypeSpec);

                            SsaRegister resultReg = stackTracker.NewReg(new VType(VType.ValTypeEnum.ReferenceValue, arrayTS));

                            // It's OK to pop num elems here since, as an integer, we don't care if it doesn't spill
                            SsaRegister numElemsReg = stackTracker.Pop();

                            midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.LivenReg, codeLocation, resultReg));
                            stackTracker.SpillStack();
                            midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.NewSZArray, codeLocation, resultReg, numElemsReg));
                            midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.KillReg, codeLocation, numElemsReg));
                            stackTracker.Push(resultReg);
                        }
                        break;
                    case CLR.CIL.HLOpcode.ldfld:
                        {
                            CppField field = ResolveField((CLRTableRow)instr.Arguments.ObjValue);
                            CLRTypeSpec fieldValueSpec = field.Type;
                            VType.ValTypeEnum valType = CppCilExporter.ValTypeForTypeSpec(m_cppBuilder, fieldValueSpec);

                            SsaRegister valueReg = stackTracker.NewReg(new VType(valType, fieldValueSpec));
                            SsaRegister objReg = stackTracker.Pop();

                            VType.ValTypeEnum objValType = objReg.VType.ValType;

                            midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.LivenReg, codeLocation, valueReg));

                            MidInstruction.OpcodeEnum opcode;
                            if (objValType == VType.ValTypeEnum.ManagedPtr)
                                opcode = MidInstruction.OpcodeEnum.LoadField_ManagedPtr;
                            else if (objValType == VType.ValTypeEnum.ReferenceValue)
                                opcode = MidInstruction.OpcodeEnum.LoadField_Object;
                            else if (objValType == VType.ValTypeEnum.ValueValue)
                                opcode = MidInstruction.OpcodeEnum.LoadField_Value;
                            else
                                throw new ArgumentException();

                            midInstrs.Add(new MidInstruction(opcode, codeLocation, objReg, valueReg, field.Name, field.DeclaredInClassSpec));
                            midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.KillReg, codeLocation, objReg));

                            stackTracker.Push(valueReg);
                        }
                        break;
                    case CLR.CIL.HLOpcode.ldflda:
                        {
                            SsaRegister objReg = stackTracker.Pop();

                            CppField field = ResolveField((CLRTableRow)instr.Arguments.ObjValue);
                            CLRTypeSpec fieldValueSpec = field.Type;
                            VType.ValTypeEnum valType = VType.ValTypeEnum.ManagedPtr;

                            bool isManagedPtr = (objReg.VType.ValType == VType.ValTypeEnum.ManagedPtr);

                            if (isManagedPtr)
                                valType = objReg.VType.ValType;

                            SsaRegister valueReg = stackTracker.NewReg(new VType(valType, fieldValueSpec));

                            VType.ValTypeEnum objValType = objReg.VType.ValType;

                            midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.LivenReg, codeLocation, valueReg));

                            MidInstruction.OpcodeEnum opcode;
                            if (isManagedPtr)
                                opcode = MidInstruction.OpcodeEnum.LoadFieldA_ManagedPtr;
                            else if (objValType == VType.ValTypeEnum.ReferenceValue)
                                opcode = MidInstruction.OpcodeEnum.LoadFieldA_Object;
                            else
                                throw new ArgumentException();

                            midInstrs.Add(new MidInstruction(opcode, codeLocation, objReg, valueReg, field.Name, field.DeclaredInClassSpec));
                            midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.KillReg, codeLocation, objReg));

                            stackTracker.Push(valueReg);
                        }
                        break;
                    case CLR.CIL.HLOpcode.ldsfld:
                        {
                            CppField field = ResolveField((CLRTableRow)instr.Arguments.ObjValue);
                            CLRTypeSpec fieldValueSpec = field.Type;
                            VType.ValTypeEnum valType = CppCilExporter.ValTypeForTypeSpec(m_cppBuilder, fieldValueSpec);

                            SsaRegister valueReg = stackTracker.NewReg(new VType(valType, fieldValueSpec));

                            midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.LivenReg, codeLocation, valueReg));
                            midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.LoadStaticField, codeLocation, valueReg, field.DeclaredInClassSpec, field.Name));

                            stackTracker.Push(valueReg);
                        }
                        break;

                    case CLR.CIL.HLOpcode.ldsflda:
                        {
                            CppField field = ResolveField((CLRTableRow)instr.Arguments.ObjValue);
                            CLRTypeSpec fieldValueSpec = field.Type;

                            SsaRegister valueReg = stackTracker.NewReg(new VType(VType.ValTypeEnum.ManagedPtr, fieldValueSpec));

                            midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.LivenReg, codeLocation, valueReg));
                            midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.LoadStaticFieldAddr, codeLocation, valueReg, field.DeclaredInClassSpec, field.Name));

                            stackTracker.Push(valueReg);
                        }
                        break;
                    case CLR.CIL.HLOpcode.ldelem:     // [.type]
                    case CLR.CIL.HLOpcode.ldelema:
                        {
                            // We just ignore the type suffix and get it from the array instead
                            SsaRegister indexReg = stackTracker.Pop();
                            SsaRegister arrayReg = stackTracker.Pop();

                            CLRTypeSpecSZArray arraySpec = (CLRTypeSpecSZArray)arrayReg.VType.TypeSpec;
                            CLRTypeSpec contentsSpec = arraySpec.SubType;

                            VType.ValTypeEnum valType;
                            MidInstruction.OpcodeEnum op;
                            if (instr.Opcode == CLR.CIL.HLOpcode.ldelem)
                            {
                                valType = CppCilExporter.ValTypeForTypeSpec(m_cppBuilder, contentsSpec);
                                op = MidInstruction.OpcodeEnum.LoadArrayElem;
                            }
                            else if (instr.Opcode == CLR.CIL.HLOpcode.ldelema)
                            {
                                valType = VType.ValTypeEnum.ManagedPtr;
                                op = MidInstruction.OpcodeEnum.LoadArrayElemAddr;
                            }
                            else
                                throw new ArgumentException();

                            SsaRegister contentsReg = stackTracker.NewReg(new VType(valType, contentsSpec));

                            midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.LivenReg, codeLocation, contentsReg));
                            midInstrs.Add(new MidInstruction(op, codeLocation, arrayReg, indexReg, contentsReg));
                            midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.KillReg, codeLocation, indexReg));
                            midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.KillReg, codeLocation, arrayReg));

                            stackTracker.Push(contentsReg);
                        }
                        break;
                    case CLR.CIL.HLOpcode.stelem:     // [.type]
                        {
                            // We just ignore the type suffix and get it from the array instead
                            SsaRegister valueReg = stackTracker.Pop();
                            SsaRegister indexReg = stackTracker.Pop();
                            SsaRegister arrayReg = stackTracker.Pop();

                            midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.StoreArrayElem, codeLocation, arrayReg, indexReg, valueReg));
                            midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.KillReg, codeLocation, valueReg));
                            midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.KillReg, codeLocation, indexReg));
                            midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.KillReg, codeLocation, arrayReg));
                        }
                        break;
                    case CLR.CIL.HLOpcode.stfld:
                        {
                            SsaRegister valueReg = stackTracker.Pop();
                            SsaRegister objReg = stackTracker.Pop();

                            CppField field = ResolveField((CLRTableRow)instr.Arguments.ObjValue);
                            CLRTypeSpec fieldValueSpec = field.Type;
                            VType.ValTypeEnum valType = CppCilExporter.ValTypeForTypeSpec(m_cppBuilder, fieldValueSpec);

                            VType.ValTypeEnum objValType = objReg.VType.ValType;

                            if (objValType == VType.ValTypeEnum.ManagedPtr)
                                midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.StoreField_ManagedPtr, codeLocation, objReg, valueReg, field.Name, field.DeclaredInClassSpec, fieldValueSpec));
                            else if (objValType == VType.ValTypeEnum.ReferenceValue)
                                midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.StoreField_Object, codeLocation, objReg, valueReg, field.Name, field.DeclaredInClassSpec, fieldValueSpec));
                            else
                                throw new ArgumentException();
                            midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.KillReg, codeLocation, valueReg));
                            midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.KillReg, codeLocation, objReg));
                        }
                        break;
                    case CLR.CIL.HLOpcode.stsfld:
                        {
                            SsaRegister valueReg = stackTracker.Pop();

                            CppField field = ResolveField((CLRTableRow)instr.Arguments.ObjValue);
                            CLRTypeSpec fieldValueSpec = field.Type;

                            midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.StoreStaticField, codeLocation, valueReg, field.DeclaredInClassSpec, fieldValueSpec, field.Name));
                            midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.KillReg, codeLocation, valueReg));
                        }
                        break;
                    case CLR.CIL.HLOpcode.ldstr:
                        {
                            SsaRegister constReg = SsaRegister.Constant(new VType(VType.ValTypeEnum.ConstantReference, m_commonTypeLookup.String, instr.Arguments.ObjValue));
                            midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.LivenReg, codeLocation, constReg));
                            stackTracker.Push(constReg);
                        }
                        break;
                    case CLR.CIL.HLOpcode.add:    // [.ovf][.un]
                    case CLR.CIL.HLOpcode.sub:    // [.ovf][.un]
                    case CLR.CIL.HLOpcode.mul:    // [.ovf][.un]
                    case CLR.CIL.HLOpcode.div:    // [.ovf][.un]
                    case CLR.CIL.HLOpcode.rem:    // [.ovf][.un]
                    case CLR.CIL.HLOpcode.and:
                    case CLR.CIL.HLOpcode.or:
                    case CLR.CIL.HLOpcode.xor:
                        {
                            SsaRegister value2 = stackTracker.Pop();
                            SsaRegister value1 = stackTracker.Pop();

                            CLRTypeSpec promoted1 = ArithPromoteValue(value1.VType.TypeSpec);
                            CLRTypeSpec promoted2 = ArithPromoteValue(value2.VType.TypeSpec);

                            MidInstruction.ArithEnum arithMode = ArithModeForBinaryNumericOp(m_commonTypeLookup, promoted1, promoted2);
                            if ((instr.Flags & CLR.CIL.HLOpFlags.Ovf) != 0)
                                arithMode |= MidInstruction.ArithEnum.Flags_Ovf;
                            if ((instr.Flags & CLR.CIL.HLOpFlags.Un) != 0)
                                arithMode |= MidInstruction.ArithEnum.Flags_Un;

                            CLRTypeSpec resultType = TypeSpecForArithModeResult(arithMode);

                            SsaRegister resultReg = stackTracker.NewReg(new VType(VType.ValTypeEnum.ValueValue, resultType));

                            midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.LivenReg, codeLocation, resultReg));
                            midInstrs.Add(new MidInstruction(SimpleTranslateInstr(instr.Opcode), codeLocation, value1, value2, resultReg, arithMode));
                            midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.KillReg, codeLocation, value2));
                            midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.KillReg, codeLocation, value1));

                            stackTracker.Push(resultReg);
                        }
                        break;
                    case CLR.CIL.HLOpcode.shl:
                    case CLR.CIL.HLOpcode.shr:    // [.un]
                        {
                            SsaRegister value2 = stackTracker.Pop();
                            SsaRegister value1 = stackTracker.Pop();

                            CLRTypeSpec promoted1 = ArithPromoteValue(value1.VType.TypeSpec);
                            CLRTypeSpec promoted2 = ArithPromoteValue(value2.VType.TypeSpec);

                            MidInstruction.ArithEnum arithMode = ArithModeForShiftOp(m_commonTypeLookup, promoted1, promoted2);
                            if ((instr.Flags & CLR.CIL.HLOpFlags.Un) != 0)
                                arithMode |= MidInstruction.ArithEnum.Flags_Un;

                            CLRTypeSpec resultType = TypeSpecForArithModeResult(arithMode);

                            SsaRegister resultReg = stackTracker.NewReg(new VType(VType.ValTypeEnum.ValueValue, resultType));

                            midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.LivenReg, codeLocation, resultReg));
                            midInstrs.Add(new MidInstruction(SimpleTranslateInstr(instr.Opcode), codeLocation, value1, value2, resultReg, arithMode));
                            midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.KillReg, codeLocation, value2));
                            midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.KillReg, codeLocation, value1));

                            stackTracker.Push(resultReg);
                        }
                        break;
                    case CLR.CIL.HLOpcode.neg:
                    case CLR.CIL.HLOpcode.not:
                        {
                            SsaRegister v = stackTracker.Pop();

                            CLRTypeSpec promoted = ArithPromoteValue(v.VType.TypeSpec);

                            MidInstruction.ArithEnum arithMode = ArithModeForUnaryOp(promoted);

                            CLRTypeSpec resultType = TypeSpecForArithModeResult(arithMode);

                            SsaRegister resultReg = stackTracker.NewReg(new VType(VType.ValTypeEnum.ValueValue, resultType));

                            midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.LivenReg, codeLocation, resultReg));
                            midInstrs.Add(new MidInstruction(SimpleTranslateInstr(instr.Opcode), codeLocation, v, resultReg, arithMode));
                            midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.KillReg, codeLocation, v));

                            stackTracker.Push(resultReg);
                        }
                        break;
                    case CLR.CIL.HLOpcode.isinst:
                        {
                            CLRTypeSpec type = m_cppBuilder.Assemblies.InternTypeDefOrRefOrSpec((CLRTableRow)instr.Arguments.ObjValue);

                            SsaRegister inputReg = stackTracker.Pop();
                            SsaRegister resultReg = stackTracker.NewReg(new VType(VType.ValTypeEnum.ReferenceValue, type));

                            midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.LivenReg, codeLocation, resultReg));
                            midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.TryConvertObj, codeLocation, inputReg, resultReg));
                            midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.KillReg, codeLocation, inputReg));

                            stackTracker.Push(resultReg);
                        }
                        break;
                    case CLR.CIL.HLOpcode.castclass:
                        {
                            CLRTypeSpec type = m_cppBuilder.Assemblies.InternTypeDefOrRefOrSpec((CLRTableRow)instr.Arguments.ObjValue);

                            SsaRegister inputReg = stackTracker.Pop();
                            SsaRegister resultReg = stackTracker.NewReg(new VType(VType.ValTypeEnum.ReferenceValue, type));

                            midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.LivenReg, codeLocation, resultReg));
                            midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.ConvertObj, codeLocation, inputReg, resultReg));
                            midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.KillReg, codeLocation, inputReg));

                            stackTracker.Push(resultReg);
                        }
                        break;
                    case CLR.CIL.HLOpcode.dup:
                        {
                            SsaRegister top = stackTracker.GetFromTop(0);
                            SsaRegister duplicate = stackTracker.NewReg(top.VType);

                            // WARNING: If you update this sequence, you must update ldvirtftn too!
                            midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.LivenReg, codeLocation, duplicate));
                            midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.DuplicateReg, codeLocation, top, duplicate));

                            stackTracker.Push(duplicate);
                        }
                        break;
                    case CLR.CIL.HLOpcode.ldind:  // (.type)
                    case CLR.CIL.HLOpcode.ldobj:
                        {
                            SsaRegister addr = stackTracker.Pop();
                            if (addr.VType.ValType != VType.ValTypeEnum.ManagedPtr)
                                throw new ArgumentException();

                            SsaRegister val = stackTracker.NewReg(new VType(CppCilExporter.ValTypeForTypeSpec(m_cppBuilder, addr.VType.TypeSpec), addr.VType.TypeSpec));

                            midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.LivenReg, codeLocation, val));
                            midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.LoadIndirect, codeLocation, addr, val));
                            midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.KillReg, codeLocation, addr));

                            stackTracker.Push(val);
                        }
                        break;
                    case CLR.CIL.HLOpcode.stind:  // (.type)
                    case CLR.CIL.HLOpcode.stobj:
                        {
                            SsaRegister val = stackTracker.Pop();
                            SsaRegister addr = stackTracker.Pop();
                            if (addr.VType.ValType != VType.ValTypeEnum.ManagedPtr)
                                throw new ArgumentException();

                            midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.StoreIndirect, codeLocation, addr, val));
                            midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.KillReg, codeLocation, val));
                            midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.KillReg, codeLocation, addr));
                        }
                        break;
                    case CLR.CIL.HLOpcode.pop:
                        {
                            SsaRegister val = stackTracker.Pop();
                            midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.KillReg, codeLocation, val));
                        }
                        break;
                    case CLR.CIL.HLOpcode.box:
                        {
                            CLRTableRow typeTok = (CLRTableRow)instr.Arguments.ObjValue;

                            stackTracker.SpillStack();
                            SsaRegister val = stackTracker.Pop();

                            if (val.VType.ValType != VType.ValTypeEnum.ConstantValue && val.VType.ValType != VType.ValTypeEnum.ValueValue)
                                throw new ArgumentException();

                            CLRTypeSpec valueTypeSpec = val.VType.TypeSpec;
                            if (valueTypeSpec is CLRTypeSpecGenericInstantiation)
                            {
                                CLRTypeSpecGenericInstantiation valueGI = (CLRTypeSpecGenericInstantiation)valueTypeSpec;
                                CLRTypeSpecClass valueGIClass = valueGI.GenericType;
                                CLRTypeDefRow typeDef = valueGIClass.TypeDef;
                                if (typeDef.ContainerClass == null && typeDef.TypeNamespace == "System" && typeDef.TypeName == "Nullable`1")
                                    valueTypeSpec = valueGI.ArgTypes[0];
                            }

                            SsaRegister boxed = stackTracker.NewReg(new VType(VType.ValTypeEnum.ReferenceValue, val.VType.TypeSpec));

                            midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.LivenReg, codeLocation, boxed));
                            midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.Box, codeLocation, val, boxed));
                            midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.KillReg, codeLocation, val));

                            stackTracker.Push(boxed);
                        }
                        break;
                    case CLR.CIL.HLOpcode.conv:   // [.ovf](.type)[.un]
                        {
                            CLRTypeSpec destType;
                            MidInstruction.ArithEnum arithMode;
                            switch (instr.TypeToken)
                            {
                                case CLR.CIL.HLOpType.I1:
                                    destType = m_commonTypeLookup.I8;
                                    arithMode = MidInstruction.ArithEnum.ArithType_Int32;
                                    break;
                                case CLR.CIL.HLOpType.I2:
                                    destType = m_commonTypeLookup.I16;
                                    arithMode = MidInstruction.ArithEnum.ArithType_Int32;
                                    break;
                                case CLR.CIL.HLOpType.I4:
                                    destType = m_commonTypeLookup.I32;
                                    arithMode = MidInstruction.ArithEnum.ArithType_Int32;
                                    break;
                                case CLR.CIL.HLOpType.I8:
                                    destType = m_commonTypeLookup.I64;
                                    arithMode = MidInstruction.ArithEnum.ArithType_Int64;
                                    break;
                                case CLR.CIL.HLOpType.U1:
                                    destType = m_commonTypeLookup.U8;
                                    arithMode = MidInstruction.ArithEnum.ArithType_Int32;
                                    break;
                                case CLR.CIL.HLOpType.U2:
                                    destType = m_commonTypeLookup.U16;
                                    arithMode = MidInstruction.ArithEnum.ArithType_Int32;
                                    break;
                                case CLR.CIL.HLOpType.U4:
                                    destType = m_commonTypeLookup.U32;
                                    arithMode = MidInstruction.ArithEnum.ArithType_Int32;
                                    break;
                                case CLR.CIL.HLOpType.U8:
                                    destType = m_commonTypeLookup.U64;
                                    arithMode = MidInstruction.ArithEnum.ArithType_Int64;
                                    break;
                                case CLR.CIL.HLOpType.R4:
                                    destType = m_commonTypeLookup.F32;
                                    arithMode = MidInstruction.ArithEnum.ArithType_Float32;
                                    break;
                                case CLR.CIL.HLOpType.R:    // Used by conv.r.un
                                case CLR.CIL.HLOpType.R8:
                                    destType = m_commonTypeLookup.F64;
                                    arithMode = MidInstruction.ArithEnum.ArithType_Float64;
                                    break;
                                case CLR.CIL.HLOpType.I:
                                    destType = m_commonTypeLookup.I;
                                    arithMode = MidInstruction.ArithEnum.ArithType_NativeInt;
                                    break;
                                case CLR.CIL.HLOpType.U:
                                    destType = m_commonTypeLookup.U;
                                    arithMode = MidInstruction.ArithEnum.ArithType_NativeInt;
                                    break;
                                default:
                                    throw new ArgumentException();
                            }

                            if ((instr.Flags & CLR.CIL.HLOpFlags.Ovf) != 0)
                                arithMode |= MidInstruction.ArithEnum.Flags_Ovf;
                            if ((instr.Flags & CLR.CIL.HLOpFlags.Un) != 0)
                                arithMode |= MidInstruction.ArithEnum.Flags_Un;

                            SsaRegister srcReg = stackTracker.Pop();
                            SsaRegister destReg = stackTracker.NewReg(new VType(VType.ValTypeEnum.ValueValue, destType));
                            midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.LivenReg, codeLocation, destReg));
                            midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.ConvertNumber, codeLocation, srcReg, destReg, arithMode));
                            midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.KillReg, codeLocation, srcReg));

                            stackTracker.Push(destReg);
                        }
                        break;
                    case CLR.CIL.HLOpcode.ldlen:
                        {
                            SsaRegister arrayReg = stackTracker.Pop();
                            SsaRegister resultReg = stackTracker.NewReg(new VType(VType.ValTypeEnum.ValueValue, m_commonTypeLookup.U));

                            midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.LivenReg, codeLocation, resultReg));
                            midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.LoadArrayLength, codeLocation, arrayReg, resultReg));
                            midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.KillReg, codeLocation, arrayReg));

                            stackTracker.Push(resultReg);
                        }
                        break;
                    case CLR.CIL.HLOpcode.ldtoken:
                        {
                            CLRTableRow tokenRow = (CLRTableRow)instr.Arguments.ObjValue;
                            CLRTypeSpec typeResolution = null;
                            CppMethodSpec methodResolution = null;
                            CppField fieldResolution = null;

                            if (tokenRow is CLRTypeRefRow || tokenRow is CLRTypeDefRow || tokenRow is CLRTypeSpecRow)
                                typeResolution = m_cppBuilder.Assemblies.InternTypeDefOrRefOrSpec(tokenRow);
                            else if (tokenRow is CLRMemberRefRow)
                            {
                                CLRMemberRefRow memberRef = (CLRMemberRefRow)tokenRow;
                                if (memberRef.FieldSig != null)
                                    fieldResolution = ResolveField(memberRef);
                                else if (memberRef.MethodSig != null)
                                    methodResolution = CppBuilder.ResolveMethodDefOrRef(memberRef);
                                else
                                    throw new ArgumentException();
                            }
                            else if (tokenRow is CLRMethodDefRow)
                                methodResolution = CppBuilder.ResolveMethodDefOrRef(tokenRow);
                            else if (tokenRow is CLRFieldRow)
                                fieldResolution = ResolveField(tokenRow);
                            else
                                throw new ArgumentException();

                            if (typeResolution != null)
                            {
                                CLRTypeSpec rtDefSpec = m_cppBuilder.Assemblies.InternTypeDefOrRefOrSpec(m_cppBuilder.Assemblies.RuntimeTypeHandleDef);
                                SsaRegister reg = stackTracker.NewReg(new VType(VType.ValTypeEnum.ValueValue, rtDefSpec));
                                midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.LivenReg, codeLocation, reg));
                                midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.LoadTypeInfoHandle, codeLocation, reg, typeResolution));
                                stackTracker.Push(reg);
                            }
                            if (methodResolution != null)
                            {
                                // TODO: nameof support
                                throw new NotImplementedException();
                            }
                            if (fieldResolution != null)
                            {
                                // Necessary for nameof and static field InitializeArray
                                CLRTypeSpec containerClassSpec = fieldResolution.DeclaredInClassSpec;
                                string fieldName = fieldResolution.Name;

                                CLRTypeSpec fldDefSpec = m_cppBuilder.Assemblies.InternTypeDefOrRefOrSpec(m_cppBuilder.Assemblies.RuntimeFieldHandleDef);

                                SsaRegister reg = stackTracker.NewReg(new VType(VType.ValTypeEnum.ValueValue, fldDefSpec));
                                midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.LivenReg, codeLocation, reg));
                                midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.LoadFieldInfoHandle, codeLocation, reg, containerClassSpec, fieldName, fieldResolution.Field.Static));
                                stackTracker.Push(reg);
                            }
                        }
                        break;
                    case CLR.CIL.HLOpcode.@switch:
                        {
                            SsaRegister valueReg = stackTracker.Pop();
                            List<CfgOutboundEdge> targetOutboundEdges = new List<CfgOutboundEdge>();

                            CfgOutboundEdgePrototype cfgEdgeProto = stackTracker.GenerateCfgEdge();
                            foreach (uint targetInstr in (uint[])instr.Arguments.ObjValue)
                            {
                                CfgNode targetNode = cfgBuilder.AddCfgTarget(this, (int)targetInstr, cfgEdgeProto.OutboundTypes);
                                targetOutboundEdges.Add(new CfgOutboundEdge(codeLocation, targetNode, cfgEdgeProto));
                            }

                            CfgNode fallThroughNode = cfgBuilder.AddCfgTarget(this, nextInstr, cfgEdgeProto.OutboundTypes);

                            midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.Switch, codeLocation, valueReg, targetOutboundEdges.ToArray()));
                            midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.KillReg, codeLocation, valueReg));

                            OutputFallThroughEdge = new CfgOutboundEdge(codeLocation, fallThroughNode, cfgEdgeProto);
                            isTerminalEdge = true;
                        }
                        break;
                    case CLR.CIL.HLOpcode.unbox:
                        {
                            CLRTypeSpec typeTok = m_cppBuilder.Assemblies.InternTypeDefOrRefOrSpec((CLRTableRow)instr.Arguments.ObjValue);

                            SsaRegister objReg = stackTracker.Pop();
                            SsaRegister valueReg = stackTracker.NewReg(new VType(VType.ValTypeEnum.ManagedPtr, typeTok));

                            midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.LivenReg, codeLocation, valueReg));
                            midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.UnboxPtr, codeLocation, objReg, valueReg));
                            midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.KillReg, codeLocation, objReg));

                            stackTracker.Push(valueReg);
                        }
                        break;
                    case CLR.CIL.HLOpcode.unbox_any:
                        {
                            CLRTypeSpec typeTok = m_cppBuilder.Assemblies.InternTypeDefOrRefOrSpec((CLRTableRow)instr.Arguments.ObjValue);

                            SsaRegister objReg = stackTracker.Pop();
                            SsaRegister valueReg = stackTracker.NewReg(new VType(VType.ValTypeEnum.ValueValue, typeTok));

                            midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.LivenReg, codeLocation, valueReg));
                            midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.UnboxValue, codeLocation, objReg, valueReg));
                            midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.KillReg, codeLocation, objReg));

                            stackTracker.Push(valueReg);
                        }
                        break;
                    case CLR.CIL.HLOpcode.initobj:
                        {
                            SsaRegister objLoc = stackTracker.Pop();

                            midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.ZeroFillPtr, codeLocation, objLoc));
                            midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.KillReg, codeLocation, objLoc));
                        }
                        break;
                    case CLR.CIL.HLOpcode.ldftn:
                        {
                            CppMethodSpec boundMethodSpec = CppBuilder.ResolveMethodDefOrRef((CLRTableRow)instr.Arguments.ObjValue);

                            SsaRegister ftnReg = SsaRegister.Constant(new VType(VType.ValTypeEnum.DelegateSimpleMethod, null, boundMethodSpec));

                            midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.LivenReg, codeLocation, ftnReg));
                            stackTracker.Push(ftnReg);
                        }
                        break;
                    case CLR.CIL.HLOpcode.ldvirtftn:
                        {
                            SsaRegister throwawayObjReg = stackTracker.Pop();

                            CppMethodSpec boundVirtMethod = CppBuilder.ResolveMethodDefOrRef((CLRTableRow)instr.Arguments.ObjValue);
                            SsaRegister ftnReg = SsaRegister.Constant(new VType(VType.ValTypeEnum.DelegateVirtualMethod, null, boundVirtMethod));
                            stackTracker.Push(ftnReg);

                            // This reverses the preceding dup sequence
                            if (cilMethod.Instructions[instrNum - 1].Opcode != CLR.CIL.HLOpcode.dup || firstInstr == instrNum)
                                throw new ArgumentException();

                            // WARNING: This must be kept in sync with dup!
                            midInstrs.RemoveRange(midInstrs.Count - 2, 2);
                            midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.LivenReg, codeLocation, ftnReg));
                        }
                        break;
                    case CLR.CIL.HLOpcode.endfinally:
                        {
                            midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.ExitFinally, codeLocation));
                            while (stackTracker.Depth > 0)
                                midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.KillReg, codeLocation, stackTracker.Pop()));
                            isTerminalEdge = true;
                        }
                        break;
                    case CLR.CIL.HLOpcode.constrained_pfx:
                    case CLR.CIL.HLOpcode.readonly_pfx:
                        break;
                    case CLR.CIL.HLOpcode.jmp:
                    case CLR.CIL.HLOpcode.calli:
                    case CLR.CIL.HLOpcode.@break:
                    case CLR.CIL.HLOpcode.cpobj:
                    case CLR.CIL.HLOpcode.refanyval:
                    case CLR.CIL.HLOpcode.ckfinite:
                    case CLR.CIL.HLOpcode.mkrefany:
                    case CLR.CIL.HLOpcode.arglist:
                    case CLR.CIL.HLOpcode.localloc:
                    case CLR.CIL.HLOpcode.endfilter:
                    case CLR.CIL.HLOpcode.unaligned_pfx:
                    case CLR.CIL.HLOpcode.volatile_pfx:
                    case CLR.CIL.HLOpcode.tail_pfx:
                    case CLR.CIL.HLOpcode.cpblk:
                    case CLR.CIL.HLOpcode.initblk:
                    case CLR.CIL.HLOpcode.no_pfx:
                    case CLR.CIL.HLOpcode.rethrow:
                    case CLR.CIL.HLOpcode.@sizeof:
                    case CLR.CIL.HLOpcode.refanytype:
                        throw new NotImplementedException("Unimplemented opcode: " + instr.Opcode.ToString());
                        break;
                }
            }

            // Post-terminal-edge cleanup
            // Leak any registers alive past the terminal edge
            while (stackTracker.Depth > 0)
                midInstrs.Add(new MidInstruction(MidInstruction.OpcodeEnum.LeakReg, codeLocation, stackTracker.Pop()));

            OutputInstructions = midInstrs.ToArray();
        }
Beispiel #9
0
 public MidInstruction(OpcodeEnum opcode, CodeLocationTag codeLocation, SsaRegister regArg, SsaRegister regArg2, CfgOutboundEdge cfgEdgeArg, bool flagArg)
 {
     Opcode = opcode;
     CodeLocation = codeLocation;
     RegArg = regArg;
     RegArg2 = regArg2;
     CfgEdgeArg = cfgEdgeArg;
     FlagArg = flagArg;
 }
Beispiel #10
0
 public CfgNodeEdge(SsaRegister[] regs)
 {
     Registers = regs;
 }
Beispiel #11
0
 public void AddRegister(SsaRegister reg)
 {
     m_ssaRegisterLookup[reg] = m_ssaRegisters.Count;
     m_ssaRegisters.Add(reg);
 }
Beispiel #12
0
 public MidInstruction(OpcodeEnum opcode, CodeLocationTag codeLocation, SsaRegister regArg, SsaRegister regArg2, ArithEnum arithArg)
 {
     Opcode = opcode;
     CodeLocation = codeLocation;
     RegArg = regArg;
     RegArg2 = regArg2;
     ArithArg = arithArg;
 }
Beispiel #13
0
        private Clarity.Rpa.HighSsaRegister InternSsaRegister(SsaRegister ssaRegister)
        {
            if (ssaRegister == null)
                return null;

            Clarity.Rpa.HighSsaRegister highSsa;
            if (!m_ssaToEmittedSsa.TryGetValue(ssaRegister, out highSsa))
            {
                Clarity.Rpa.HighValueType valType;
                object constValue = null;

                switch (ssaRegister.VType.ValType)
                {
                    case VType.ValTypeEnum.ManagedPtr:
                        valType = Clarity.Rpa.HighValueType.ManagedPtr;
                        break;
                    case VType.ValTypeEnum.ConstantValue:
                        constValue = ssaRegister.ConstantValue;
                        valType = Clarity.Rpa.HighValueType.ConstantValue;
                        break;
                    case VType.ValTypeEnum.ConstantReference:
                        constValue = ssaRegister.ConstantValue;
                        valType = Clarity.Rpa.HighValueType.ConstantString;
                        break;
                    case VType.ValTypeEnum.ReferenceValue:
                        valType = Clarity.Rpa.HighValueType.ReferenceValue;
                        break;
                    case VType.ValTypeEnum.Null:
                        valType = Clarity.Rpa.HighValueType.Null;
                        break;
                    case VType.ValTypeEnum.ValueValue:
                        valType = Clarity.Rpa.HighValueType.ValueValue;
                        break;
                    default:
                        throw new ArgumentException();
                }

                highSsa = new Clarity.Rpa.HighSsaRegister(valType, RpaTagFactory.CreateTypeTag(ssaRegister.VType.TypeSpec), constValue);
                m_ssaToEmittedSsa.Add(ssaRegister, highSsa);
            }

            return highSsa;
        }
Beispiel #14
0
 public Entry(SsaRegister reg)
 {
     m_isAlive = true;
     m_reg = reg;
 }
Beispiel #15
0
 public void Push(SsaRegister instanceReg)
 {
     m_regs.Add(instanceReg);
 }
Beispiel #16
0
 public MidInstruction(OpcodeEnum opcode, CodeLocationTag codeLocation, SsaRegister regArg, uint uintArg)
 {
     Opcode = opcode;
     CodeLocation = codeLocation;
     RegArg = regArg;
     UIntArg = uintArg;
 }
Beispiel #17
0
        private SsaRegister EmitPassiveConversion(Clarity.Rpa.CodeLocationTag codeLocation, SsaRegister sourceReg, CLRTypeSpec destType, CppCfgNodeOutline outline, IList<Clarity.Rpa.HighInstruction> instrs)
        {
            if (sourceReg.VType.ValType == VType.ValTypeEnum.DelegateSimpleMethod ||
                sourceReg.VType.ValType == VType.ValTypeEnum.DelegateVirtualMethod)
                return sourceReg;

            if (sourceReg.VType.TypeSpec.Equals(destType))
                return sourceReg;

            if (sourceReg.VType.ValType == VType.ValTypeEnum.Null)
            {
                SsaRegister nullReg = new SsaRegister(new VType(VType.ValTypeEnum.Null, destType));
                nullReg.MakeUsable();
                nullReg.GenerateUniqueID(m_regAllocator);

                outline.AddRegister(nullReg);
                return nullReg;
            }

            SsaRegister newReg;
            switch (sourceReg.VType.ValType)
            {
                case VType.ValTypeEnum.ConstantReference:
                case VType.ValTypeEnum.ReferenceValue:
                    newReg = new SsaRegister(new VType(VType.ValTypeEnum.ReferenceValue, destType));
                    break;
                case VType.ValTypeEnum.ValueValue:
                case VType.ValTypeEnum.ConstantValue:
                    newReg = new SsaRegister(new VType(VType.ValTypeEnum.ValueValue, destType));
                    break;
                default:
                    throw new ArgumentException();
            }

            newReg.MakeUsable();
            newReg.GenerateUniqueID(m_regAllocator);

            instrs.Add(new Clarity.Rpa.Instructions.PassiveConvertInstruction(
                codeLocation,
                InternSsaRegister(newReg),
                InternSsaRegister(sourceReg)
                ));

            return newReg;
        }
Beispiel #18
0
        private CLR.CLRTypeSpec StackTypeSpecForSsaReg(SsaRegister regA, bool isUnsigned)
        {
            NumericStackType stackTypeA = StackTypeForTypeSpec(regA.VType.TypeSpec);

            CLR.CLRSigType.ElementType elementType;
            switch (stackTypeA)
            {
                case NumericStackType.Float32:
                    elementType = CLR.CLRSigType.ElementType.R4;
                    break;
                case NumericStackType.Float64:
                    elementType = CLR.CLRSigType.ElementType.R8;
                    break;
                case NumericStackType.Int32:
                    elementType = isUnsigned ? CLR.CLRSigType.ElementType.U4 : CLR.CLRSigType.ElementType.I4;
                    break;
                case NumericStackType.Int64:
                    elementType = isUnsigned ? CLR.CLRSigType.ElementType.U8 : CLR.CLRSigType.ElementType.I8;
                    break;
                case NumericStackType.NativeInt:
                    elementType = isUnsigned ? CLR.CLRSigType.ElementType.U : CLR.CLRSigType.ElementType.I;
                    break;
                default:
                    throw new ArgumentException();
            }
            return m_builder.Assemblies.InternVagueType(new CLR.CLRSigTypeSimple(elementType));
        }
Beispiel #19
0
 private SsaRegister EmitPassiveConversion_PermitRefs(Clarity.Rpa.CodeLocationTag codeLocation, SsaRegister sourceReg, CLRTypeSpec destType, CppCfgNodeOutline outline, IList<Clarity.Rpa.HighInstruction> instrs)
 {
     switch (sourceReg.VType.ValType)
     {
         case VType.ValTypeEnum.ManagedPtr:
             if (sourceReg.VType.TypeSpec.Equals(destType))
                 return sourceReg;
             throw new ArgumentException();
         default:
             return EmitPassiveConversion(codeLocation, sourceReg, destType, outline, instrs);
     }
 }
Beispiel #20
0
 public SsaVRegMapping(SsaRegister ssaReg, VReg vReg)
 {
     m_ssaReg = ssaReg;
     m_vReg = vReg;
 }
Beispiel #21
0
        private NumericStackType NumericStackTypeForNumericBinaryOp(SsaRegister regA, SsaRegister regB)
        {
            // III.1.5 table III.4
            NumericStackType stackTypeA = StackTypeForTypeSpec(regA.VType.TypeSpec);
            NumericStackType stackTypeB = StackTypeForTypeSpec(regB.VType.TypeSpec);
            NumericStackType combinedType;

            if (stackTypeA == NumericStackType.Int32)
            {
                if (stackTypeB == NumericStackType.NativeInt)
                    combinedType = NumericStackType.NativeInt;
                else if (stackTypeB == NumericStackType.Int32)
                    combinedType = NumericStackType.Int32;
                else
                    throw new Exception("Unexpected binary numeric operation operands");
            }
            else if (stackTypeA == NumericStackType.Int64)
            {
                if (stackTypeB == NumericStackType.Int64)
                    combinedType = NumericStackType.Int64;
                else
                    throw new Exception("Unexpected binary numeric operation operands");
            }
            else if (stackTypeA == NumericStackType.NativeInt)
            {
                if (stackTypeB == NumericStackType.NativeInt
                    || stackTypeB == NumericStackType.Int32)
                    combinedType = NumericStackType.NativeInt;
                else
                    throw new Exception("Unexpected binary numeric operation operands");
            }
            else if (stackTypeB == NumericStackType.Float32)
            {
                if (stackTypeB == NumericStackType.Float32)
                    combinedType = NumericStackType.Float32;
                else if (stackTypeB == NumericStackType.Float64)
                    combinedType = NumericStackType.Float32;
                else
                    throw new Exception("Unexpected binary numeric operation operands");
            }
            else if (stackTypeA == NumericStackType.Float64)
            {
                if (stackTypeB == NumericStackType.Float32
                    || stackTypeB == NumericStackType.Float64)
                    combinedType = NumericStackType.Float64;
                else
                    throw new Exception("Unexpected binary numeric operation operands");
            }
            else
                throw new Exception("Unexpected binary numeric operation operands");

            return combinedType;
        }
Beispiel #22
0
 public MidInstruction(OpcodeEnum opcode, CodeLocationTag codeLocation, SsaRegister regArg, SsaRegister regArg2, SsaRegister regArg3, bool flagArg)
 {
     Opcode = opcode;
     CodeLocation = codeLocation;
     RegArg = regArg;
     RegArg2 = regArg2;
     RegArg3 = regArg3;
     FlagArg = FlagArg;
 }
Beispiel #23
0
 private CLR.CLRTypeSpec TypeSpecForNumericBinaryOp(SsaRegister regA, SsaRegister regB, bool isUnsigned)
 {
     return TypeSpecForNumericStackType(NumericStackTypeForNumericBinaryOp(regA, regB), isUnsigned);
 }
Beispiel #24
0
 public void RecycleReg(SsaRegister reg)
 {
     AddReg(reg);
 }
Beispiel #25
0
 private void AliasSsaRegister(Clarity.Rpa.HighSsaRegister src, SsaRegister copy)
 {
     if (m_ssaToEmittedSsa.ContainsKey(copy))
         throw new Exception();
     m_ssaToEmittedSsa.Add(copy, src);
 }
Beispiel #26
0
 private static bool IsRegScopable(SsaRegister reg)
 {
     if (reg.IsSpilled)
         return false;
     return CppRegisterAllocator.IsVTypeSpillable(reg.VType);
 }
Beispiel #27
0
 public int GetRegisterID(SsaRegister reg)
 {
     return m_ssaRegisterLookup[reg];
 }
Beispiel #28
0
 private void AddReg(SsaRegister reg)
 {
     m_regStack.Push(new Entry(reg));
     m_indent += "\t";
 }
 public CfgOutboundEdgePrototype(VType[] outboundTypes, SsaRegister[] outboundRegs)
 {
     m_outboundRegs = outboundRegs;
     m_outboundTypes = outboundTypes;
 }
Beispiel #30
0
 public MidInstruction(OpcodeEnum opcode, CodeLocationTag codeLocation, CppMethodSpec methodSpecArg, CLRTypeSpec typeSpecArg, SsaRegister regArg, SsaRegister regArg2, SsaRegister[] regArgs)
 {
     Opcode = opcode;
     CodeLocation = codeLocation;
     TypeSpecArg = typeSpecArg;
     MethodSpecArg = methodSpecArg;
     RegArg = regArg;
     RegArg2 = regArg2;
     RegArgs = regArgs;
 }