Browse Source

Reduced branch codes to just br and brtrue

pull/70/head
David Srbecký 15 years ago
parent
commit
01de42c04a
  1. 118
      ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs
  2. 188
      ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs
  3. 8
      ICSharpCode.Decompiler/ILAst/ILAstTypes.cs
  4. 52
      ICSharpCode.Decompiler/ILAst/ILCodes.cs
  5. 19
      ICSharpCode.Decompiler/ILAst/PeepholeTransform.cs
  6. 34
      ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs

118
ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs

@ -108,7 +108,7 @@ namespace ICSharpCode.Decompiler.Ast
} else if (node is ILWhileLoop) { } else if (node is ILWhileLoop) {
ILWhileLoop ilLoop = (ILWhileLoop)node; ILWhileLoop ilLoop = (ILWhileLoop)node;
WhileStatement whileStmt = new WhileStatement() { WhileStatement whileStmt = new WhileStatement() {
Condition = ilLoop.Condition != null ? MakeBranchCondition(ilLoop.Condition) : new PrimitiveExpression(true), Condition = ilLoop.Condition != null ? (Expression)TransformExpression(ilLoop.Condition) : new PrimitiveExpression(true),
EmbeddedStatement = TransformBlock(ilLoop.BodyBlock) EmbeddedStatement = TransformBlock(ilLoop.BodyBlock)
}; };
yield return whileStmt; yield return whileStmt;
@ -116,7 +116,7 @@ namespace ICSharpCode.Decompiler.Ast
ILCondition conditionalNode = (ILCondition)node; ILCondition conditionalNode = (ILCondition)node;
bool hasFalseBlock = conditionalNode.FalseBlock.EntryGoto != null || conditionalNode.FalseBlock.Body.Count > 0; bool hasFalseBlock = conditionalNode.FalseBlock.EntryGoto != null || conditionalNode.FalseBlock.Body.Count > 0;
yield return new Ast.IfElseStatement { yield return new Ast.IfElseStatement {
Condition = MakeBranchCondition(conditionalNode.Condition), Condition = (Expression)TransformExpression(conditionalNode.Condition),
TrueStatement = TransformBlock(conditionalNode.TrueBlock), TrueStatement = TransformBlock(conditionalNode.TrueBlock),
FalseStatement = hasFalseBlock ? TransformBlock(conditionalNode.FalseBlock) : null FalseStatement = hasFalseBlock ? TransformBlock(conditionalNode.FalseBlock) : null
}; };
@ -166,58 +166,6 @@ namespace ICSharpCode.Decompiler.Ast
return args; return args;
} }
Ast.Expression MakeBranchCondition(ILExpression expr)
{
switch(expr.Code) {
case ILCode.LogicNot:
return new Ast.UnaryOperatorExpression(UnaryOperatorType.Not, MakeBranchCondition(expr.Arguments[0]));
case ILCode.BrLogicAnd:
return new Ast.BinaryOperatorExpression(
MakeBranchCondition(expr.Arguments[0]),
BinaryOperatorType.ConditionalAnd,
MakeBranchCondition(expr.Arguments[1])
);
case ILCode.BrLogicOr:
return new Ast.BinaryOperatorExpression(
MakeBranchCondition(expr.Arguments[0]),
BinaryOperatorType.ConditionalOr,
MakeBranchCondition(expr.Arguments[1])
);
}
List<Ast.Expression> args = TransformExpressionArguments(expr);
Ast.Expression arg1 = args.Count >= 1 ? args[0] : null;
Ast.Expression arg2 = args.Count >= 2 ? args[1] : null;
switch((Code)expr.Code) {
case Code.Brfalse:
return new Ast.UnaryOperatorExpression(UnaryOperatorType.Not, arg1);
case Code.Brtrue:
return arg1;
case Code.Beq:
return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Equality, arg2);
case Code.Bge:
return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThanOrEqual, arg2);
case Code.Bge_Un:
return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThanOrEqual, arg2);
case Code.Bgt:
return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThan, arg2);
case Code.Bgt_Un:
return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThan, arg2);
case Code.Ble:
return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThanOrEqual, arg2);
case Code.Ble_Un:
return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThanOrEqual, arg2);
case Code.Blt:
return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2);
case Code.Blt_Un:
return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2);
case Code.Bne_Un:
return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.InEquality, arg2);
default:
throw new Exception("Bad opcode");
}
}
static string FormatByteCodeOperand(object operand) static string FormatByteCodeOperand(object operand)
{ {
if (operand == null) { if (operand == null) {
@ -255,53 +203,15 @@ namespace ICSharpCode.Decompiler.Ast
AstNode TransformByteCode(ILExpression byteCode) AstNode TransformByteCode(ILExpression byteCode)
{ {
ILCode opCode = byteCode.Code;
object operand = byteCode.Operand; object operand = byteCode.Operand;
AstType operandAsTypeRef = AstBuilder.ConvertType(operand as Cecil.TypeReference); AstType operandAsTypeRef = AstBuilder.ConvertType(operand as Cecil.TypeReference);
ILExpression operandAsByteCode = operand as ILExpression;
// Do branches first because TransformExpressionArguments does not work on arguments that are branches themselfs
// TODO: We should probably have virtual instructions for these and not abuse branch codes as expressions
switch(opCode) {
case ILCode.Br: return new Ast.GotoStatement(((ILLabel)byteCode.Operand).Name);
case ILCode.Brfalse:
case ILCode.Brtrue:
case ILCode.Beq:
case ILCode.Bge:
case ILCode.Bge_Un:
case ILCode.Bgt:
case ILCode.Bgt_Un:
case ILCode.Ble:
case ILCode.Ble_Un:
case ILCode.Blt:
case ILCode.Blt_Un:
case ILCode.Bne_Un:
case ILCode.BrLogicAnd:
case ILCode.BrLogicOr:
return new Ast.IfElseStatement() {
Condition = MakeBranchCondition(byteCode),
TrueStatement = new BlockStatement() {
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]),
};
case ILCode.LoopBreak:
return new Ast.BreakStatement();
case ILCode.LoopContinue:
return new Ast.ContinueStatement();
}
List<Ast.Expression> args = TransformExpressionArguments(byteCode); List<Ast.Expression> args = TransformExpressionArguments(byteCode);
Ast.Expression arg1 = args.Count >= 1 ? args[0] : null; Ast.Expression arg1 = args.Count >= 1 ? args[0] : null;
Ast.Expression arg2 = args.Count >= 2 ? args[1] : null; Ast.Expression arg2 = args.Count >= 2 ? args[1] : null;
Ast.Expression arg3 = args.Count >= 3 ? args[2] : null; Ast.Expression arg3 = args.Count >= 3 ? args[2] : null;
switch(opCode) { switch(byteCode.Code) {
#region Arithmetic #region Arithmetic
case ILCode.Add: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2); case ILCode.Add: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2);
case ILCode.Add_Ovf: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2); case ILCode.Add_Ovf: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2);
@ -337,7 +247,7 @@ namespace ICSharpCode.Decompiler.Ast
// change "new (int[,])[10] to new int[10][,]" // change "new (int[,])[10] to new int[10][,]"
ct.ArraySpecifiers.MoveTo(ace.AdditionalArraySpecifiers); ct.ArraySpecifiers.MoveTo(ace.AdditionalArraySpecifiers);
} }
if (opCode == ILCode.InitArray) { if (byteCode.Code == ILCode.InitArray) {
ace.Initializer = new ArrayInitializerExpression(); ace.Initializer = new ArrayInitializerExpression();
ace.Initializer.Elements.AddRange(args); ace.Initializer.Elements.AddRange(args);
} else { } else {
@ -392,6 +302,24 @@ namespace ICSharpCode.Decompiler.Ast
return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2); return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2);
case ILCode.Clt_Un: case ILCode.Clt_Un:
return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2); return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2);
#endregion
#region Logical
case ILCode.LogicNot: return new Ast.UnaryOperatorExpression(UnaryOperatorType.Not, arg1);
case ILCode.LogicAnd: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.ConditionalAnd, arg2);
case ILCode.LogicOr: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.ConditionalOr, arg2);
case ILCode.TernaryOp: return new Ast.ConditionalExpression() { Condition = arg1, TrueExpression = arg2, FalseExpression = arg3 };
#endregion
#region Branch
case ILCode.Br: return new Ast.GotoStatement(((ILLabel)byteCode.Operand).Name);
case ILCode.Brtrue:
return new Ast.IfElseStatement() {
Condition = arg1,
TrueStatement = new BlockStatement() {
new Ast.GotoStatement(((ILLabel)byteCode.Operand).Name)
}
};
case ILCode.LoopBreak: return new Ast.BreakStatement();
case ILCode.LoopContinue: return new Ast.ContinueStatement();
#endregion #endregion
#region Conversions #region Conversions
case ILCode.Conv_I1: case ILCode.Conv_I1:
@ -629,7 +557,7 @@ namespace ICSharpCode.Decompiler.Ast
case ILCode.Throw: return new Ast.ThrowStatement { Expression = arg1 }; case ILCode.Throw: return new Ast.ThrowStatement { Expression = arg1 };
case ILCode.Unaligned: return InlineAssembly(byteCode, args); case ILCode.Unaligned: return InlineAssembly(byteCode, args);
case ILCode.Volatile: return InlineAssembly(byteCode, args); case ILCode.Volatile: return InlineAssembly(byteCode, args);
default: throw new Exception("Unknown OpCode: " + opCode); default: throw new Exception("Unknown OpCode: " + byteCode.Code);
} }
} }

