Browse Source

Perform copy propagation for all address-loading instructions.

pull/100/head
Daniel Grunwald 15 years ago
parent
commit
fa05b733ee
  1. 64
      ICSharpCode.Decompiler/ILAst/ILInlining.cs
  2. 23
      ICSharpCode.Decompiler/Tests/ValueTypes.cs

64
ICSharpCode.Decompiler/ILAst/ILInlining.cs

@ -25,6 +25,17 @@ namespace ICSharpCode.Decompiler.ILAst @@ -25,6 +25,17 @@ namespace ICSharpCode.Decompiler.ILAst
public ILInlining(ILBlock method)
{
this.method = method;
AnalyzeMethod();
}
void AnalyzeMethod()
{
numStloc.Clear();
numLdloc.Clear();
numLdloca.Clear();
numStarg.Clear();
numLdarga.Clear();
// Analyse the whole method
foreach(ILExpression expr in method.GetSelfAndChildrenRecursive<ILExpression>()) {
ILVariable locVar = expr.Operand as ILVariable;
@ -203,6 +214,17 @@ namespace ICSharpCode.Decompiler.ILAst @@ -203,6 +214,17 @@ namespace ICSharpCode.Decompiler.ILAst
if (r != null)
return r;
}
if (IsSafeForInlineOver(expr, expressionBeingMoved))
return null; // continue searching
else
return false; // abort, inlining not possible
}
/// <summary>
/// Determines whether it is save to move 'expressionBeingMoved' past 'expr'
/// </summary>
bool IsSafeForInlineOver(ILExpression expr, ILExpression expressionBeingMoved)
{
switch (expr.Code) {
case ILCode.Ldloc:
ILVariable loadedVar = (ILVariable)expr.Operand;
@ -214,9 +236,8 @@ namespace ICSharpCode.Decompiler.ILAst @@ -214,9 +236,8 @@ namespace ICSharpCode.Decompiler.ILAst
if (potentialStore.Code == ILCode.Stloc && potentialStore.Operand == loadedVar)
return false;
}
// the expression is loading a non-forbidden variable:
// we're allowed to continue searching
return null;
// the expression is loading a non-forbidden variable
return true;
case ILCode.Ldarg:
// Also try moving over ldarg instructions - this is necessary because an earlier copy propagation
// step might have introduced ldarg in place of an ldloc that would be skipped.
@ -227,12 +248,18 @@ namespace ICSharpCode.Decompiler.ILAst @@ -227,12 +248,18 @@ namespace ICSharpCode.Decompiler.ILAst
if (potentialStore.Code == ILCode.Starg && potentialStore.Operand == loadedParam)
return false;
}
return null;
return true;
case ILCode.Ldloca:
case ILCode.Ldarga:
// Continue searching:
// It is always safe to move code past an instruction that loads a constant.
return null;
case ILCode.Ldflda:
case ILCode.Ldsflda:
case ILCode.Ldelema:
// address-loading instructions are safe if their arguments are safe
foreach (ILExpression arg in expr.Arguments) {
if (!IsSafeForInlineOver(arg, expressionBeingMoved))
return false;
}
return true;
default:
// abort, inlining is not possible
return false;
@ -268,17 +295,31 @@ namespace ICSharpCode.Decompiler.ILAst @@ -268,17 +295,31 @@ namespace ICSharpCode.Decompiler.ILAst
&& numStloc.GetOrDefault(v) == 1 && numLdloca.GetOrDefault(v) == 0
&& CanPerformCopyPropagation(ldArg))
{
// un-inline the arguments of the ldArg instruction
ILVariable[] uninlinedArgs = new ILVariable[ldArg.Arguments.Count];
for (int j = 0; j < uninlinedArgs.Length; j++) {
uninlinedArgs[j] = new ILVariable { IsGenerated = true, Name = v.Name + "_cp_" + j };
block.Body.Insert(i++, new ILExpression(ILCode.Stloc, uninlinedArgs[j], ldArg.Arguments[j]));
}
// perform copy propagation:
foreach (var expr in method.GetSelfAndChildrenRecursive<ILExpression>()) {
if (expr.Code == ILCode.Ldloc && expr.Operand == v) {
expr.Code = ldArg.Code;
expr.Operand = ldArg.Operand;
for (int j = 0; j < uninlinedArgs.Length; j++) {
expr.Arguments.Add(new ILExpression(ILCode.Ldloc, uninlinedArgs[j]));
}
}
}
block.Body.RemoveAt(i);
if (uninlinedArgs.Length > 0) {
// if we un-inlined stuff; we need to update the usage counters
AnalyzeMethod();
}
InlineInto(block, i, aggressive: false); // maybe inlining gets possible after the removal of block.Body[i]
i--;
i -= uninlinedArgs.Length + 1;
}
}
}
@ -289,7 +330,12 @@ namespace ICSharpCode.Decompiler.ILAst @@ -289,7 +330,12 @@ namespace ICSharpCode.Decompiler.ILAst
switch (ldArg.Code) {
case ILCode.Ldloca:
case ILCode.Ldarga:
return true; // ldloca/ldarga always return the same value for a given operand, so they can be safely copied
case ILCode.Ldelema:
case ILCode.Ldflda:
case ILCode.Ldsflda:
// All address-loading instructions always return the same value for a given operand/argument combination,
// so they can be safely copied.
return true;
case ILCode.Ldarg:
// arguments can be copied only if they aren't assigned to (directly or indirectly via ldarga)
ParameterDefinition pd = (ParameterDefinition)ldArg.Operand;

23
ICSharpCode.Decompiler/Tests/ValueTypes.cs

@ -87,4 +87,27 @@ public static class ValueTypes @@ -87,4 +87,27 @@ public static class ValueTypes
// test passing through by-ref arguments
Copy4(ref p, out o);
}
public static void Issue56(int i, out string str)
{
str = "qq";
str += i.ToString();
}
public static void CopyAroundAndModifyField(S s)
{
S locS = s;
locS.Field += 10;
s = locS;
}
static int[] MakeArray()
{
return null;
}
public static void IncrementArrayLocation()
{
MakeArray()[Environment.TickCount]++;
}
}

Loading…
Cancel
Save