public MidInstruction(OpcodeEnum opcode, CodeLocationTag codeLocation, SsaRegister regArg, CfgOutboundEdge[] cfgEdgesArg) { Opcode = opcode; CodeLocation = codeLocation; RegArg = regArg; CfgEdgesArg = cfgEdgesArg; }
public void AddSuccessor(CfgOutboundEdge outboundEdge) { m_successors.Add(outboundEdge); }
public void Parse() { CfgNodeCompiler compiler = new CfgNodeCompiler(this); compiler.Compile(); m_midInstructions = compiler.OutputInstructions; m_fallThroughEdge = compiler.OutputFallThroughEdge; }
private CppTranslatedOutboundEdge InternOutboundEdge(CfgNode node, CfgOutboundEdge edge) { CppTranslatedOutboundEdge outboundEdge; if (m_translatedOutboundEdges.TryGetValue(edge, out outboundEdge)) return outboundEdge; bool needRegTranslation = false; int survivingRegsCount = edge.SurvivingRegs.Length; CfgNode successorNode = edge.SuccessorNode; for (int i = 0; i < survivingRegsCount; i++) { CLR.CLRTypeSpec outType = edge.SurvivingRegs[i].VType.TypeSpec; CLR.CLRTypeSpec inType = successorNode.EntryTypes[i].TypeSpec; if (!outType.Equals(inType)) { needRegTranslation = true; break; } } Clarity.Rpa.HighCfgNodeHandle prevNode = InternHighCfgNode(node); if (!needRegTranslation) { List<Clarity.Rpa.HighSsaRegister> regs = new List<Clarity.Rpa.HighSsaRegister>(); foreach (SsaRegister reg in edge.SurvivingRegs) regs.Add(InternSsaRegister(reg)); Clarity.Rpa.HighCfgNodeHandle nextNode = InternHighCfgNode(edge.SuccessorNode); outboundEdge = new CppTranslatedOutboundEdge(prevNode, nextNode, regs); } else { List<Clarity.Rpa.HighInstruction> instrs = new List<Clarity.Rpa.HighInstruction>(); List<Clarity.Rpa.HighSsaRegister> regs = new List<Clarity.Rpa.HighSsaRegister>(); List<Clarity.Rpa.HighPhi> phis = new List<Clarity.Rpa.HighPhi>(); Clarity.Rpa.HighCfgNodeHandle nextNode = InternHighCfgNode(edge.SuccessorNode); MidInstruction[] midInstrs = edge.SuccessorNode.MidInstructions; for (int i = 0; i < survivingRegsCount; i++) { MidInstruction midInstr = midInstrs[i]; if (midInstr.Opcode != MidInstruction.OpcodeEnum.EntryReg) throw new Exception("Internal error"); Clarity.Rpa.HighSsaRegister sourceReg = InternSsaRegister(edge.SurvivingRegs[i]); Clarity.Rpa.HighSsaRegister targetReg = InternSsaRegister(midInstr.RegArg); if (!targetReg.IsConstant) { HighSsaRegister importReg = new HighSsaRegister(sourceReg.ValueType, sourceReg.Type, sourceReg.ConstantValue); HighSsaRegister exportReg = new HighSsaRegister(targetReg.ValueType, targetReg.Type, targetReg.ConstantValue); HighPhiLink phiLink = new HighPhiLink(prevNode, sourceReg); phis.Add(new HighPhi(importReg, new HighPhiLink[] { phiLink })); instrs.Add(new Clarity.Rpa.Instructions.PassiveConvertInstruction( midInstr.CodeLocation, exportReg, importReg )); regs.Add(exportReg); } else regs.Add(targetReg); } instrs.Add(new Clarity.Rpa.Instructions.BranchInstruction(edge.CodeLocation, nextNode)); Clarity.Rpa.HighCfgNode cfgNode = new HighCfgNode(new Clarity.Rpa.HighCfgNodeHandle[] { prevNode }, phis.ToArray(), instrs.ToArray()); Clarity.Rpa.HighCfgNodeHandle cfgNodeHandle = new Clarity.Rpa.HighCfgNodeHandle(cfgNode); outboundEdge = new CppTranslatedOutboundEdge(cfgNodeHandle, cfgNodeHandle, regs); } m_translatedOutboundEdges.Add(edge, outboundEdge); return outboundEdge; }
private static void LinkSuccessor(CfgNode node, CfgOutboundEdge outboundEdge) { if (outboundEdge == null) return; node.AddSuccessor(outboundEdge); outboundEdge.SuccessorNode.AddPredecessor(node); }
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(); }
public MidInstruction(OpcodeEnum opcode, CodeLocationTag codeLocation, CfgOutboundEdge cfgEdgeArg) { Opcode = opcode; CodeLocation = codeLocation; CfgEdgeArg = cfgEdgeArg; }
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; }