188
ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs

@ -11,6 +11,7 @@ namespace ICSharpCode.Decompiler.ILAst
{ {
public enum ILAstOptimizationStep public enum ILAstOptimizationStep
{ {
ReduceBranchInstructionSet,
SplitToMovableBlocks, SplitToMovableBlocks,
PeepholeOptimizations, PeepholeOptimizations,
FindLoops, FindLoops,
@ -32,6 +33,11 @@ namespace ICSharpCode.Decompiler.ILAst
public void Optimize(DecompilerContext context, ILBlock method, ILAstOptimizationStep abortBeforeStep = ILAstOptimizationStep.None) public void Optimize(DecompilerContext context, ILBlock method, ILAstOptimizationStep abortBeforeStep = ILAstOptimizationStep.None)
{ {
if (abortBeforeStep == ILAstOptimizationStep.ReduceBranchInstructionSet) return;
foreach(ILBlock block in method.GetSelfAndChildrenRecursive<ILBlock>().ToList()) {
ReduceBranchInstructionSet(block);
}
if (abortBeforeStep == ILAstOptimizationStep.SplitToMovableBlocks) return; if (abortBeforeStep == ILAstOptimizationStep.SplitToMovableBlocks) return;
foreach(ILBlock block in method.GetSelfAndChildrenRecursive<ILBlock>().ToList()) { foreach(ILBlock block in method.GetSelfAndChildrenRecursive<ILBlock>().ToList()) {
SplitToBasicBlocks(block); SplitToBasicBlocks(block);
@ -85,6 +91,39 @@ namespace ICSharpCode.Decompiler.ILAst
GotoRemoval.RemoveRedundantCode(method); GotoRemoval.RemoveRedundantCode(method);
} }
/// <summary>
/// Reduces the branch codes to just br and brtrue.
/// Moves ILRanges to the branch argument
/// </summary>
void ReduceBranchInstructionSet(ILBlock block)
{
for (int i = 0; i < block.Body.Count; i++) {
ILExpression expr = block.Body[i] as ILExpression;
if (expr != null && expr.Prefixes == null) {
switch(expr.Code) {
case ILCode.Brtrue:
expr.Arguments.Single().ILRanges.AddRange(expr.ILRanges);
expr.ILRanges.Clear();
continue;
case ILCode.__Brfalse: block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.LogicNot, null, expr.Arguments.Single())); break;
case ILCode.__Beq: block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.Ceq, null, expr.Arguments)); break;
case ILCode.__Bne_Un: block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.LogicNot, null, new ILExpression(ILCode.Ceq, null, expr.Arguments))); break;
case ILCode.__Bgt: block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.Cgt, null, expr.Arguments)); break;
case ILCode.__Bgt_Un: block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.Cgt_Un, null, expr.Arguments)); break;
case ILCode.__Ble: block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.LogicNot, null, new ILExpression(ILCode.Cgt, null, expr.Arguments))); break;
case ILCode.__Ble_Un: block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.LogicNot, null, new ILExpression(ILCode.Cgt_Un, null, expr.Arguments))); break;
case ILCode.__Blt: block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.Clt, null, expr.Arguments)); break;
case ILCode.__Blt_Un: block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.Clt_Un, null, expr.Arguments)); break;
case ILCode.__Bge: block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.LogicNot, null, new ILExpression(ILCode.Clt, null, expr.Arguments))); break;
case ILCode.__Bge_Un: block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.LogicNot, null, new ILExpression(ILCode.Clt_Un, null, expr.Arguments))); break;
default:
continue;
}
((ILExpression)block.Body[i]).Arguments.Single().ILRanges.AddRange(expr.ILRanges);
}
}
}
/// <summary> /// <summary>
/// Group input into a set of blocks that can be later arbitraliby schufled. /// Group input into a set of blocks that can be later arbitraliby schufled.
/// The method adds necessary branches to make control flow between blocks /// The method adds necessary branches to make control flow between blocks
@ -196,31 +235,11 @@ namespace ICSharpCode.Decompiler.ILAst
} while(modified); } 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 &&
branchExpr.Prefixes == null)
{
trueLabel = (ILLabel)branchExpr.Operand;
falseLabel = (ILLabel)((ILExpression)bb.FallthoughGoto).Operand;
return true;
}
}
return false;
}
bool IsStloc(ILBasicBlock bb, ref ILVariable locVar, ref ILExpression val, ref ILLabel fallLabel) bool IsStloc(ILBasicBlock bb, ref ILVariable locVar, ref ILExpression val, ref ILLabel fallLabel)
{ {
if (bb.Body.Count == 1) { if (bb.Body.Count == 1) {
ILExpression expr = bb.Body[0] as ILExpression; ILExpression expr;
if (expr != null && if (bb.Body[0].Match(ILCode.Stloc, out expr)) {
expr.Code == ILCode.Stloc &&
expr.Prefixes == null)
{
locVar = (ILVariable)expr.Operand; locVar = (ILVariable)expr.Operand;
val = expr.Arguments[0]; val = expr.Arguments[0];
fallLabel = (ILLabel)bb.FallthoughGoto.Operand; fallLabel = (ILLabel)bb.FallthoughGoto.Operand;
@ -235,7 +254,7 @@ namespace ICSharpCode.Decompiler.ILAst
{ {
Debug.Assert(scope.Contains(head)); Debug.Assert(scope.Contains(head));
ILExpression branchExpr = null; ILExpression condExpr = null;
ILLabel trueLabel = null; ILLabel trueLabel = null;
ILLabel falseLabel = null; ILLabel falseLabel = null;
ILVariable trueLocVar = null; ILVariable trueLocVar = null;
@ -245,7 +264,7 @@ namespace ICSharpCode.Decompiler.ILAst
ILExpression falseExpr = null; ILExpression falseExpr = null;
ILLabel falseFall = null; ILLabel falseFall = null;
if(IsConditionalBranch(head, ref branchExpr, ref trueLabel, ref falseLabel) && if(head.MatchBrTure(out condExpr, out trueLabel, out falseLabel) &&
labelGlobalRefCount[trueLabel] == 1 && labelGlobalRefCount[trueLabel] == 1 &&
labelGlobalRefCount[falseLabel] == 1 && labelGlobalRefCount[falseLabel] == 1 &&
IsStloc(labelToBasicBlock[trueLabel], ref trueLocVar, ref trueExpr, ref trueFall) && IsStloc(labelToBasicBlock[trueLabel], ref trueLocVar, ref trueExpr, ref trueFall) &&
@ -254,24 +273,16 @@ namespace ICSharpCode.Decompiler.ILAst
trueFall == falseFall) trueFall == falseFall)
{ {
// Create the ternary expression // Create the ternary expression
head.Body = new List<ILNode>() { head.Body = new List<ILNode>() { new ILExpression(ILCode.Stloc, trueLocVar, new ILExpression(ILCode.TernaryOp, null, condExpr, trueExpr, falseExpr)) };
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); head.FallthoughGoto = new ILExpression(ILCode.Br, trueFall);
// Remove the old basic blocks // Remove the old basic blocks
scope.Remove(labelToBasicBlock[trueLabel]); scope.RemoveOrThrow(labelToBasicBlock[trueLabel]);
scope.Remove(labelToBasicBlock[falseLabel]); scope.RemoveOrThrow(labelToBasicBlock[falseLabel]);
labelToBasicBlock.Remove(trueLabel); labelToBasicBlock.RemoveOrThrow(trueLabel);
labelToBasicBlock.Remove(falseLabel); labelToBasicBlock.RemoveOrThrow(falseLabel);
labelGlobalRefCount.Remove(trueLabel); labelGlobalRefCount.RemoveOrThrow(trueLabel);
labelGlobalRefCount.Remove(falseLabel); labelGlobalRefCount.RemoveOrThrow(falseLabel);
return true; return true;
} }
@ -283,10 +294,10 @@ namespace ICSharpCode.Decompiler.ILAst
{ {
Debug.Assert(scope.Contains(head)); Debug.Assert(scope.Contains(head));
ILExpression branchExpr = null; ILExpression condExpr;
ILLabel trueLabel = null; ILLabel trueLabel;
ILLabel falseLabel = null; ILLabel falseLabel;
if(IsConditionalBranch(head, ref branchExpr, ref trueLabel, ref falseLabel)) { if(head.MatchBrTure(out condExpr, out trueLabel, 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
@ -296,32 +307,27 @@ namespace ICSharpCode.Decompiler.ILAst
bool negate = (pass == 1); bool negate = (pass == 1);
ILBasicBlock nextBasicBlock = labelToBasicBlock[nextLabel]; ILBasicBlock nextBasicBlock = labelToBasicBlock[nextLabel];
ILExpression nextBranchExpr = null; ILExpression nextCondExpr;
ILLabel nextTrueLablel = null; ILLabel nextTrueLablel;
ILLabel nextFalseLabel = null; ILLabel nextFalseLabel;
if (scope.Contains(nextBasicBlock) && if (scope.Contains(nextBasicBlock) &&
nextBasicBlock != head && nextBasicBlock != head &&
labelGlobalRefCount[nextBasicBlock.EntryLabel] == 1 && labelGlobalRefCount[nextBasicBlock.EntryLabel] == 1 &&
IsConditionalBranch(nextBasicBlock, ref nextBranchExpr, ref nextTrueLablel, ref nextFalseLabel) && nextBasicBlock.MatchBrTure(out nextCondExpr, out nextTrueLablel, out nextFalseLabel) &&
(otherLablel == nextFalseLabel || otherLablel == nextTrueLablel)) (otherLablel == nextFalseLabel || otherLablel == nextTrueLablel))
{ {
// We are using the branches as expressions now, so do not keep their labels alive
branchExpr.Operand = null;
nextBranchExpr.Operand = null;
// Create short cicuit branch // Create short cicuit branch
if (otherLablel == nextFalseLabel) { if (otherLablel == nextFalseLabel) {
head.Body[0] = new ILExpression(ILCode.BrLogicAnd, nextTrueLablel, negate ? new ILExpression(ILCode.LogicNot, null, branchExpr) : branchExpr, nextBranchExpr); head.Body[0] = new ILExpression(ILCode.Brtrue, nextTrueLablel, new ILExpression(ILCode.LogicAnd, null, negate ? new ILExpression(ILCode.LogicNot, null, condExpr) : condExpr, nextCondExpr));
} else { } else {
head.Body[0] = new ILExpression(ILCode.BrLogicOr, nextTrueLablel, negate ? branchExpr : new ILExpression(ILCode.LogicNot, null, branchExpr), nextBranchExpr); head.Body[0] = new ILExpression(ILCode.Brtrue, nextTrueLablel, new ILExpression(ILCode.LogicOr, null, negate ? condExpr : new ILExpression(ILCode.LogicNot, null, condExpr), nextCondExpr));
} }
head.FallthoughGoto = new ILExpression(ILCode.Br, nextFalseLabel); head.FallthoughGoto = new ILExpression(ILCode.Br, nextFalseLabel);
// Remove the inlined branch from scope // Remove the inlined branch from scope
labelGlobalRefCount.Remove(nextBasicBlock.EntryLabel); labelGlobalRefCount.RemoveOrThrow(nextBasicBlock.EntryLabel);
labelToBasicBlock.Remove(nextBasicBlock.EntryLabel); labelToBasicBlock.RemoveOrThrow(nextBasicBlock.EntryLabel);
if (!scope.Remove(nextBasicBlock)) scope.RemoveOrThrow(nextBasicBlock);
throw new Exception("Element not found");
return true; return true;
} }
@ -455,13 +461,12 @@ namespace ICSharpCode.Decompiler.ILAst
HashSet<ControlFlowNode> loopContents = FindLoopContent(scope, node); HashSet<ControlFlowNode> loopContents = FindLoopContent(scope, node);
ILBasicBlock basicBlock = (ILBasicBlock)node.UserData; ILBasicBlock basicBlock = (ILBasicBlock)node.UserData;
ILExpression branchExpr = null; ILExpression condExpr;
ILLabel trueLabel = null; ILLabel trueLabel;
ILLabel falseLabel = null; ILLabel falseLabel;
if(IsConditionalBranch(basicBlock, ref branchExpr, ref trueLabel, ref falseLabel)) { if(basicBlock.MatchBrTure(out condExpr, out trueLabel, out falseLabel)) {
loopContents.Remove(node); loopContents.RemoveOrThrow(node);
scope.Remove(node); scope.RemoveOrThrow(node);
branchExpr.Operand = null; // Do not keep label alive
// TODO: Does 'true' really point into the loop body? Swap if necessary // TODO: Does 'true' really point into the loop body? Swap if necessary
@ -479,7 +484,7 @@ namespace ICSharpCode.Decompiler.ILAst
EntryLabel = basicBlock.EntryLabel, EntryLabel = basicBlock.EntryLabel,
Body = new List<ILNode>() { Body = new List<ILNode>() {
new ILWhileLoop() { new ILWhileLoop() {
Condition = branchExpr, Condition = condExpr,
BodyBlock = new ILBlock() { BodyBlock = new ILBlock() {
EntryGoto = new ILExpression(ILCode.Br, trueLabel), EntryGoto = new ILExpression(ILCode.Br, trueLabel),
Body = FindLoops(loopContents, node, true) Body = FindLoops(loopContents, node, true)
@ -567,8 +572,7 @@ namespace ICSharpCode.Decompiler.ILAst
}); });
// Remove the item so that it is not picked up as content // Remove the item so that it is not picked up as content
if (!scope.Remove(node)) scope.RemoveOrThrow(node);
throw new Exception("Item is not in set");
// Pull in code of cases // Pull in code of cases
ControlFlowNode fallTarget = null; ControlFlowNode fallTarget = null;
@ -602,23 +606,20 @@ namespace ICSharpCode.Decompiler.ILAst
} }
// Two-way branch // Two-way branch
ILExpression branchExpr = null; ILExpression condExpr;
ILLabel trueLabel = null; ILLabel trueLabel;
ILLabel falseLabel = null; ILLabel falseLabel;
if(IsConditionalBranch(block, ref branchExpr, ref trueLabel, ref falseLabel)) { if(block.MatchBrTure(out condExpr, out trueLabel, out falseLabel)) {
// The branch label will not be used - kill it
branchExpr.Operand = null;
// 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;
trueLabel = falseLabel; trueLabel = falseLabel;
falseLabel = temp; falseLabel = temp;
branchExpr = new ILExpression(ILCode.LogicNot, null, branchExpr); condExpr = new ILExpression(ILCode.LogicNot, null, condExpr);
// Convert the basic block to ILCondition // Convert the basic block to ILCondition
ILCondition ilCond = new ILCondition() { ILCondition ilCond = new ILCondition() {
Condition = branchExpr, Condition = condExpr,
TrueBlock = new ILBlock() { EntryGoto = new ILExpression(ILCode.Br, trueLabel) }, TrueBlock = new ILBlock() { EntryGoto = new ILExpression(ILCode.Br, trueLabel) },
FalseBlock = new ILBlock() { EntryGoto = new ILExpression(ILCode.Br, falseLabel) } FalseBlock = new ILBlock() { EntryGoto = new ILExpression(ILCode.Br, falseLabel) }
}; };
@ -628,8 +629,7 @@ namespace ICSharpCode.Decompiler.ILAst
}); });
// Remove the item immediately so that it is not picked up as content // Remove the item immediately so that it is not picked up as content
if (!scope.Remove(node)) scope.RemoveOrThrow(node);
throw new Exception("Item is not in set");
ControlFlowNode trueTarget = null; ControlFlowNode trueTarget = null;
labelToCfNode.TryGetValue(trueLabel, out trueTarget); labelToCfNode.TryGetValue(trueLabel, out trueTarget);
@ -811,10 +811,24 @@ namespace ICSharpCode.Decompiler.ILAst
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;
return true; return true;
} else {
operand = default(T);
return false;
} }
operand = default(T);
return false;
}
public static bool MatchBrTure(this ILBasicBlock bb, out ILExpression condition, out ILLabel trueLabel, out ILLabel falseLabel)
{
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;
return true;
}
}
condition = null;
trueLabel = null;
falseLabel = null;
return false;
} }
public static bool CanFallthough(this ILNode node) public static bool CanFallthough(this ILNode node)
@ -833,5 +847,17 @@ namespace ICSharpCode.Decompiler.ILAst
} }
return true; return true;
} }
public static void RemoveOrThrow<T>(this ICollection<T> collection, T item)
{
if (!collection.Remove(item))
throw new Exception("The item was not found in the collection");
}
public static void RemoveOrThrow<K,V>(this Dictionary<K,V> collection, K key)
{
if (!collection.Remove(key))
throw new Exception("The key was not found in the dictionary");
}
} }
} }

