From 897ac7fe0441103f780875bcacf52434ef723d19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Srbeck=C3=BD?= Date: Mon, 7 Mar 2011 00:12:40 +0000 Subject: [PATCH] Moved inlineing from Builder to Optimizer --- ICSharpCode.Decompiler/ILAst/ILAstBuilder.cs | 59 +------------ .../ILAst/ILAstOptimizer.cs | 88 +++++++++++++++++++ 2 files changed, 90 insertions(+), 57 deletions(-) diff --git a/ICSharpCode.Decompiler/ILAst/ILAstBuilder.cs b/ICSharpCode.Decompiler/ILAst/ILAstBuilder.cs index 8a060384c..4ee3a4546 100644 --- a/ICSharpCode.Decompiler/ILAst/ILAstBuilder.cs +++ b/ICSharpCode.Decompiler/ILAst/ILAstBuilder.cs @@ -201,9 +201,6 @@ namespace ICSharpCode.Decompiler.ILAst MethodDefinition methodDef; bool optimize; - Dictionary instrToByteCode = new Dictionary(); - Dictionary allowInline = new Dictionary(); - // Virtual instructions to load exception on stack Dictionary ldexceptions = new Dictionary(); @@ -223,6 +220,8 @@ namespace ICSharpCode.Decompiler.ILAst List StackAnalysis(MethodDefinition methodDef) { + Dictionary instrToByteCode = new Dictionary(); + // Create temporary structure for the stack analysis List body = new List(methodDef.Body.Instructions.Count); List prefixes = null; @@ -406,9 +405,6 @@ namespace ICSharpCode.Decompiler.ILAst } pushedBy.StoreTo.Add(tmpVar); } - if (byteCode.StackBefore[i].PushedBy.Length == 1) { - allowInline[tmpVar] = true; - } argIdx++; } } @@ -500,13 +496,6 @@ namespace ICSharpCode.Decompiler.ILAst newVars.Add(mergedVar); } } - - // Permit inlining - foreach(VariableInfo newVar in newVars) { - if (newVar.Stores.Count == 1 && newVar.Loads.Count == 1) { - allowInline[newVar.Variable] = true; - } - } } // Set bytecode operands @@ -667,50 +656,6 @@ namespace ICSharpCode.Decompiler.ILAst } } - // Try to in-line stloc / ldloc pairs - for(int i = 0; i < ast.Count - 1; i++) { - if (i < 0) continue; - - ILExpression currExpr = ast[i] as ILExpression; - ILExpression nextExpr = ast[i + 1] as ILExpression; - - if (currExpr != null && nextExpr != null && currExpr.Code == ILCode.Stloc) { - - // If the next expression is generated stloc, look inside - if (nextExpr.Code == ILCode.Stloc && ((ILVariable)nextExpr.Operand).IsGenerated) { - nextExpr = nextExpr.Arguments[0]; - } - - // Find the use of the 'expr' - for(int j = 0; j < nextExpr.Arguments.Count; j++) { - ILExpression arg = nextExpr.Arguments[j]; - - // We are moving the expression evaluation past the other aguments. - // It is ok to pass ldloc because the expression can not contain stloc and thus the ldcoc will still return the same value - // Do not inline ldloca - if (arg.Code == ILCode.Ldloc) { - if (arg.Operand == currExpr.Operand) { - bool canInline; - allowInline.TryGetValue((ILVariable)arg.Operand, out canInline); - - if (canInline) { - // Assigne the ranges for optimized away instrustions somewhere - currExpr.Arguments[0].ILRanges.AddRange(currExpr.ILRanges); - currExpr.Arguments[0].ILRanges.AddRange(nextExpr.Arguments[j].ILRanges); - - ast.RemoveAt(i); - nextExpr.Arguments[j] = currExpr.Arguments[0]; // Inline the stloc body - i -= 2; // Try the same index again - break; // Found - } - } - } else { - break; // Side-effects - } - } - } - } - return ast; } } diff --git a/ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs b/ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs index fa0a6b15f..023010baa 100644 --- a/ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs +++ b/ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs @@ -11,6 +11,7 @@ namespace ICSharpCode.Decompiler.ILAst { public enum ILAstOptimizationStep { + InlineVariables, ReduceBranchInstructionSet, YieldReturn, SplitToMovableBlocks, @@ -34,6 +35,9 @@ namespace ICSharpCode.Decompiler.ILAst public void Optimize(DecompilerContext context, ILBlock method, ILAstOptimizationStep abortBeforeStep = ILAstOptimizationStep.None) { + if (abortBeforeStep == ILAstOptimizationStep.InlineVariables) return; + InlineVariables(method); + if (abortBeforeStep == ILAstOptimizationStep.ReduceBranchInstructionSet) return; foreach(ILBlock block in method.GetSelfAndChildrenRecursive().ToList()) { ReduceBranchInstructionSet(block); @@ -95,6 +99,83 @@ namespace ICSharpCode.Decompiler.ILAst GotoRemoval.RemoveRedundantCode(method); } + void InlineVariables(ILBlock method) + { + // Analyse the whole method + Dictionary numStloc = new Dictionary(); + Dictionary numLdloc = new Dictionary(); + Dictionary numLdloca = new Dictionary(); + + foreach(ILExpression expr in method.GetSelfAndChildrenRecursive()) { + ILVariable locVar = expr.Operand as ILVariable; + if (locVar != null) { + if (expr.Code == ILCode.Stloc) { + numStloc[locVar] = numStloc.GetOrDefault(locVar) + 1; + } else if (expr.Code == ILCode.Ldloc) { + numLdloc[locVar] = numLdloc.GetOrDefault(locVar) + 1; + } else if (expr.Code == ILCode.Ldloca) { + numLdloca[locVar] = numLdloca.GetOrDefault(locVar) + 1; + } else { + throw new NotSupportedException(expr.Code.ToString()); + } + } + } + + // Inline all blocks + foreach(ILBlock block in method.GetSelfAndChildrenRecursive()) { + List body = block.Body; + for(int i = 0; i < body.Count - 1;) { + ILExpression nextExpr = body[i + 1] as ILExpression; + ILVariable locVar; + ILExpression expr; + ILExpression ldParent; + int ldPos; + if (body[i].Match(ILCode.Stloc, out locVar, out expr) && + numStloc.GetOrDefault(locVar) == 1 && + numLdloc.GetOrDefault(locVar) == 1 && + numLdloca.GetOrDefault(locVar) == 0 && + nextExpr != null && + FindLdloc(nextExpr, locVar, out ldParent, out ldPos) == true && + ldParent != null) + { + // Assign the ranges of the optimized instrustions + expr.ILRanges.AddRange(((ILExpression)body[i]).ILRanges); + expr.ILRanges.AddRange(ldParent.Arguments[ldPos].ILRanges); + + // We are moving the expression evaluation past the other aguments. + // It is ok to pass ldloc because the expression can not contain stloc and thus the ldloc will still return the same value + body.RemoveAt(i); + ldParent.Arguments[ldPos] = expr; // Inline the stloc body + i = Math.Max(0, i - 1); // Go back one step + } else { + i++; + } + } + } + } + + /// + /// Finds the position to inline to. + /// + /// true = found; false = cannot continue search; null = not found + static bool? FindLdloc(ILExpression expr, ILVariable v, out ILExpression parent, out int pos) + { + parent = null; + pos = 0; + for (int i = 0; i < expr.Arguments.Count; i++) { + ILExpression arg = expr.Arguments[i]; + if (arg.Code == ILCode.Ldloc && arg.Operand == v) { + parent = expr; + pos = i; + return true; + } + bool? r = FindLdloc(arg, v, out parent, out pos); + if (r != null) + return r; + } + return expr.Code == ILCode.Ldloc ? (bool?)null : false; + } + /// /// Reduces the branch codes to just br and brtrue. /// Moves ILRanges to the branch argument @@ -941,6 +1022,13 @@ namespace ICSharpCode.Decompiler.ILAst return true; } + public static V GetOrDefault(this Dictionary dict, K key) + { + V ret; + dict.TryGetValue(key, out ret); + return ret; + } + public static void RemoveOrThrow(this ICollection collection, T item) { if (!collection.Remove(item))