private TransformToSsa(ControlFlowGraph cfg, SsaForm ssaForm) { this.cfg = cfg; this.ssaForm = ssaForm; this.writeToOriginalVariables = new List<SsaInstruction>[ssaForm.OriginalVariables.Count]; this.addressTaken = new bool[ssaForm.OriginalVariables.Count]; }
public static bool MakeByRefCallsSimple(SsaForm ssaForm) { SimplifyByRefCalls instance = new SimplifyByRefCalls(ssaForm); foreach (SsaBlock block in ssaForm.Blocks) { for (int i = 0; i < block.Instructions.Count; i++) { SsaInstruction inst = block.Instructions[i]; if (inst.Instruction != null) { switch (inst.Instruction.OpCode.Code) { case Code.Call: case Code.Callvirt: instance.MakeByRefCallSimple(block, ref i, (IMethodSignature)inst.Instruction.Operand); break; case Code.Initobj: instance.MakeInitObjCallSimple(block, ref i); break; case Code.Ldfld: instance.MakeLoadFieldCallSimple(block, ref i); break; } } } } instance.RemoveRedundantInstructions(); if (instance.couldSimplifySomething) ssaForm.ComputeVariableUsage(); return instance.couldSimplifySomething; }
readonly bool[] addressTaken; // array index -> SsaVariable OriginalVariableIndex; value = whether ldloca instruction was used with variable TransformToSsa(ControlFlowGraph cfg, SsaForm ssaForm) { this.cfg = cfg; this.ssaForm = ssaForm; writeToOriginalVariables = new List <SsaInstruction> [ssaForm.OriginalVariables.Count]; addressTaken = new bool[ssaForm.OriginalVariables.Count]; }
internal SsaForm Build() { CreateGraphStructure(); this.ssaForm = new SsaForm(blocks, parameters, locals, stackLocations, method.HasThis); CreateInstructions(cfg.EntryPoint.BlockIndex); CreateSpecialInstructions(); return(ssaForm); }
public static void RemoveDeadAssignments(SsaForm ssaForm) { HashSet <SsaVariable> liveVariables = new HashSet <SsaVariable>(); // find variables that are used directly foreach (SsaBlock block in ssaForm.Blocks) { foreach (SsaInstruction inst in block.Instructions) { if (!CanRemoveAsDeadCode(inst)) { if (inst.Target != null) { liveVariables.Add(inst.Target); } foreach (SsaVariable op in inst.Operands) { liveVariables.Add(op); } } } } Queue <SsaVariable> queue = new Queue <SsaVariable>(liveVariables); // find variables that are used indirectly while (queue.Count > 0) { SsaVariable v = queue.Dequeue(); if (v.IsSingleAssignment) { foreach (SsaVariable op in v.Definition.Operands) { if (liveVariables.Add(op)) { queue.Enqueue(op); } } } } // remove assignments to all unused variables foreach (SsaBlock block in ssaForm.Blocks) { block.Instructions.RemoveAll( inst => { if (inst.Target != null && !liveVariables.Contains(inst.Target)) { Debug.Assert(inst.Target.IsSingleAssignment); return(true); } return(false); }); } ssaForm.ComputeVariableUsage(); // update usage after we modified stuff }
public static void Transform(ControlFlowGraph cfg, SsaForm ssa, bool optimize = true) { TransformToSsa transform = new TransformToSsa(cfg, ssa); transform.ConvertVariablesToSsa(); SsaOptimization.RemoveDeadAssignments(ssa); // required so that 'MakeByRefCallsSimple' can detect more cases if (SimplifyByRefCalls.MakeByRefCallsSimple(ssa)) { transform.ConvertVariablesToSsa(); } if (optimize) SsaOptimization.Optimize(ssa); }
public static void Transform(ControlFlowGraph cfg, SsaForm ssa, bool optimize = true) { TransformToSsa transform = new TransformToSsa(cfg, ssa); transform.ConvertVariablesToSsa(); SsaOptimization.RemoveDeadAssignments(ssa); // required so that 'MakeByRefCallsSimple' can detect more cases if (SimplifyByRefCalls.MakeByRefCallsSimple(ssa)) { transform.ConvertVariablesToSsa(); } if (optimize) { SsaOptimization.Optimize(ssa); } }
public static void SimpleCopyPropagation(SsaForm ssaForm, bool onlyForStackLocations = true) { foreach (SsaBlock block in ssaForm.Blocks) { foreach (SsaInstruction inst in block.Instructions) { if (inst.IsMoveInstruction && inst.Target.IsSingleAssignment && inst.Operands[0].IsSingleAssignment) { if (inst.Target.IsStackLocation || !onlyForStackLocations) { // replace all uses of 'target' with 'operands[0]'. foreach (SsaInstruction useInstruction in inst.Target.Usage) { useInstruction.ReplaceVariableInOperands(inst.Target, inst.Operands[0]); } } } } } ssaForm.ComputeVariableUsage(); // update usage after we modified stuff }
/// <summary> /// When any instructions stores its result in a stack location that's used only once in a 'stloc' or 'starg' instruction, /// we optimize this to directly store in the target location. /// As optimization this is redundant (does the same as copy propagation), but it'll make us keep the variables named /// after locals instead of keeping the temps as using only the simple copy propagation would do. /// </summary> public static void DirectlyStoreToVariables(SsaForm ssaForm) { foreach (SsaBlock block in ssaForm.Blocks) { block.Instructions.RemoveAll( inst => { if (inst.Instruction != null && (inst.Instruction.OpCode == OpCodes.Stloc || inst.Instruction.OpCode == OpCodes.Starg)) { SsaVariable target = inst.Target; SsaVariable temp = inst.Operands[0]; if (target.IsSingleAssignment && temp.IsSingleAssignment && temp.Usage.Count == 1 && temp.IsStackLocation) { temp.Definition.Target = target; return true; } } return false; }); } ssaForm.ComputeVariableUsage(); // update usage after we modified stuff }
/// <summary> /// When any instructions stores its result in a stack location that's used only once in a 'stloc' or 'starg' instruction, /// we optimize this to directly store in the target location. /// As optimization this is redundant (does the same as copy propagation), but it'll make us keep the variables named /// after locals instead of keeping the temps as using only the simple copy propagation would do. /// </summary> public static void DirectlyStoreToVariables(SsaForm ssaForm) { foreach (SsaBlock block in ssaForm.Blocks) { block.Instructions.RemoveAll( inst => { if (inst.Instruction != null && (inst.Instruction.OpCode == OpCodes.Stloc || inst.Instruction.OpCode == OpCodes.Starg)) { SsaVariable target = inst.Target; SsaVariable temp = inst.Operands[0]; if (target.IsSingleAssignment && temp.IsSingleAssignment && temp.Usage.Count == 1 && temp.IsStackLocation) { temp.Definition.Target = target; return(true); } } return(false); }); } ssaForm.ComputeVariableUsage(); // update usage after we modified stuff }
public static void RemoveDeadAssignments(SsaForm ssaForm) { HashSet<SsaVariable> liveVariables = new HashSet<SsaVariable>(); // find variables that are used directly foreach (SsaBlock block in ssaForm.Blocks) { foreach (SsaInstruction inst in block.Instructions) { if (!CanRemoveAsDeadCode(inst)) { if (inst.Target != null) liveVariables.Add(inst.Target); foreach (SsaVariable op in inst.Operands) { liveVariables.Add(op); } } } } Queue<SsaVariable> queue = new Queue<SsaVariable>(liveVariables); // find variables that are used indirectly while (queue.Count > 0) { SsaVariable v = queue.Dequeue(); if (v.IsSingleAssignment) { foreach (SsaVariable op in v.Definition.Operands) { if (liveVariables.Add(op)) queue.Enqueue(op); } } } // remove assignments to all unused variables foreach (SsaBlock block in ssaForm.Blocks) { block.Instructions.RemoveAll( inst => { if (inst.Target != null && !liveVariables.Contains(inst.Target)) { Debug.Assert(inst.Target.IsSingleAssignment); return true; } return false; }); } ssaForm.ComputeVariableUsage(); // update usage after we modified stuff }
public static bool MakeByRefCallsSimple(SsaForm ssaForm) { SimplifyByRefCalls instance = new SimplifyByRefCalls(ssaForm); foreach (SsaBlock block in ssaForm.Blocks) { for (int i = 0; i < block.Instructions.Count; i++) { SsaInstruction inst = block.Instructions[i]; if (inst.Instruction != null) { switch (inst.Instruction.OpCode.Code) { case Code.Call: case Code.Callvirt: instance.MakeByRefCallSimple(block, ref i, (IMethodSignature)inst.Instruction.Operand); break; case Code.Initobj: instance.MakeInitObjCallSimple(block, ref i); break; case Code.Ldfld: instance.MakeLoadFieldCallSimple(block, ref i); break; } } } } instance.RemoveRedundantInstructions(); if (instance.couldSimplifySomething) { ssaForm.ComputeVariableUsage(); } return(instance.couldSimplifySomething); }
internal SsaForm Build() { CreateGraphStructure(); this.ssaForm = new SsaForm(blocks, parameters, locals, stackLocations, method.HasThis); CreateInstructions(cfg.EntryPoint.BlockIndex); CreateSpecialInstructions(); return ssaForm; }
public static void Optimize(SsaForm ssaForm) { DirectlyStoreToVariables(ssaForm); SimpleCopyPropagation(ssaForm); RemoveDeadAssignments(ssaForm); }
private SimplifyByRefCalls(SsaForm ssaForm) { this.ssaForm = ssaForm; }