summaryrefslogtreecommitdiff
path: root/ICSharpCode.Decompiler/FlowAnalysis/TransformToSsa.cs
diff options
context:
space:
mode:
Diffstat (limited to 'ICSharpCode.Decompiler/FlowAnalysis/TransformToSsa.cs')
-rw-r--r--ICSharpCode.Decompiler/FlowAnalysis/TransformToSsa.cs254
1 files changed, 0 insertions, 254 deletions
diff --git a/ICSharpCode.Decompiler/FlowAnalysis/TransformToSsa.cs b/ICSharpCode.Decompiler/FlowAnalysis/TransformToSsa.cs
deleted file mode 100644
index 47ff7bff..00000000
--- a/ICSharpCode.Decompiler/FlowAnalysis/TransformToSsa.cs
+++ /dev/null
@@ -1,254 +0,0 @@
-// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy of this
-// software and associated documentation files (the "Software"), to deal in the Software
-// without restriction, including without limitation the rights to use, copy, modify, merge,
-// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
-// to whom the Software is furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in all copies or
-// substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
-// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
-// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
-// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
-// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-// DEALINGS IN THE SOFTWARE.
-
-using System;
-using System.Collections.Generic;
-using System.Collections.ObjectModel;
-using System.Diagnostics;
-using System.Linq;
-
-using Mono.Cecil;
-using Mono.Cecil.Cil;
-
-namespace ICSharpCode.Decompiler.FlowAnalysis
-{
- /// <summary>
- /// Convers a method to static single assignment form.
- /// </summary>
- internal sealed class TransformToSsa
- {
- 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);
- }
-
- readonly ControlFlowGraph cfg;
- readonly SsaForm ssaForm;
- readonly List<SsaInstruction>[] writeToOriginalVariables; // array index -> SsaVariable OriginalVariableIndex
- 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];
- }
-
- #region CollectInformationAboutOriginalVariableUse
- void CollectInformationAboutOriginalVariableUse()
- {
- Debug.Assert(addressTaken.Length == writeToOriginalVariables.Length);
- for (int i = 0; i < writeToOriginalVariables.Length; i++) {
- Debug.Assert(ssaForm.OriginalVariables[i].OriginalVariableIndex == i);
-
- addressTaken[i] = false;
- // writeToOriginalVariables is only used when placing phi functions
- // we don't need to do that anymore for variables that are already in SSA form
- if (ssaForm.OriginalVariables[i].IsSingleAssignment)
- writeToOriginalVariables[i] = null;
- else
- writeToOriginalVariables[i] = new List<SsaInstruction>();
- }
- foreach (SsaBlock block in ssaForm.Blocks) {
- foreach (SsaInstruction inst in block.Instructions) {
- if (inst.Target != null ) {
- var list = writeToOriginalVariables[inst.Target.OriginalVariableIndex];
- if (list != null)
- list.Add(inst);
- }
- if (inst.Instruction != null) {
- if (inst.Instruction.OpCode == OpCodes.Ldloca) {
- addressTaken[ssaForm.GetOriginalVariable((VariableDefinition)inst.Instruction.Operand).OriginalVariableIndex] = true;
- } else if (inst.Instruction.OpCode == OpCodes.Ldarga) {
- addressTaken[ssaForm.GetOriginalVariable((ParameterDefinition)inst.Instruction.Operand).OriginalVariableIndex] = true;
- }
- }
- }
- }
- }
- #endregion
-
- #region ConvertToSsa
- void ConvertVariablesToSsa()
- {
- CollectInformationAboutOriginalVariableUse();
- bool[] processVariable = new bool[ssaForm.OriginalVariables.Count];
- foreach (SsaVariable variable in ssaForm.OriginalVariables) {
- if (!variable.IsSingleAssignment && !addressTaken[variable.OriginalVariableIndex]) {
- PlacePhiFunctions(variable);
- processVariable[variable.OriginalVariableIndex] = true;
- }
- }
- RenameVariables(processVariable);
- foreach (SsaVariable variable in ssaForm.OriginalVariables) {
- if (!addressTaken[variable.OriginalVariableIndex]) {
- Debug.Assert(variable.IsSingleAssignment && variable.Definition != null);
- }
- }
- ssaForm.ComputeVariableUsage();
- }
- #endregion
-
- #region PlacePhiFunctions
- void PlacePhiFunctions(SsaVariable variable)
- {
- cfg.ResetVisited();
- HashSet<SsaBlock> blocksWithPhi = new HashSet<SsaBlock>();
- Queue<ControlFlowNode> worklist = new Queue<ControlFlowNode>();
- foreach (SsaInstruction writeInstruction in writeToOriginalVariables[variable.OriginalVariableIndex]) {
- ControlFlowNode cfgNode = cfg.Nodes[writeInstruction.ParentBlock.BlockIndex];
- if (!cfgNode.Visited) {
- cfgNode.Visited = true;
- worklist.Enqueue(cfgNode);
- }
- }
- while (worklist.Count > 0) {
- ControlFlowNode cfgNode = worklist.Dequeue();
- foreach (ControlFlowNode dfNode in cfgNode.DominanceFrontier) {
- // we don't need phi functions in the exit node
- if (dfNode.NodeType == ControlFlowNodeType.RegularExit || dfNode.NodeType == ControlFlowNodeType.ExceptionalExit)
- continue;
- SsaBlock y = ssaForm.Blocks[dfNode.BlockIndex];
- if (blocksWithPhi.Add(y)) {
- // add a phi instruction in y
- SsaVariable[] operands = Enumerable.Repeat(variable, dfNode.Incoming.Count).ToArray();
- y.Instructions.Insert(0, new SsaInstruction(y, null, variable, operands, specialOpCode: SpecialOpCode.Phi));
- if (!dfNode.Visited) {
- dfNode.Visited = true;
- worklist.Enqueue(dfNode);
- }
- }
- }
- }
- }
- #endregion
-
- #region RenameVariable
- int tempVariableCounter = 1;
-
- void RenameVariables(bool[] processVariable)
- {
- VariableRenamer r = new VariableRenamer(this, processVariable);
- r.Visit(ssaForm.EntryPoint);
- }
-
- sealed class VariableRenamer
- {
- readonly TransformToSsa transform;
- readonly ReadOnlyCollection<SsaVariable> inputVariables;
- internal readonly Stack<SsaVariable>[] versionStacks;
- int[] versionCounters; // specifies for each input variable the next version number
-
- // processVariable = specifies for each input variable whether we should rename it
- public VariableRenamer(TransformToSsa transform, bool[] processVariable)
- {
- this.transform = transform;
- inputVariables = transform.ssaForm.OriginalVariables;
- Debug.Assert(inputVariables.Count == processVariable.Length);
- versionCounters = new int[inputVariables.Count];
- versionStacks = new Stack<SsaVariable>[inputVariables.Count];
- for (int i = 0; i < versionStacks.Length; i++) {
- if (processVariable[i]) {
- Debug.Assert(inputVariables[i].IsSingleAssignment == false);
- // only create version stacks for the variables that we need to process and that weren't already processed earlier
- versionStacks[i] = new Stack<SsaVariable>();
- versionStacks[i].Push(inputVariables[i]);
- }
- }
- }
-
- SsaVariable MakeNewVersion(int variableIndex)
- {
- int versionCounter = ++versionCounters[variableIndex];
- SsaVariable x = inputVariables[variableIndex];
- if (versionCounter == 1) {
- return x;
- } else {
- if (x.IsStackLocation) {
- return new SsaVariable(x, "temp" + (transform.tempVariableCounter++));
- } else {
- return new SsaVariable(x, x.Name + "_" + versionCounter);
- }
- }
- }
-
- internal void Visit(SsaBlock block)
- {
- // duplicate top of all stacks
- foreach (var stack in versionStacks) {
- if (stack != null)
- stack.Push(stack.Peek());
- }
-
- foreach (SsaInstruction s in block.Instructions) {
- // replace all uses of variables being processed with their current version.
- if (s.SpecialOpCode != SpecialOpCode.Phi) {
- for (int i = 0; i < s.Operands.Length; i++) {
- var stack = versionStacks[s.Operands[i].OriginalVariableIndex];
- if (stack != null)
- s.Operands[i] = stack.Peek();
- }
- }
- // if we're writing to a variable we should process:
- if (s.Target != null) {
- int targetIndex = s.Target.OriginalVariableIndex;
- if (versionStacks[targetIndex] != null) {
- s.Target = MakeNewVersion(targetIndex);
- s.Target.IsSingleAssignment = true;
- s.Target.Definition = s;
-
- // we already pushed our entry for this SsaBlock at the beginning (where we duplicated all stacks),
- // so now replace the top element
- versionStacks[targetIndex].Pop();
- versionStacks[targetIndex].Push(s.Target);
- }
- }
- }
-
- foreach (SsaBlock succ in block.Successors) {
- int j = succ.Predecessors.IndexOf(block);
- Debug.Assert(j >= 0);
- foreach (SsaInstruction f in succ.Instructions) {
- if (f.SpecialOpCode == SpecialOpCode.Phi) {
- var stack = versionStacks[f.Target.OriginalVariableIndex];
- if (stack != null) {
- f.Operands[j] = stack.Peek();
- }
- }
- }
- }
- foreach (ControlFlowNode child in transform.cfg.Nodes[block.BlockIndex].DominatorTreeChildren)
- Visit(transform.ssaForm.Blocks[child.BlockIndex]);
- // restore stacks:
- foreach (var stack in versionStacks) {
- if (stack != null)
- stack.Pop();
- }
- }
- }
- #endregion
- }
-}