Browse Source

Moved inlineing from Builder to Optimizer

pull/70/head
David Srbecký 15 years ago
parent
commit
897ac7fe04
  1. 59
      ICSharpCode.Decompiler/ILAst/ILAstBuilder.cs
  2. 88
      ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs

59
ICSharpCode.Decompiler/ILAst/ILAstBuilder.cs

@ -201,9 +201,6 @@ namespace ICSharpCode.Decompiler.ILAst @@ -201,9 +201,6 @@ namespace ICSharpCode.Decompiler.ILAst
MethodDefinition methodDef;
bool optimize;
Dictionary<Instruction, ByteCode> instrToByteCode = new Dictionary<Instruction, ByteCode>();
Dictionary<ILVariable, bool> allowInline = new Dictionary<ILVariable, bool>();
// Virtual instructions to load exception on stack
Dictionary<ExceptionHandler, ByteCode> ldexceptions = new Dictionary<ExceptionHandler, ILAstBuilder.ByteCode>();
@ -223,6 +220,8 @@ namespace ICSharpCode.Decompiler.ILAst @@ -223,6 +220,8 @@ namespace ICSharpCode.Decompiler.ILAst
List<ByteCode> StackAnalysis(MethodDefinition methodDef)
{
Dictionary<Instruction, ByteCode> instrToByteCode = new Dictionary<Instruction, ByteCode>();
// Create temporary structure for the stack analysis
List<ByteCode> body = new List<ByteCode>(methodDef.Body.Instructions.Count);
List<Instruction> prefixes = null;
@ -406,9 +405,6 @@ namespace ICSharpCode.Decompiler.ILAst @@ -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 @@ -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 @@ -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;
}
}

88
ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs

@ -11,6 +11,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -11,6 +11,7 @@ namespace ICSharpCode.Decompiler.ILAst
{
public enum ILAstOptimizationStep
{
InlineVariables,
ReduceBranchInstructionSet,
YieldReturn,
SplitToMovableBlocks,
@ -34,6 +35,9 @@ namespace ICSharpCode.Decompiler.ILAst @@ -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<ILBlock>().ToList()) {
ReduceBranchInstructionSet(block);
@ -95,6 +99,83 @@ namespace ICSharpCode.Decompiler.ILAst @@ -95,6 +99,83 @@ namespace ICSharpCode.Decompiler.ILAst
GotoRemoval.RemoveRedundantCode(method);
}
void InlineVariables(ILBlock method)
{
// Analyse the whole method
Dictionary<ILVariable, int> numStloc = new Dictionary<ILVariable, int>();
Dictionary<ILVariable, int> numLdloc = new Dictionary<ILVariable, int>();
Dictionary<ILVariable, int> numLdloca = new Dictionary<ILVariable, int>();
foreach(ILExpression expr in method.GetSelfAndChildrenRecursive<ILExpression>()) {
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<ILBlock>()) {
List<ILNode> 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++;
}
}
}
}
/// <summary>
/// Finds the position to inline to.
/// </summary>
/// <returns>true = found; false = cannot continue search; null = not found</returns>
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;
}
/// <summary>
/// Reduces the branch codes to just br and brtrue.
/// Moves ILRanges to the branch argument
@ -941,6 +1022,13 @@ namespace ICSharpCode.Decompiler.ILAst @@ -941,6 +1022,13 @@ namespace ICSharpCode.Decompiler.ILAst
return true;
}
public static V GetOrDefault<K,V>(this Dictionary<K, V> dict, K key)
{
V ret;
dict.TryGetValue(key, out ret);
return ret;
}
public static void RemoveOrThrow<T>(this ICollection<T> collection, T item)
{
if (!collection.Remove(item))

Loading…
Cancel
Save