Browse Source

Minor refactoring of ILAst pattern matching

pull/70/head
David Srbecký 15 years ago
parent
commit
4c38e164de
  1. 112
      ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs

112
ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs

@ -236,40 +236,26 @@ namespace ICSharpCode.Decompiler.ILAst @@ -236,40 +236,26 @@ namespace ICSharpCode.Decompiler.ILAst
} while(modified);
}
bool IsStloc(ILBasicBlock bb, ref ILVariable locVar, ref ILExpression val, ref ILLabel fallLabel)
{
if (bb.Body.Count == 1) {
ILExpression expr;
if (bb.Body[0].Match(ILCode.Stloc, out expr)) {
locVar = (ILVariable)expr.Operand;
val = expr.Arguments[0];
fallLabel = (ILLabel)bb.FallthoughGoto.Operand;
return true;
}
}
return false;
}
// scope is modified if successful
bool TrySimplifyTernaryOperator(List<ILNode> scope, ILBasicBlock head)
{
Debug.Assert(scope.Contains(head));
ILExpression condExpr = null;
ILLabel trueLabel = null;
ILLabel falseLabel = null;
ILVariable trueLocVar = null;
ILExpression trueExpr = null;
ILLabel trueFall = null;
ILVariable falseLocVar = null;
ILExpression falseExpr = null;
ILLabel falseFall = null;
if(head.MatchBrTure(out condExpr, out trueLabel, out falseLabel) &&
ILExpression condExpr;
ILLabel trueLabel;
ILLabel falseLabel;
ILVariable trueLocVar;
ILExpression trueExpr;
ILLabel trueFall;
ILVariable falseLocVar;
ILExpression falseExpr;
ILLabel falseFall;
if(head.Match(ILCode.Brtrue, out trueLabel, out condExpr, out falseLabel) &&
labelGlobalRefCount[trueLabel] == 1 &&
labelGlobalRefCount[falseLabel] == 1 &&
IsStloc(labelToBasicBlock[trueLabel], ref trueLocVar, ref trueExpr, ref trueFall) &&
IsStloc(labelToBasicBlock[falseLabel], ref falseLocVar, ref falseExpr, ref falseFall) &&
labelToBasicBlock[trueLabel].Match(ILCode.Stloc, out trueLocVar, out trueExpr, out trueFall) &&
labelToBasicBlock[falseLabel].Match(ILCode.Stloc, out falseLocVar, out falseExpr, out falseFall) &&
trueLocVar == falseLocVar &&
trueFall == falseFall)
{
@ -298,7 +284,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -298,7 +284,7 @@ namespace ICSharpCode.Decompiler.ILAst
ILExpression condExpr;
ILLabel trueLabel;
ILLabel falseLabel;
if(head.MatchBrTure(out condExpr, out trueLabel, out falseLabel)) {
if(head.Match(ILCode.Brtrue, out trueLabel, out condExpr, out falseLabel)) {
for (int pass = 0; pass < 2; pass++) {
// On the second pass, swap labels and negate expression of the first branch
@ -314,7 +300,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -314,7 +300,7 @@ namespace ICSharpCode.Decompiler.ILAst
if (scope.Contains(nextBasicBlock) &&
nextBasicBlock != head &&
labelGlobalRefCount[nextBasicBlock.EntryLabel] == 1 &&
nextBasicBlock.MatchBrTure(out nextCondExpr, out nextTrueLablel, out nextFalseLabel) &&
nextBasicBlock.Match(ILCode.Brtrue, out nextTrueLablel, out nextCondExpr, out nextFalseLabel) &&
(otherLablel == nextFalseLabel || otherLablel == nextTrueLablel))
{
// Create short cicuit branch
@ -355,9 +341,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -355,9 +341,7 @@ namespace ICSharpCode.Decompiler.ILAst
foreach(ILBlock block in method.GetSelfAndChildrenRecursive<ILBlock>()) {
for (int i = 0; i < block.Body.Count; i++) {
ILLabel targetLabel;
if (block.Body[i].Match(ILCode.Br, out targetLabel) ||
block.Body[i].Match(ILCode.Leave, out targetLabel))
{
if (block.Body[i].Match(ILCode.Br, out targetLabel) || block.Body[i].Match(ILCode.Leave, out targetLabel)) {
// Skip extra labels
while(nextSibling.ContainsKey(targetLabel) && nextSibling[targetLabel] is ILLabel) {
targetLabel = (ILLabel)nextSibling[targetLabel];
@ -365,17 +349,17 @@ namespace ICSharpCode.Decompiler.ILAst @@ -365,17 +349,17 @@ namespace ICSharpCode.Decompiler.ILAst
// Inline return statement
ILNode target;
ILExpression retExpr;
List<ILExpression> retArgs;
if (nextSibling.TryGetValue(targetLabel, out target) &&
target.Match(ILCode.Ret, out retExpr))
target.Match(ILCode.Ret, out retArgs))
{
ILVariable locVar;
object constValue;
if (retExpr.Arguments.Count == 0) {
if (retArgs.Count == 0) {
block.Body[i] = new ILExpression(ILCode.Ret, null);
} else if (retExpr.Arguments.Single().Match(ILCode.Ldloc, out locVar)) {
} else if (retArgs.Single().Match(ILCode.Ldloc, out locVar)) {
block.Body[i] = new ILExpression(ILCode.Ret, null, new ILExpression(ILCode.Ldloc, locVar));
} else if (retExpr.Arguments.Single().Match(ILCode.Ldc_I4, out constValue)) {
} else if (retArgs.Single().Match(ILCode.Ldc_I4, out constValue)) {
block.Body[i] = new ILExpression(ILCode.Ret, null, new ILExpression(ILCode.Ldc_I4, constValue));
}
}
@ -467,7 +451,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -467,7 +451,7 @@ namespace ICSharpCode.Decompiler.ILAst
ILExpression condExpr;
ILLabel trueLabel;
ILLabel falseLabel;
if(basicBlock.MatchBrTure(out condExpr, out trueLabel, out falseLabel))
if(basicBlock.Match(ILCode.Brtrue, out trueLabel, out condExpr, out falseLabel))
{
ControlFlowNode trueTarget;
labelToCfNode.TryGetValue(trueLabel, out trueTarget);
@ -581,9 +565,10 @@ namespace ICSharpCode.Decompiler.ILAst @@ -581,9 +565,10 @@ namespace ICSharpCode.Decompiler.ILAst
// Switch
ILLabel[] caseLabels;
if (condBranch.Match(ILCode.Switch, out caseLabels)) {
List<ILExpression> switchArgs;
if (condBranch.Match(ILCode.Switch, out caseLabels, out switchArgs)) {
ILSwitch ilSwitch = new ILSwitch() { Condition = condBranch.Arguments.Single() };
ILSwitch ilSwitch = new ILSwitch() { Condition = switchArgs.Single() };
ILBasicBlock newBB = new ILBasicBlock() {
EntryLabel = block.EntryLabel, // Keep the entry label
Body = { ilSwitch },
@ -662,7 +647,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -662,7 +647,7 @@ namespace ICSharpCode.Decompiler.ILAst
ILExpression condExpr;
ILLabel trueLabel;
ILLabel falseLabel;
if(block.MatchBrTure(out condExpr, out trueLabel, out falseLabel)) {
if(block.Match(ILCode.Brtrue, out trueLabel, out condExpr, out falseLabel)) {
// Swap bodies since that seems to be the usual C# order
ILLabel temp = trueLabel;
@ -852,17 +837,12 @@ namespace ICSharpCode.Decompiler.ILAst @@ -852,17 +837,12 @@ namespace ICSharpCode.Decompiler.ILAst
return expr != null && expr.Prefixes == null && expr.Code == code;
}
public static bool Match(this ILNode node, ILCode code, out ILExpression expr)
{
expr = node as ILExpression;
return expr != null && expr.Prefixes == null && expr.Code == code;
}
public static bool Match<T>(this ILNode node, ILCode code, out T operand)
{
ILExpression expr = node as ILExpression;
if (expr != null && expr.Prefixes == null && expr.Code == code) {
operand = (T)expr.Operand;
Debug.Assert(expr.Arguments.Count == 0);
return true;
}
operand = default(T);
@ -873,6 +853,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -873,6 +853,7 @@ namespace ICSharpCode.Decompiler.ILAst
{
ILExpression expr = node as ILExpression;
if (expr != null && expr.Prefixes == null && expr.Code == code) {
Debug.Assert(expr.Operand == null);
args = expr.Arguments;
return true;
}
@ -880,18 +861,41 @@ namespace ICSharpCode.Decompiler.ILAst @@ -880,18 +861,41 @@ namespace ICSharpCode.Decompiler.ILAst
return false;
}
public static bool MatchBrTure(this ILBasicBlock bb, out ILExpression condition, out ILLabel trueLabel, out ILLabel falseLabel)
public static bool Match<T>(this ILNode node, ILCode code, out T operand, out List<ILExpression> args)
{
ILExpression expr = node as ILExpression;
if (expr != null && expr.Prefixes == null && expr.Code == code) {
operand = (T)expr.Operand;
args = expr.Arguments;
return true;
}
operand = default(T);
args = null;
return false;
}
public static bool Match<T>(this ILNode node, ILCode code, out T operand, out ILExpression arg)
{
List<ILExpression> args;
if (node.Match(code, out operand, out args)) {
arg = args.Single();
return true;
}
arg = null;
return false;
}
public static bool Match<T>(this ILBasicBlock bb, ILCode code, out T operand, out ILExpression arg, out ILLabel fallLabel)
{
if (bb.Body.Count == 1) {
if (bb.Body[0].Match(ILCode.Brtrue, out trueLabel)) {
condition = ((ILExpression)bb.Body[0]).Arguments.Single();
falseLabel = (ILLabel)((ILExpression)bb.FallthoughGoto).Operand;
if (bb.Body[0].Match(code, out operand, out arg)) {
fallLabel = (ILLabel)bb.FallthoughGoto.Operand;
return true;
}
}
condition = null;
trueLabel = null;
falseLabel = null;
operand = default(T);
arg = null;
fallLabel = null;
return false;
}

Loading…
Cancel
Save