Browse Source

Use short circuit logic instead of ternary operator if possible

pull/100/head
David Srbecký 14 years ago
parent
commit
d518b07f8b
  1. 95
      ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs

95
ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs

@ -17,6 +17,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -17,6 +17,7 @@ namespace ICSharpCode.Decompiler.ILAst
CopyPropagation,
YieldReturn,
SplitToMovableBlocks,
TypeInference,
PeepholeOptimizations,
FindLoops,
FindConditions,
@ -26,7 +27,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -26,7 +27,7 @@ namespace ICSharpCode.Decompiler.ILAst
FlattenIfStatements,
InlineVariables2,
PeepholeTransforms,
TypeInference,
TypeInference2,
None
}
@ -36,8 +37,12 @@ namespace ICSharpCode.Decompiler.ILAst @@ -36,8 +37,12 @@ namespace ICSharpCode.Decompiler.ILAst
Dictionary<ILLabel, ControlFlowNode> labelToCfNode = new Dictionary<ILLabel, ControlFlowNode>();
TypeSystem typeSystem;
public void Optimize(DecompilerContext context, ILBlock method, ILAstOptimizationStep abortBeforeStep = ILAstOptimizationStep.None)
{
this.typeSystem = context.CurrentMethod.Module.TypeSystem;
if (abortBeforeStep == ILAstOptimizationStep.SimpleGotoAndNopRemoval) return;
SimpleGotoAndNopRemoval(method);
@ -64,10 +69,19 @@ namespace ICSharpCode.Decompiler.ILAst @@ -64,10 +69,19 @@ namespace ICSharpCode.Decompiler.ILAst
SplitToBasicBlocks(block);
}
if (abortBeforeStep == ILAstOptimizationStep.TypeInference) return;
// Types are needed for the ternary operator optimization
TypeAnalysis.Run(context, method);
if (abortBeforeStep == ILAstOptimizationStep.PeepholeOptimizations) return;
AnalyseLabels(method);
foreach(ILBlock block in method.GetSelfAndChildrenRecursive<ILBlock>().ToList()) {
PeepholeOptimizations(block);
bool modified;
do {
modified = false;
modified |= block.RunPeepholeOptimization(TrySimplifyShortCircuit);
modified |= block.RunPeepholeOptimization(TrySimplifyTernaryOperator);
} while(modified);
}
if (abortBeforeStep == ILAstOptimizationStep.FindLoops) return;
@ -109,10 +123,15 @@ namespace ICSharpCode.Decompiler.ILAst @@ -109,10 +123,15 @@ namespace ICSharpCode.Decompiler.ILAst
// open up additional inlining possibilities.
new ILInlining(method).InlineAllVariables();
foreach (ILExpression expr in method.GetSelfAndChildrenRecursive<ILExpression>()) {
expr.InferredType = null;
expr.ExpectedType = null;
}
if (abortBeforeStep == ILAstOptimizationStep.PeepholeTransforms) return;
PeepholeTransforms.Run(context, method);
if (abortBeforeStep == ILAstOptimizationStep.TypeInference) return;
if (abortBeforeStep == ILAstOptimizationStep.TypeInference2) return;
TypeAnalysis.Run(context, method);
GotoRemoval.RemoveRedundantCode(method);
@ -265,28 +284,8 @@ namespace ICSharpCode.Decompiler.ILAst @@ -265,28 +284,8 @@ namespace ICSharpCode.Decompiler.ILAst
}
}
void PeepholeOptimizations(ILBlock block)
{
bool modified;
do {
modified = false;
for (int i = 0; i < block.Body.Count;) {
ILBasicBlock bb = (ILBasicBlock)block.Body[i];
if (TrySimplifyShortCircuit(block.Body, bb)) {
modified = true;
continue;
}
if (TrySimplifyTernaryOperator(block.Body, bb)) {
modified = true;
continue;
}
i++;
}
} while(modified);
}
// scope is modified if successful
bool TrySimplifyTernaryOperator(List<ILNode> scope, ILBasicBlock head)
bool TrySimplifyTernaryOperator(List<ILNode> scope, ILBasicBlock head, int index)
{
Debug.Assert(scope.Contains(head));
@ -308,8 +307,31 @@ namespace ICSharpCode.Decompiler.ILAst @@ -308,8 +307,31 @@ namespace ICSharpCode.Decompiler.ILAst
trueLocVar == falseLocVar &&
trueFall == falseFall)
{
// Create the ternary expression
head.Body = new List<ILNode>() { new ILExpression(ILCode.Stloc, trueLocVar, new ILExpression(ILCode.TernaryOp, null, condExpr, trueExpr, falseExpr)) };
int boolVal;
ILExpression newExpr;
// a ? true : b is equvalent to a || b
// a ? b : true is equvalent to !a || b
// a ? b : false is equvalent to a && b
// a ? false : b is equvalent to !a && b
if (trueLocVar.Type == typeSystem.Boolean && trueExpr.Match(ILCode.Ldc_I4, out boolVal)) {
// It can be expressed as logical expression
if (boolVal != 0) {
newExpr = new ILExpression(ILCode.LogicOr, null, condExpr, falseExpr);
} else {
newExpr = new ILExpression(ILCode.LogicAnd, null, new ILExpression(ILCode.LogicNot, null, condExpr), falseExpr);
}
} else if (trueLocVar.Type == typeSystem.Boolean && falseExpr.Match(ILCode.Ldc_I4, out boolVal)) {
// It can be expressed as logical expression
if (boolVal != 0) {
newExpr = new ILExpression(ILCode.LogicOr, null, new ILExpression(ILCode.LogicNot, null, condExpr), trueExpr);
} else {
newExpr = new ILExpression(ILCode.LogicAnd, null, condExpr, trueExpr);
}
} else {
// Create ternary expression
newExpr = new ILExpression(ILCode.TernaryOp, null, condExpr, trueExpr, falseExpr);
}
head.Body = new List<ILNode>() { new ILExpression(ILCode.Stloc, trueLocVar, newExpr) };
head.FallthoughGoto = new ILExpression(ILCode.Br, trueFall);
// Remove the old basic blocks
@ -326,7 +348,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -326,7 +348,7 @@ namespace ICSharpCode.Decompiler.ILAst
}
// scope is modified if successful
bool TrySimplifyShortCircuit(List<ILNode> scope, ILBasicBlock head)
bool TrySimplifyShortCircuit(List<ILNode> scope, ILBasicBlock head, int index)
{
Debug.Assert(scope.Contains(head));
@ -977,6 +999,25 @@ namespace ICSharpCode.Decompiler.ILAst @@ -977,6 +999,25 @@ namespace ICSharpCode.Decompiler.ILAst
return false;
}
/// <summary>
/// Perform one pass of a given optimization on this block.
/// This block must consist of only basicblocks.
/// </summary>
public static bool RunPeepholeOptimization(this ILBlock block, Func<List<ILNode>, ILBasicBlock, int, bool> optimization)
{
bool modified = false;
List<ILNode> body = block.Body;
for (int i = 0; i < body.Count;) {
if (optimization(body, (ILBasicBlock)body[i], i)) {
modified = true;
i = Math.Max(0, i - 1); // Go back one step
} else {
i++;
}
}
return modified;
}
public static bool CanFallThough(this ILNode node)
{
ILExpression expr = node as ILExpression;

Loading…
Cancel
Save