Permalink
Browse files

Peephole detection of the ternary operator (?:)

  • Loading branch information...
1 parent 1942385 commit 05b0b427d6e79bdff3eaaaedb13c217f3165a1f4 @dsrbecky dsrbecky committed Feb 26, 2011
@@ -285,6 +285,12 @@ AstNode TransformByteCode(ILExpression byteCode)
new Ast.GotoStatement(((ILLabel)byteCode.Operand).Name)
}
};
+ case ILCode.TernaryOp:
+ return new Ast.ConditionalExpression() {
+ Condition = MakeBranchCondition(byteCode.Arguments[0]),
+ TrueExpression = (Expression)TransformExpression(byteCode.Arguments[1]),
+ FalseExpression = (Expression)TransformExpression(byteCode.Arguments[2]),
+ };
}
List<Ast.Expression> args = TransformExpressionArguments(byteCode);
@@ -12,7 +12,7 @@ namespace Decompiler.ControlFlow
public enum ILAstOptimizationStep
{
SplitToMovableBlocks,
- ShortCircuits,
+ PeepholeOptimizations,
FindLoops,
FindConditions,
FlattenNestedMovableBlocks,
@@ -34,8 +34,11 @@ public void Optimize(DecompilerContext context, ILBlock method, ILAstOptimizatio
SplitToBasicBlocks(block);
}
- if (abortBeforeStep == ILAstOptimizationStep.ShortCircuits) return;
- OptimizeShortCircuits(method);
+ if (abortBeforeStep == ILAstOptimizationStep.PeepholeOptimizations) return;
+ AnalyseLabels(method);
+ foreach(ILBlock block in method.GetSelfAndChildrenRecursive<ILBlock>().ToList()) {
+ PeepholeOptimizations(block);
+ }
if (abortBeforeStep == ILAstOptimizationStep.FindLoops) return;
foreach(ILBlock block in method.GetSelfAndChildrenRecursive<ILBlock>().ToList()) {
@@ -132,29 +135,21 @@ void SplitToBasicBlocks(ILBlock block)
}
}
+ foreach (ILBasicBlock bb in basicBlocks) {
+ if (bb.Body.Count > 0 &&
+ bb.Body.Last() is ILExpression &&
+ ((ILExpression)bb.Body.Last()).Code == ILCode.Br)
+ {
+ Debug.Assert(bb.FallthoughGoto == null);
+ bb.FallthoughGoto = (ILExpression)bb.Body.Last();
+ bb.Body.RemoveAt(bb.Body.Count - 1);
+ }
+ }
+
block.Body = basicBlocks;
return;
}
- void OptimizeShortCircuits(ILBlock method)
- {
- AnalyseLabels(method);
-
- foreach(ILBlock block in method.GetSelfAndChildrenRecursive<ILBlock>().ToList()) {
- bool modified;
- do {
- modified = false;
- for (int i = 0; i < block.Body.Count;) {
- if (TrySimplifyShortCircuit(block.Body, (ILBasicBlock)block.Body[i])) {
- modified = true;
- } else {
- i++;
- }
- }
- } while(modified);
- }
- }
-
Dictionary<ILLabel, int> labelGlobalRefCount;
Dictionary<ILLabel, ILBasicBlock> labelToBasicBlock;
@@ -175,11 +170,34 @@ void AnalyseLabels(ILBlock method)
}
}
+ void PeepholeOptimizations(ILBlock block)
+ {
+ bool modified;
+ do {
+ modified = false;
+ for (int i = 0; i < block.Body.Count;) {
+ if (TrySimplifyShortCircuit(block.Body, (ILBasicBlock)block.Body[i])) {
+ modified = true;
+ continue;
+ }
+ if (TrySimplifyTernaryOperator(block.Body, (ILBasicBlock)block.Body[i])) {
+ modified = true;
+ continue;
+ }
+ i++;
+ }
+ } while(modified);
+ }
+
bool IsConditionalBranch(ILBasicBlock bb, ref ILExpression branchExpr, ref ILLabel trueLabel, ref ILLabel falseLabel)
{
if (bb.Body.Count == 1) {
branchExpr = bb.Body[0] as ILExpression;
- if (branchExpr != null && branchExpr.Operand is ILLabel && branchExpr.Arguments.Count > 0) {
+ if (branchExpr != null &&
+ branchExpr.Operand is ILLabel &&
+ branchExpr.Arguments.Count > 0 &&
+ branchExpr.Prefixes == null)
+ {
trueLabel = (ILLabel)branchExpr.Operand;
falseLabel = (ILLabel)((ILExpression)bb.FallthoughGoto).Operand;
return true;
@@ -188,6 +206,71 @@ bool IsConditionalBranch(ILBasicBlock bb, ref ILExpression branchExpr, ref ILLab
return false;
}
+ bool IsStloc(ILBasicBlock bb, ref ILVariable locVar, ref ILExpression val, ref ILLabel fallLabel)
+ {
+ if (bb.Body.Count == 1) {
+ ILExpression expr = bb.Body[0] as ILExpression;
+ if (expr != null &&
+ expr.Code == ILCode.Stloc &&
+ expr.Prefixes == null)
+ {
+ 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 branchExpr = 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(IsConditionalBranch(head, ref branchExpr, ref trueLabel, ref 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) &&
+ trueLocVar == falseLocVar &&
+ trueFall == falseFall)
+ {
+ // Create the ternary expression
+ head.Body = new List<ILNode>() {
+ new ILExpression(ILCode.Stloc, trueLocVar,
+ new ILExpression(ILCode.TernaryOp, null,
+ new ILExpression(branchExpr.Code, null, branchExpr.Arguments.ToArray()),
+ trueExpr,
+ falseExpr
+ )
+ )
+ };
+ head.FallthoughGoto = new ILExpression(ILCode.Br, trueFall);
+
+ // Remove the old basic blocks
+ scope.Remove(labelToBasicBlock[trueLabel]);
+ scope.Remove(labelToBasicBlock[falseLabel]);
+ labelToBasicBlock.Remove(trueLabel);
+ labelToBasicBlock.Remove(falseLabel);
+ labelGlobalRefCount.Remove(trueLabel);
+ labelGlobalRefCount.Remove(falseLabel);
+
+ return true;
+ }
+ return false;
+ }
+
// scope is modified if successful
bool TrySimplifyShortCircuit(List<ILNode> scope, ILBasicBlock head)
{
@@ -228,7 +311,8 @@ bool TrySimplifyShortCircuit(List<ILNode> scope, ILBasicBlock head)
head.FallthoughGoto = new ILExpression(ILCode.Br, nextFalseLabel);
// Remove the inlined branch from scope
- labelGlobalRefCount[nextBasicBlock.EntryLabel] = 0;
+ labelGlobalRefCount.Remove(nextBasicBlock.EntryLabel);
+ labelToBasicBlock.Remove(nextBasicBlock.EntryLabel);
if (!scope.Remove(nextBasicBlock))
throw new Exception("Element not found");
@@ -259,6 +259,7 @@ public enum ILCode
BrLogicAnd,
BrLogicOr,
InitArray, // Array Initializer
+ TernaryOp, // ?:
Pattern // used for ILAst pattern nodes
}
@@ -119,6 +119,14 @@ TypeReference DoInferTypeForExpression(ILExpression expr, TypeReference expected
InferTypeForExpression(expr.Arguments[1], typeSystem.Boolean);
}
return null;
+ case ILCode.TernaryOp:
+ if (forceInferChildren) {
+ InferTypeForExpression(expr.Arguments[0], typeSystem.Boolean);
+ }
+ return TypeWithMoreInformation(
+ InferTypeForExpression(expr.Arguments[1], expectedType, forceInferChildren),
+ InferTypeForExpression(expr.Arguments[2], expectedType, forceInferChildren)
+ );
#endregion
#region Variable load/store
case ILCode.Stloc:

0 comments on commit 05b0b42

Please sign in to comment.