Browse Source

implement basic support for custom short circuit operators + unit test; fixes #193

pull/143/merge
Siegfried Pammer 14 years ago
parent
commit
a929decdeb
  1. 4
      ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs
  2. 80
      ICSharpCode.Decompiler/ILAst/SimpleControlFlow.cs
  3. 4
      ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs
  4. 43
      ICSharpCode.Decompiler/Tests/CustomShortCircuitOperators.cs
  5. 1
      ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj
  6. 6
      ICSharpCode.Decompiler/Tests/TestRunner.cs

4
ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs

@ -44,6 +44,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -44,6 +44,7 @@ namespace ICSharpCode.Decompiler.ILAst
JoinBasicBlocks,
TransformDecimalCtorToConstant,
SimplifyLdObjAndStObj,
SimplifyCustomShortCircuit,
TransformArrayInitializers,
TransformObjectInitializers,
MakeAssignmentExpression,
@ -136,6 +137,9 @@ namespace ICSharpCode.Decompiler.ILAst @@ -136,6 +137,9 @@ namespace ICSharpCode.Decompiler.ILAst
if (abortBeforeStep == ILAstOptimizationStep.SimplifyLdObjAndStObj) return;
modified |= block.RunOptimization(SimplifyLdObjAndStObj);
if (abortBeforeStep == ILAstOptimizationStep.SimplifyCustomShortCircuit) return;
modified |= block.RunOptimization(new SimpleControlFlow(context, method).SimplifyCustomShortCircuit);
if (abortBeforeStep == ILAstOptimizationStep.TransformArrayInitializers) return;
modified |= block.RunOptimization(TransformArrayInitializers);

80
ICSharpCode.Decompiler/ILAst/SimpleControlFlow.cs