8
ICSharpCode.Decompiler/ILAst/ILAstTypes.cs

@ -220,6 +220,14 @@ namespace ICSharpCode.Decompiler.ILAst
public static readonly object AnyOperand = new object(); public static readonly object AnyOperand = new object();
public ILExpression(ILCode code, object operand, List<ILExpression> args)
{
this.Code = code;
this.Operand = operand;
this.Arguments = new List<ILExpression>(args);
this.ILRanges = new List<ILRange>(1);
}
public ILExpression(ILCode code, object operand, params ILExpression[] args) public ILExpression(ILCode code, object operand, params ILExpression[] args)
{ {
this.Code = code; this.Code = code;

52
ICSharpCode.Decompiler/ILAst/ILCodes.cs

@ -32,7 +32,7 @@ namespace ICSharpCode.Decompiler.ILAst
public enum ILCode public enum ILCode
{ {
// For convenience, the start is exactly identical to Mono.Cecil.Cil.Code // For convenience, the start is exactly identical to Mono.Cecil.Cil.Code
// The macro instructions should never be used and are therefore prepended by __ // Instructions that should not be used are prepended by __
Nop, Nop,
Break, Break,
__Ldarg_0, __Ldarg_0,
@ -89,18 +89,18 @@ namespace ICSharpCode.Decompiler.ILAst
__Ble_Un_S, __Ble_Un_S,
__Blt_Un_S, __Blt_Un_S,
Br, Br,
Brfalse, __Brfalse,
Brtrue, Brtrue,
Beq, __Beq,
Bge, __Bge,
Bgt, __Bgt,
Ble, __Ble,
Blt, __Blt,
Bne_Un, __Bne_Un,
Bge_Un, __Bge_Un,
Bgt_Un, __Bgt_Un,
Ble_Un, __Ble_Un,
Blt_Un, __Blt_Un,
Switch, Switch,
Ldind_I1, Ldind_I1,
Ldind_U1, Ldind_U1,
@ -256,8 +256,8 @@ namespace ICSharpCode.Decompiler.ILAst
// Virtual codes - defined for convenience // Virtual codes - defined for convenience
Ldexception, // Operand holds the CatchType for catch handler, null for filter Ldexception, // Operand holds the CatchType for catch handler, null for filter
LogicNot, LogicNot,
BrLogicAnd, LogicAnd,
BrLogicOr, LogicOr,
InitArray, // Array Initializer InitArray, // Array Initializer
TernaryOp, // ?: TernaryOp, // ?:
LoopBreak, LoopBreak,
@ -271,7 +271,7 @@ namespace ICSharpCode.Decompiler.ILAst
{ {
public static string GetName(this ILCode code) public static string GetName(this ILCode code)
{ {
return code.ToString().ToLowerInvariant().Replace('_','.'); return code.ToString().ToLowerInvariant().TrimStart('_').Replace('_','.');
} }
public static bool CanFallThough(this ILCode code) public static bool CanFallThough(this ILCode code)
@ -396,18 +396,18 @@ namespace ICSharpCode.Decompiler.ILAst
case ILCode.__Ldc_I4_8: code = ILCode.Ldc_I4; operand = 8; break; case ILCode.__Ldc_I4_8: code = ILCode.Ldc_I4; operand = 8; break;
case ILCode.__Ldc_I4_S: code = ILCode.Ldc_I4; operand = (int) (sbyte) operand; break; case ILCode.__Ldc_I4_S: code = ILCode.Ldc_I4; operand = (int) (sbyte) operand; break;
case ILCode.__Br_S: code = ILCode.Br; break; case ILCode.__Br_S: code = ILCode.Br; break;
case ILCode.__Brfalse_S: code = ILCode.Brfalse; break; case ILCode.__Brfalse_S: code = ILCode.__Brfalse; break;
case ILCode.__Brtrue_S: code = ILCode.Brtrue; break; case ILCode.__Brtrue_S: code = ILCode.Brtrue; break;
case ILCode.__Beq_S: code = ILCode.Beq; break; case ILCode.__Beq_S: code = ILCode.__Beq; break;
case ILCode.__Bge_S: code = ILCode.Bge; break; case ILCode.__Bge_S: code = ILCode.__Bge; break;
case ILCode.__Bgt_S: code = ILCode.Bgt; break; case ILCode.__Bgt_S: code = ILCode.__Bgt; break;
case ILCode.__Ble_S: code = ILCode.Ble; break; case ILCode.__Ble_S: code = ILCode.__Ble; break;
case ILCode.__Blt_S: code = ILCode.Blt; break; case ILCode.__Blt_S: code = ILCode.__Blt; break;
case ILCode.__Bne_Un_S: code = ILCode.Bne_Un; break; case ILCode.__Bne_Un_S: code = ILCode.__Bne_Un; break;
case ILCode.__Bge_Un_S: code = ILCode.Bge_Un; break; case ILCode.__Bge_Un_S: code = ILCode.__Bge_Un; break;
case ILCode.__Bgt_Un_S: code = ILCode.Bgt_Un; break; case ILCode.__Bgt_Un_S: code = ILCode.__Bgt_Un; break;
case ILCode.__Ble_Un_S: code = ILCode.Ble_Un; break; case ILCode.__Ble_Un_S: code = ILCode.__Ble_Un; break;
case ILCode.__Blt_Un_S: code = ILCode.Blt_Un; break; case ILCode.__Blt_Un_S: code = ILCode.__Blt_Un; break;
case ILCode.__Leave_S: code = ILCode.Leave; break; case ILCode.__Leave_S: code = ILCode.Leave; break;
} }
} }

19
ICSharpCode.Decompiler/ILAst/PeepholeTransform.cs

@ -123,7 +123,7 @@ namespace ICSharpCode.Decompiler.ILAst
#region CachedDelegateInitialization #region CachedDelegateInitialization
void CachedDelegateInitialization(ILBlock block, ref int i) void CachedDelegateInitialization(ILBlock block, ref int i)
{ {
// if (logicnot(brtrue(ldsfld(field)))) { // if (logicnot(ldsfld(field))) {
// stsfld(field, newobj(Action::.ctor, ldnull(), ldftn(method))) // stsfld(field, newobj(Action::.ctor, ldnull(), ldftn(method)))
// } else { // } else {
// } // }
@ -134,7 +134,9 @@ namespace ICSharpCode.Decompiler.ILAst
return; return;
if (!(c.TrueBlock.Body.Count == 1 && c.FalseBlock.Body.Count == 0)) if (!(c.TrueBlock.Body.Count == 1 && c.FalseBlock.Body.Count == 0))
return; return;
ILExpression condition = UnpackBrFalse(c.Condition); if (!c.Condition.Match(ILCode.LogicNot))
return;
ILExpression condition = c.Condition.Arguments.Single() as ILExpression;
if (condition == null || condition.Code != ILCode.Ldsfld) if (condition == null || condition.Code != ILCode.Ldsfld)
return; return;
FieldDefinition field = condition.Operand as FieldDefinition; // field is defined in current assembly FieldDefinition field = condition.Operand as FieldDefinition; // field is defined in current assembly
@ -168,19 +170,6 @@ namespace ICSharpCode.Decompiler.ILAst
} }
} }
} }
/// <summary>
/// Returns 'result' in brfalse(result) or logicnot(brtrue(result)).
/// </summary>
static ILExpression UnpackBrFalse(ILExpression condition)
{
if (condition.Code == ILCode.Brfalse) {
return condition.Arguments.Single();
} else if (condition.Code == ILCode.LogicNot && condition.Arguments.Single().Code == ILCode.Brtrue) {
return condition.Arguments.Single().Arguments.Single();
}
return null;
}
#endregion #endregion
} }
} }

