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

Loading…
Cancel
Save