@ -165,7 +165,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -165,7 +165,7 @@ namespace ICSharpCode.Decompiler.ILAst
ILBasicBlock rightBB;
ILExpression rightExpr;
if (head.Body.Count >= 3 &&
head.Body[head.Body.Count - 3].Match(ILCode.Stloc, out v, out leftExpr) &&
head.Body[head.Body.Count - 3].Match(ILCode.Stloc, out v, out leftExpr) &&
leftExpr.Match(ILCode.Ldloc, out leftVar) &&
head.MatchLastAndBr(ILCode.Brtrue, out endBBLabel, out leftExpr2, out rightBBLabel) &&
leftExpr2.MatchLdloc(leftVar) &&
@ -234,6 +234,84 @@ namespace ICSharpCode.Decompiler.ILAst @@ -234,6 +234,84 @@ namespace ICSharpCode.Decompiler.ILAst
return false;
}
public bool SimplifyCustomShortCircuit(List<ILNode> body, ILBasicBlock head, int pos)
{
Debug.Assert(body.Contains(head));
// --- looking for the following pattern ---
// stloc(targetVar, leftVar)
// brtrue(exitLabel, call(op_False, leftVar)
// br(followingBlock)
//
// FollowingBlock:
// stloc(targetVar, call(op_BitwiseAnd, leftVar, rightExpression))
// br(exitLabel)
// ---
if (head.Body.Count < 3)
return false;
// looking for:
// stloc(targetVar, leftVar)
ILVariable targetVar;
ILExpression targetVarInitExpr;
if (!head.Body[head.Body.Count - 3].Match(ILCode.Stloc, out targetVar, out targetVarInitExpr))
return false;
// looking for:
// brtrue(exitLabel, call(op_False, leftVar)
// br(followingBlock)
ILExpression callExpr;
ILLabel exitLabel;
ILLabel followingBlock;
if(!head.MatchLastAndBr(ILCode.Brtrue, out exitLabel, out callExpr, out followingBlock))
return false;
MethodDefinition opFalse;
ILExpression leftVar;
if (!callExpr.Match(ILCode.Call, out opFalse, out leftVar))
return false;
if (!leftVar.MatchLdloc(targetVarInitExpr.Operand as ILVariable))
return false;
ILBasicBlock followingBasicBlock = labelToBasicBlock[followingBlock];
// FollowingBlock:
// stloc(targetVar, call(op_BitwiseAnd, leftVar, rightExpression))
// br(exitLabel)
ILVariable _targetVar;
ILExpression opBitwiseCallExpr;
ILLabel _exitLabel;
if (!followingBasicBlock.MatchSingleAndBr(ILCode.Stloc, out _targetVar, out opBitwiseCallExpr, out _exitLabel))
return false;
if (_targetVar != targetVar)
return false;
MethodDefinition opBitwise;
ILExpression leftVarExpression;
ILExpression rightExpression;
if (!opBitwiseCallExpr.Match(ILCode.Call, out opBitwise, out leftVarExpression, out rightExpression))
return false;
if (!leftVar.MatchLdloc(leftVarExpression.Operand as ILVariable))
return false;
// insert:
// stloc(targetVar, LogicAnd(C::op_BitwiseAnd, leftVar, rightExpression)
// br(exitLabel)
ILExpression shortCircuitExpr = MakeLeftAssociativeShortCircuit(opBitwise.Name == "op_BitwiseAnd" ? ILCode.LogicAnd : ILCode.LogicOr, leftVar, rightExpression);
shortCircuitExpr.Operand = opBitwise;
head.Body.RemoveTail(ILCode.Stloc, ILCode.Brtrue, ILCode.Br);
head.Body.Add(new ILExpression(ILCode.Stloc, targetVar, shortCircuitExpr));
head.Body.Add(new ILExpression(ILCode.Br, exitLabel));
body.Remove(followingBasicBlock);
return true;
}
ILExpression MakeLeftAssociativeShortCircuit(ILCode code, ILExpression left, ILExpression right)
{
// Assuming that the inputs are already left associative

4
ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs

@ -267,6 +267,10 @@ namespace ICSharpCode.Decompiler.ILAst @@ -267,6 +267,10 @@ namespace ICSharpCode.Decompiler.ILAst
return typeSystem.Boolean;
case ILCode.LogicAnd:
case ILCode.LogicOr:
// if Operand is set the logic and/or expression is a custom operator
// we can deal with it the same as a normal invocation.
if (expr.Operand != null)
goto case ILCode.Call;
if (forceInferChildren) {
InferTypeForExpression(expr.Arguments[0], typeSystem.Boolean);
InferTypeForExpression(expr.Arguments[1], typeSystem.Boolean);

43
ICSharpCode.Decompiler/Tests/CustomShortCircuitOperators.cs

@ -0,0 +1,43 @@ @@ -0,0 +1,43 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under MIT X11 license (for details please see \doc\license.txt)
using System;
public static class CustomShortCircuitOperators
{
private class B
{
public static bool operator true(CustomShortCircuitOperators.B x)
{
return true;
}
public static bool operator false(CustomShortCircuitOperators.B x)
{
return false;
}
}
private class C : CustomShortCircuitOperators.B
{
public static CustomShortCircuitOperators.C operator &(CustomShortCircuitOperators.C x, CustomShortCircuitOperators.C y)
{
return null;
}
public static CustomShortCircuitOperators.C operator |(CustomShortCircuitOperators.C x, CustomShortCircuitOperators.C y)
{
return null;
}
private static void Main()
{
CustomShortCircuitOperators.C c = new CustomShortCircuitOperators.C();
CustomShortCircuitOperators.C c2 = new CustomShortCircuitOperators.C();
CustomShortCircuitOperators.C c3 = c && c2;
CustomShortCircuitOperators.C c4 = c || c2;
Console.WriteLine(c3.ToString());
Console.WriteLine(c4.ToString());
}
}
}

1
ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj

@ -57,6 +57,7 @@ @@ -57,6 +57,7 @@
<ItemGroup>
<Compile Include="CallOverloadedMethod.cs" />
<Compile Include="CheckedUnchecked.cs" />
<Compile Include="CustomShortCircuitOperators.cs" />
<Compile Include="Helpers\CodeAssert.cs" />
<Compile Include="IncrementDecrement.cs" />
<Compile Include="PInvoke.cs" />

6
ICSharpCode.Decompiler/Tests/TestRunner.cs

@ -49,6 +49,12 @@ namespace ICSharpCode.Decompiler.Tests @@ -49,6 +49,12 @@ namespace ICSharpCode.Decompiler.Tests
TestFile(@"..\..\Tests\Generics.cs");
}
[Test]
public void CustomShortCircuitOperators()
{
TestFile(@"..\..\Tests\CustomShortCircuitOperators.cs");
}
[Test]
public void IncrementDecrement()
{

Loading…
Cancel
Save