34
ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs

@ -39,6 +39,14 @@ namespace ICSharpCode.Decompiler.ILAst
void InferTypes(ILNode node) void InferTypes(ILNode node)
{ {
ILCondition cond = node as ILCondition;
if (cond != null) {
InferTypeForExpression(cond.Condition, typeSystem.Boolean, false);
}
ILWhileLoop loop = node as ILWhileLoop;
if (loop != null && loop.Condition != null) {
InferTypeForExpression(loop.Condition, typeSystem.Boolean, false);
}
ILExpression expr = node as ILExpression; ILExpression expr = node as ILExpression;
if (expr != null) { if (expr != null) {
ILVariable v = expr.Operand as ILVariable; ILVariable v = expr.Operand as ILVariable;
@ -111,13 +119,13 @@ namespace ICSharpCode.Decompiler.ILAst
InferTypeForExpression(expr.Arguments.Single(), typeSystem.Boolean); InferTypeForExpression(expr.Arguments.Single(), typeSystem.Boolean);
} }
return typeSystem.Boolean; return typeSystem.Boolean;
case ILCode.BrLogicAnd: case ILCode.LogicAnd:
case ILCode.BrLogicOr: case ILCode.LogicOr:
if (forceInferChildren) { if (forceInferChildren) {
InferTypeForExpression(expr.Arguments[0], typeSystem.Boolean); InferTypeForExpression(expr.Arguments[0], typeSystem.Boolean);
InferTypeForExpression(expr.Arguments[1], typeSystem.Boolean); InferTypeForExpression(expr.Arguments[1], typeSystem.Boolean);
} }
return null; return typeSystem.Boolean;
case ILCode.TernaryOp: case ILCode.TernaryOp:
if (forceInferChildren) { if (forceInferChildren) {
InferTypeForExpression(expr.Arguments[0], typeSystem.Boolean); InferTypeForExpression(expr.Arguments[0], typeSystem.Boolean);
@ -438,30 +446,10 @@ namespace ICSharpCode.Decompiler.ILAst
return typeSystem.Boolean; return typeSystem.Boolean;
#endregion #endregion
#region Branch instructions #region Branch instructions
case ILCode.Beq:
case ILCode.Bne_Un:
if (forceInferChildren)
InferArgumentsInBinaryOperator(expr, null);
return null;
case ILCode.Brtrue: case ILCode.Brtrue:
case ILCode.Brfalse:
if (forceInferChildren) if (forceInferChildren)
InferTypeForExpression(expr.Arguments.Single(), typeSystem.Boolean); InferTypeForExpression(expr.Arguments.Single(), typeSystem.Boolean);
return null; return null;
case ILCode.Blt:
case ILCode.Ble:
case ILCode.Bgt:
case ILCode.Bge:
if (forceInferChildren)
InferArgumentsInBinaryOperator(expr, true);
return null;
case ILCode.Blt_Un:
case ILCode.Ble_Un:
case ILCode.Bgt_Un:
case ILCode.Bge_Un:
if (forceInferChildren)
InferArgumentsInBinaryOperator(expr, false);
return null;
case ILCode.Br: case ILCode.Br:
case ILCode.Leave: case ILCode.Leave:
case ILCode.Endfinally: case ILCode.Endfinally:

Loading…
Cancel
Save