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 @@ -108,7 +108,7 @@ namespace ICSharpCode.Decompiler.Ast
} else if (node is ILWhileLoop) {
ILWhileLoop ilLoop = (ILWhileLoop)node;
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)
};
yield return whileStmt;
@ -116,7 +116,7 @@ namespace ICSharpCode.Decompiler.Ast @@ -116,7 +116,7 @@ namespace ICSharpCode.Decompiler.Ast
ILCondition conditionalNode = (ILCondition)node;
bool hasFalseBlock = conditionalNode.FalseBlock.EntryGoto != null || conditionalNode.FalseBlock.Body.Count > 0;
yield return new Ast.IfElseStatement {
Condition = MakeBranchCondition(conditionalNode.Condition),
Condition = (Expression)TransformExpression(conditionalNode.Condition),
TrueStatement = TransformBlock(conditionalNode.TrueBlock),
FalseStatement = hasFalseBlock ? TransformBlock(conditionalNode.FalseBlock) : null
};
@ -166,58 +166,6 @@ namespace ICSharpCode.Decompiler.Ast @@ -166,58 +166,6 @@ namespace ICSharpCode.Decompiler.Ast
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)
{
if (operand == null) {
@ -255,53 +203,15 @@ namespace ICSharpCode.Decompiler.Ast @@ -255,53 +203,15 @@ namespace ICSharpCode.Decompiler.Ast
AstNode TransformByteCode(ILExpression byteCode)
{
ILCode opCode = byteCode.Code;
object operand = byteCode.Operand;
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);
Ast.Expression arg1 = args.Count >= 1 ? args[0] : null;
Ast.Expression arg2 = args.Count >= 2 ? args[1] : null;
Ast.Expression arg3 = args.Count >= 3 ? args[2] : null;
switch(opCode) {
switch(byteCode.Code) {
#region Arithmetic
case ILCode.Add: 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 @@ -337,7 +247,7 @@ namespace ICSharpCode.Decompiler.Ast
// change "new (int[,])[10] to new int[10][,]"
ct.ArraySpecifiers.MoveTo(ace.AdditionalArraySpecifiers);
}
if (opCode == ILCode.InitArray) {
if (byteCode.Code == ILCode.InitArray) {
ace.Initializer = new ArrayInitializerExpression();
ace.Initializer.Elements.AddRange(args);
} else {
@ -392,6 +302,24 @@ namespace ICSharpCode.Decompiler.Ast @@ -392,6 +302,24 @@ namespace ICSharpCode.Decompiler.Ast
return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2);
case ILCode.Clt_Un:
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
#region Conversions
case ILCode.Conv_I1:
@ -629,7 +557,7 @@ namespace ICSharpCode.Decompiler.Ast @@ -629,7 +557,7 @@ namespace ICSharpCode.Decompiler.Ast
case ILCode.Throw: return new Ast.ThrowStatement { Expression = arg1 };
case ILCode.Unaligned: 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 @@ -11,6 +11,7 @@ namespace ICSharpCode.Decompiler.ILAst
{
public enum ILAstOptimizationStep
{
ReduceBranchInstructionSet,
SplitToMovableBlocks,
PeepholeOptimizations,
FindLoops,
@ -32,6 +33,11 @@ namespace ICSharpCode.Decompiler.ILAst @@ -32,6 +33,11 @@ namespace ICSharpCode.Decompiler.ILAst
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;
foreach(ILBlock block in method.GetSelfAndChildrenRecursive<ILBlock>().ToList()) {
SplitToBasicBlocks(block);
@ -85,6 +91,39 @@ namespace ICSharpCode.Decompiler.ILAst @@ -85,6 +91,39 @@ namespace ICSharpCode.Decompiler.ILAst
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>
/// Group input into a set of blocks that can be later arbitraliby schufled.
/// The method adds necessary branches to make control flow between blocks
@ -196,31 +235,11 @@ namespace ICSharpCode.Decompiler.ILAst @@ -196,31 +235,11 @@ namespace ICSharpCode.Decompiler.ILAst
} 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)
{
if (bb.Body.Count == 1) {
ILExpression expr = bb.Body[0] as ILExpression;
if (expr != null &&
expr.Code == ILCode.Stloc &&
expr.Prefixes == null)
{
ILExpression expr;
if (bb.Body[0].Match(ILCode.Stloc, out expr)) {
locVar = (ILVariable)expr.Operand;
val = expr.Arguments[0];
fallLabel = (ILLabel)bb.FallthoughGoto.Operand;
@ -235,7 +254,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -235,7 +254,7 @@ namespace ICSharpCode.Decompiler.ILAst
{
Debug.Assert(scope.Contains(head));
ILExpression branchExpr = null;
ILExpression condExpr = null;
ILLabel trueLabel = null;
ILLabel falseLabel = null;
ILVariable trueLocVar = null;
@ -245,7 +264,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -245,7 +264,7 @@ namespace ICSharpCode.Decompiler.ILAst
ILExpression falseExpr = 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[falseLabel] == 1 &&
IsStloc(labelToBasicBlock[trueLabel], ref trueLocVar, ref trueExpr, ref trueFall) &&
@ -254,24 +273,16 @@ namespace ICSharpCode.Decompiler.ILAst @@ -254,24 +273,16 @@ namespace ICSharpCode.Decompiler.ILAst
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.Body = new List<ILNode>() { new ILExpression(ILCode.Stloc, trueLocVar, new ILExpression(ILCode.TernaryOp, null, condExpr, 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);
scope.RemoveOrThrow(labelToBasicBlock[trueLabel]);
scope.RemoveOrThrow(labelToBasicBlock[falseLabel]);
labelToBasicBlock.RemoveOrThrow(trueLabel);
labelToBasicBlock.RemoveOrThrow(falseLabel);
labelGlobalRefCount.RemoveOrThrow(trueLabel);
labelGlobalRefCount.RemoveOrThrow(falseLabel);
return true;
}
@ -283,10 +294,10 @@ namespace ICSharpCode.Decompiler.ILAst @@ -283,10 +294,10 @@ namespace ICSharpCode.Decompiler.ILAst
{
Debug.Assert(scope.Contains(head));
ILExpression branchExpr = null;
ILLabel trueLabel = null;
ILLabel falseLabel = null;
if(IsConditionalBranch(head, ref branchExpr, ref trueLabel, ref falseLabel)) {
ILExpression condExpr;
ILLabel trueLabel;
ILLabel falseLabel;
if(head.MatchBrTure(out condExpr, out trueLabel, out falseLabel)) {
for (int pass = 0; pass < 2; pass++) {
// On the second pass, swap labels and negate expression of the first branch
@ -296,32 +307,27 @@ namespace ICSharpCode.Decompiler.ILAst @@ -296,32 +307,27 @@ namespace ICSharpCode.Decompiler.ILAst
bool negate = (pass == 1);
ILBasicBlock nextBasicBlock = labelToBasicBlock[nextLabel];
ILExpression nextBranchExpr = null;
ILLabel nextTrueLablel = null;
ILLabel nextFalseLabel = null;
ILExpression nextCondExpr;
ILLabel nextTrueLablel;
ILLabel nextFalseLabel;
if (scope.Contains(nextBasicBlock) &&
nextBasicBlock != head &&
labelGlobalRefCount[nextBasicBlock.EntryLabel] == 1 &&
IsConditionalBranch(nextBasicBlock, ref nextBranchExpr, ref nextTrueLablel, ref nextFalseLabel) &&
nextBasicBlock.MatchBrTure(out nextCondExpr, out nextTrueLablel, out nextFalseLabel) &&
(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
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 {
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);
// Remove the inlined branch from scope
labelGlobalRefCount.Remove(nextBasicBlock.EntryLabel);
labelToBasicBlock.Remove(nextBasicBlock.EntryLabel);
if (!scope.Remove(nextBasicBlock))
throw new Exception("Element not found");
labelGlobalRefCount.RemoveOrThrow(nextBasicBlock.EntryLabel);
labelToBasicBlock.RemoveOrThrow(nextBasicBlock.EntryLabel);
scope.RemoveOrThrow(nextBasicBlock);
return true;
}
@ -455,13 +461,12 @@ namespace ICSharpCode.Decompiler.ILAst @@ -455,13 +461,12 @@ namespace ICSharpCode.Decompiler.ILAst
HashSet<ControlFlowNode> loopContents = FindLoopContent(scope, node);
ILBasicBlock basicBlock = (ILBasicBlock)node.UserData;
ILExpression branchExpr = null;
ILLabel trueLabel = null;
ILLabel falseLabel = null;
if(IsConditionalBranch(basicBlock, ref branchExpr, ref trueLabel, ref falseLabel)) {
loopContents.Remove(node);
scope.Remove(node);
branchExpr.Operand = null; // Do not keep label alive
ILExpression condExpr;
ILLabel trueLabel;
ILLabel falseLabel;
if(basicBlock.MatchBrTure(out condExpr, out trueLabel, out falseLabel)) {
loopContents.RemoveOrThrow(node);
scope.RemoveOrThrow(node);
// TODO: Does 'true' really point into the loop body? Swap if necessary
@ -479,7 +484,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -479,7 +484,7 @@ namespace ICSharpCode.Decompiler.ILAst
EntryLabel = basicBlock.EntryLabel,
Body = new List<ILNode>() {
new ILWhileLoop() {
Condition = branchExpr,
Condition = condExpr,
BodyBlock = new ILBlock() {
EntryGoto = new ILExpression(ILCode.Br, trueLabel),
Body = FindLoops(loopContents, node, true)
@ -567,8 +572,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -567,8 +572,7 @@ namespace ICSharpCode.Decompiler.ILAst
});
// Remove the item so that it is not picked up as content
if (!scope.Remove(node))
throw new Exception("Item is not in set");
scope.RemoveOrThrow(node);
// Pull in code of cases
ControlFlowNode fallTarget = null;
@ -602,23 +606,20 @@ namespace ICSharpCode.Decompiler.ILAst @@ -602,23 +606,20 @@ namespace ICSharpCode.Decompiler.ILAst
}
// Two-way branch
ILExpression branchExpr = null;
ILLabel trueLabel = null;
ILLabel falseLabel = null;
if(IsConditionalBranch(block, ref branchExpr, ref trueLabel, ref falseLabel)) {
// The branch label will not be used - kill it
branchExpr.Operand = null;
ILExpression condExpr;
ILLabel trueLabel;
ILLabel falseLabel;
if(block.MatchBrTure(out condExpr, out trueLabel, out falseLabel)) {
// Swap bodies since that seems to be the usual C# order
ILLabel temp = trueLabel;
trueLabel = falseLabel;
falseLabel = temp;
branchExpr = new ILExpression(ILCode.LogicNot, null, branchExpr);
condExpr = new ILExpression(ILCode.LogicNot, null, condExpr);
// Convert the basic block to ILCondition
ILCondition ilCond = new ILCondition() {
Condition = branchExpr,
Condition = condExpr,
TrueBlock = new ILBlock() { EntryGoto = new ILExpression(ILCode.Br, trueLabel) },
FalseBlock = new ILBlock() { EntryGoto = new ILExpression(ILCode.Br, falseLabel) }
};
@ -628,8 +629,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -628,8 +629,7 @@ namespace ICSharpCode.Decompiler.ILAst
});
// Remove the item immediately so that it is not picked up as content
if (!scope.Remove(node))
throw new Exception("Item is not in set");
scope.RemoveOrThrow(node);
ControlFlowNode trueTarget = null;
labelToCfNode.TryGetValue(trueLabel, out trueTarget);
@ -811,10 +811,24 @@ namespace ICSharpCode.Decompiler.ILAst @@ -811,10 +811,24 @@ namespace ICSharpCode.Decompiler.ILAst
if (expr != null && expr.Prefixes == null && expr.Code == code) {
operand = (T)expr.Operand;
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)
@ -833,5 +847,17 @@ namespace ICSharpCode.Decompiler.ILAst @@ -833,5 +847,17 @@ namespace ICSharpCode.Decompiler.ILAst
}
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 @@ -220,6 +220,14 @@ namespace ICSharpCode.Decompiler.ILAst
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)
{
this.Code = code;

52
ICSharpCode.Decompiler/ILAst/ILCodes.cs

@ -32,7 +32,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -32,7 +32,7 @@ namespace ICSharpCode.Decompiler.ILAst
public enum ILCode
{
// 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,
Break,
__Ldarg_0,
@ -89,18 +89,18 @@ namespace ICSharpCode.Decompiler.ILAst @@ -89,18 +89,18 @@ namespace ICSharpCode.Decompiler.ILAst
__Ble_Un_S,
__Blt_Un_S,
Br,
Brfalse,
__Brfalse,
Brtrue,
Beq,
Bge,
Bgt,
Ble,
Blt,
Bne_Un,
Bge_Un,
Bgt_Un,
Ble_Un,
Blt_Un,
__Beq,
__Bge,
__Bgt,
__Ble,
__Blt,
__Bne_Un,
__Bge_Un,
__Bgt_Un,
__Ble_Un,
__Blt_Un,
Switch,
Ldind_I1,
Ldind_U1,
@ -256,8 +256,8 @@ namespace ICSharpCode.Decompiler.ILAst @@ -256,8 +256,8 @@ namespace ICSharpCode.Decompiler.ILAst
// Virtual codes - defined for convenience
Ldexception, // Operand holds the CatchType for catch handler, null for filter
LogicNot,
BrLogicAnd,
BrLogicOr,
LogicAnd,
LogicOr,
InitArray, // Array Initializer
TernaryOp, // ?:
LoopBreak,
@ -271,7 +271,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -271,7 +271,7 @@ namespace ICSharpCode.Decompiler.ILAst
{
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)
@ -396,18 +396,18 @@ namespace ICSharpCode.Decompiler.ILAst @@ -396,18 +396,18 @@ namespace ICSharpCode.Decompiler.ILAst
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.__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.__Beq_S: code = ILCode.Beq; break;
case ILCode.__Bge_S: code = ILCode.Bge; break;
case ILCode.__Bgt_S: code = ILCode.Bgt; break;
case ILCode.__Ble_S: code = ILCode.Ble; break;
case ILCode.__Blt_S: code = ILCode.Blt; break;
case ILCode.__Bne_Un_S: code = ILCode.Bne_Un; break;
case ILCode.__Bge_Un_S: code = ILCode.Bge_Un; break;
case ILCode.__Bgt_Un_S: code = ILCode.Bgt_Un; break;
case ILCode.__Ble_Un_S: code = ILCode.Ble_Un; break;
case ILCode.__Blt_Un_S: code = ILCode.Blt_Un; break;
case ILCode.__Beq_S: code = ILCode.__Beq; break;
case ILCode.__Bge_S: code = ILCode.__Bge; break;
case ILCode.__Bgt_S: code = ILCode.__Bgt; break;
case ILCode.__Ble_S: code = ILCode.__Ble; break;
case ILCode.__Blt_S: code = ILCode.__Blt; break;
case ILCode.__Bne_Un_S: code = ILCode.__Bne_Un; break;
case ILCode.__Bge_Un_S: code = ILCode.__Bge_Un; break;
case ILCode.__Bgt_Un_S: code = ILCode.__Bgt_Un; break;
case ILCode.__Ble_Un_S: code = ILCode.__Ble_Un; break;
case ILCode.__Blt_Un_S: code = ILCode.__Blt_Un; break;
case ILCode.__Leave_S: code = ILCode.Leave; break;
}
}

19
ICSharpCode.Decompiler/ILAst/PeepholeTransform.cs

@ -123,7 +123,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -123,7 +123,7 @@ namespace ICSharpCode.Decompiler.ILAst
#region CachedDelegateInitialization
void CachedDelegateInitialization(ILBlock block, ref int i)
{
// if (logicnot(brtrue(ldsfld(field)))) {
// if (logicnot(ldsfld(field))) {
// stsfld(field, newobj(Action::.ctor, ldnull(), ldftn(method)))
// } else {
// }
@ -134,7 +134,9 @@ namespace ICSharpCode.Decompiler.ILAst @@ -134,7 +134,9 @@ namespace ICSharpCode.Decompiler.ILAst
return;
if (!(c.TrueBlock.Body.Count == 1 && c.FalseBlock.Body.Count == 0))
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)
return;
FieldDefinition field = condition.Operand as FieldDefinition; // field is defined in current assembly
@ -168,19 +170,6 @@ namespace ICSharpCode.Decompiler.ILAst @@ -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
}
}

34
ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs

@ -39,6 +39,14 @@ namespace ICSharpCode.Decompiler.ILAst @@ -39,6 +39,14 @@ namespace ICSharpCode.Decompiler.ILAst
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;
if (expr != null) {
ILVariable v = expr.Operand as ILVariable;
@ -111,13 +119,13 @@ namespace ICSharpCode.Decompiler.ILAst @@ -111,13 +119,13 @@ namespace ICSharpCode.Decompiler.ILAst
InferTypeForExpression(expr.Arguments.Single(), typeSystem.Boolean);
}
return typeSystem.Boolean;
case ILCode.BrLogicAnd:
case ILCode.BrLogicOr:
case ILCode.LogicAnd:
case ILCode.LogicOr:
if (forceInferChildren) {
InferTypeForExpression(expr.Arguments[0], typeSystem.Boolean);
InferTypeForExpression(expr.Arguments[1], typeSystem.Boolean);
}
return null;
return typeSystem.Boolean;
case ILCode.TernaryOp:
if (forceInferChildren) {
InferTypeForExpression(expr.Arguments[0], typeSystem.Boolean);
@ -438,30 +446,10 @@ namespace ICSharpCode.Decompiler.ILAst @@ -438,30 +446,10 @@ namespace ICSharpCode.Decompiler.ILAst
return typeSystem.Boolean;
#endregion
#region Branch instructions
case ILCode.Beq:
case ILCode.Bne_Un:
if (forceInferChildren)
InferArgumentsInBinaryOperator(expr, null);
return null;
case ILCode.Brtrue:
case ILCode.Brfalse:
if (forceInferChildren)
InferTypeForExpression(expr.Arguments.Single(), typeSystem.Boolean);
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.Leave:
case ILCode.Endfinally:

Loading…
Cancel
Save