public bool JoinBasicBlocks(List <ILNode> body, ILBasicBlock head, int pos) { ILLabel nextLabel; ILBasicBlock nextBB; if (!head.Body.ElementAtOrDefault(head.Body.Count - 2).IsConditionalControlFlow() && head.Body.Last().Match(ILCode.Br, out nextLabel) && labelGlobalRefCount[nextLabel] == 1 && labelToBasicBlock.TryGetValue(nextLabel, out nextBB) && body.Contains(nextBB) && nextBB.Body.First() == nextLabel && !nextBB.Body.OfType <ILTryCatchBlock>().Any() ) { var tail = head.Body.RemoveTail(ILCode.Br); tail[0].AddSelfAndChildrenRecursiveILRanges(nextBB.ILRanges); nextBB.Body[0].AddSelfAndChildrenRecursiveILRanges(nextBB.ILRanges); nextBB.Body.RemoveAt(0); // Remove label if (head.Body.Count > 0) { head.Body[head.Body.Count - 1].EndILRanges.AddRange(nextBB.ILRanges); } else { head.ILRanges.AddRange(nextBB.ILRanges); } head.EndILRanges.AddRange(nextBB.EndILRanges); head.Body.AddRange(nextBB.Body); body.RemoveOrThrow(nextBB); return(true); } return(false); }
public bool SimplifyShortCircuit(List <ILNode> body, ILBasicBlock head, int pos) { Debug.Assert(body.Contains(head)); ILExpression condExpr; ILLabel trueLabel; ILLabel falseLabel; if (head.MatchLastAndBr(ILCode.Brtrue, out trueLabel, out condExpr, out falseLabel)) { for (int pass = 0; pass < 2; pass++) { // On the second pass, swap labels and negate expression of the first branch // It is slightly ugly, but much better then copy-pasting this whole block ILLabel nextLabel = (pass == 0) ? trueLabel : falseLabel; ILLabel otherLablel = (pass == 0) ? falseLabel : trueLabel; bool negate = (pass == 1); ILBasicBlock nextBasicBlock = labelToBasicBlock[nextLabel]; ILExpression nextCondExpr; ILLabel nextTrueLablel; ILLabel nextFalseLabel; if (body.Contains(nextBasicBlock) && nextBasicBlock != head && labelGlobalRefCount[(ILLabel)nextBasicBlock.Body.First()] == 1 && nextBasicBlock.MatchSingleAndBr(ILCode.Brtrue, out nextTrueLablel, out nextCondExpr, out nextFalseLabel) && (otherLablel == nextFalseLabel || otherLablel == nextTrueLablel)) { // Create short cicuit branch ILExpression logicExpr; if (otherLablel == nextFalseLabel) { logicExpr = MakeLeftAssociativeShortCircuit(ILCode.LogicAnd, negate ? new ILExpression(ILCode.LogicNot, null, condExpr) : condExpr, nextCondExpr); } else { logicExpr = MakeLeftAssociativeShortCircuit(ILCode.LogicOr, negate ? condExpr : new ILExpression(ILCode.LogicNot, null, condExpr), nextCondExpr); } var tail = head.Body.RemoveTail(ILCode.Brtrue, ILCode.Br); nextCondExpr.ILRanges.AddRange(tail[0].ILRanges); // brtrue nextCondExpr.ILRanges.AddRange(nextBasicBlock.ILRanges); nextBasicBlock.Body[0].AddSelfAndChildrenRecursiveILRanges(nextCondExpr.ILRanges); // label nextCondExpr.ILRanges.AddRange(nextBasicBlock.Body[1].ILRanges); // brtrue head.Body.Add(new ILExpression(ILCode.Brtrue, nextTrueLablel, logicExpr)); ILExpression brFalseLbl; head.Body.Add(brFalseLbl = new ILExpression(ILCode.Br, nextFalseLabel)); nextBasicBlock.Body[2].AddSelfAndChildrenRecursiveILRanges(brFalseLbl.ILRanges); // br brFalseLbl.ILRanges.AddRange(nextBasicBlock.EndILRanges); tail[1].AddSelfAndChildrenRecursiveILRanges(brFalseLbl.ILRanges); // br // Remove the inlined branch from scope body.RemoveOrThrow(nextBasicBlock); return(true); } } } return(false); }
public bool SimplifyNullCoalescing(List <ILNode> body, ILBasicBlock head, int pos) { // ... // v = ldloc(leftVar) // brtrue(endBBLabel, ldloc(leftVar)) // br(rightBBLabel) // // rightBBLabel: // v = rightExpr // br(endBBLabel) // ... // => // ... // v = NullCoalescing(ldloc(leftVar), rightExpr) // br(endBBLabel) ILVariable v, v2; ILExpression leftExpr, leftExpr2; ILVariable leftVar; ILLabel endBBLabel, endBBLabel2; ILLabel rightBBLabel; ILBasicBlock rightBB; ILExpression rightExpr; if (head.Body.Count >= 3 && 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) && labelToBasicBlock.TryGetValue(rightBBLabel, out rightBB) && rightBB.MatchSingleAndBr(ILCode.Stloc, out v2, out rightExpr, out endBBLabel2) && v == v2 && endBBLabel == endBBLabel2 && labelGlobalRefCount.GetOrDefault(rightBBLabel) == 1 && body.Contains(rightBB) ) { var tail = head.Body.RemoveTail(ILCode.Stloc, ILCode.Brtrue, ILCode.Br); ILExpression nullCoal, stloc; head.Body.Add(stloc = new ILExpression(ILCode.Stloc, v, nullCoal = new ILExpression(ILCode.NullCoalescing, null, leftExpr, rightExpr))); head.Body.Add(new ILExpression(ILCode.Br, endBBLabel)); tail[0].AddSelfAndChildrenRecursiveILRanges(stloc.ILRanges); tail[1].AddSelfAndChildrenRecursiveILRanges(nullCoal.ILRanges); tail[2].AddSelfAndChildrenRecursiveILRanges(rightExpr.ILRanges); // br (to rightBB) rightExpr.ILRanges.AddRange(rightBB.AllILRanges); rightBB.Body[0].AddSelfAndChildrenRecursiveILRanges(rightExpr.ILRanges); // label rightExpr.ILRanges.AddRange(rightBB.Body[1].ILRanges); // stloc: no recursive add rightBB.Body[2].AddSelfAndChildrenRecursiveILRanges(rightExpr.ILRanges); // br body.RemoveOrThrow(labelToBasicBlock[rightBBLabel]); return(true); } return(false); }
public bool SimplifyNullCoalescing(List <ILNode> body, ILBasicBlock head, int pos) { // ... // v = ldloc(leftVar) // brtrue(endBBLabel, ldloc(leftVar)) // br(rightBBLabel) // // rightBBLabel: // v = rightExpr // br(endBBLabel) // ... // => // ... // v = NullCoalescing(ldloc(leftVar), rightExpr) // br(endBBLabel) ILVariable v, v2; ILExpression leftExpr, leftExpr2; ILVariable leftVar; ILLabel endBBLabel, endBBLabel2; ILLabel rightBBLabel; ILBasicBlock rightBB; ILExpression rightExpr; if (head.Body.Count >= 3 && 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) && labelToBasicBlock.TryGetValue(rightBBLabel, out rightBB) && rightBB.MatchSingleAndBr(ILCode.Stloc, out v2, out rightExpr, out endBBLabel2) && v == v2 && endBBLabel == endBBLabel2 && labelGlobalRefCount.GetOrDefault(rightBBLabel) == 1 && body.Contains(rightBB) ) { head.Body.RemoveTail(ILCode.Stloc, ILCode.Brtrue, ILCode.Br); head.Body.Add(new ILExpression(ILCode.Stloc, v, new ILExpression(ILCode.NullCoalescing, null, leftExpr, rightExpr))); head.Body.Add(new ILExpression(ILCode.Br, endBBLabel)); body.RemoveOrThrow(labelToBasicBlock[rightBBLabel]); return(true); } return(false); }
public bool SimplifyNullCoalescing(List<AstNode> body, AstBasicBlock head, int pos) { // ... // v = ldloc(leftVar) // brtrue(endBBLabel, ldloc(leftVar)) // br(rightBBLabel) // // rightBBLabel: // v = rightExpr // br(endBBLabel) // ... // => // ... // v = NullCoalescing(ldloc(leftVar), rightExpr) // br(endBBLabel) AstVariable v, v2; AstExpression leftExpr, leftExpr2; AstVariable leftVar; AstLabel endBBLabel, endBBLabel2; AstLabel rightBBLabel; AstBasicBlock rightBB; AstExpression rightExpr; if (head.Body.Count >= 3 && head.Body[head.Body.Count - 3].Match(AstCode.Stloc, out v, out leftExpr) && leftExpr.Match(AstCode.Ldloc, out leftVar) && head.MatchLastAndBr(AstCode.Brtrue, out endBBLabel, out leftExpr2, out rightBBLabel) && leftExpr2.MatchLdloc(leftVar) && labelToBasicBlock.TryGetValue(rightBBLabel, out rightBB) && rightBB.MatchSingleAndBr(AstCode.Stloc, out v2, out rightExpr, out endBBLabel2) && v == v2 && endBBLabel == endBBLabel2 && labelGlobalRefCount.GetOrDefault(rightBBLabel) == 1 && body.Contains(rightBB) ) { head.Body.RemoveTail(AstCode.Stloc, AstCode.Brtrue, AstCode.Br); head.Body.Add(new AstExpression(leftExpr.SourceLocation, AstCode.Stloc, v, new AstExpression(leftExpr.SourceLocation, AstCode.NullCoalescing, null, leftExpr, rightExpr))); head.Body.Add(new AstExpression(leftExpr.SourceLocation, AstCode.Br, endBBLabel)); body.RemoveOrThrow(labelToBasicBlock[rightBBLabel]); return true; } return false; }
public bool JoinBasicBlocks(List<ILNode> body, ILBasicBlock head, int pos) { ILLabel nextLabel; ILBasicBlock nextBB; if (!head.Body.ElementAtOrDefault(head.Body.Count - 2).IsConditionalControlFlow() && head.Body.Last().Match(ILCode.Br, out nextLabel) && labelGlobalRefCount[nextLabel] == 1 && labelToBasicBlock.TryGetValue(nextLabel, out nextBB) && body.Contains(nextBB) && nextBB.Body.First() == nextLabel && !nextBB.Body.OfType<ILTryCatchBlock>().Any() ) { head.Body.RemoveTail(ILCode.Br); nextBB.Body.RemoveAt(0); // Remove label head.Body.AddRange(nextBB.Body); body.RemoveOrThrow(nextBB); return true; } return false; }
public bool JoinBasicBlocks(List <AstNode> body, AstBasicBlock head, int pos) { AstLabel nextLabel; AstBasicBlock nextBB; if (!head.Body.ElementAtOrDefault(head.Body.Count - 2).IsConditionalControlFlow() && head.Body.Last().Match(AstCode.Br, out nextLabel) && labelGlobalRefCount[nextLabel] == 1 && labelToBasicBlock.TryGetValue(nextLabel, out nextBB) && body.Contains(nextBB) && nextBB.Body.First() == nextLabel && !nextBB.Body.OfType <AstTryCatchBlock>().Any() ) { head.Body.RemoveTail(AstCode.Br); nextBB.Body.RemoveAt(0); // Remove label head.Body.AddRange(nextBB.Body); body.RemoveOrThrow(nextBB); return(true); } return(false); }
public bool SimplifyTernaryOperator(List<ILNode> body, ILBasicBlock head, int pos) { Debug.Assert(body.Contains(head)); ILExpression condExpr; ILLabel trueLabel; ILLabel falseLabel; ILVariable trueLocVar = null; ILExpression trueExpr; ILLabel trueFall; ILVariable falseLocVar = null; ILExpression falseExpr; ILLabel falseFall; object unused; if (head.MatchLastAndBr(ILCode.Brtrue, out trueLabel, out condExpr, out falseLabel) && labelGlobalRefCount[trueLabel] == 1 && labelGlobalRefCount[falseLabel] == 1 && ((labelToBasicBlock[trueLabel].MatchSingleAndBr(ILCode.Stloc, out trueLocVar, out trueExpr, out trueFall) && labelToBasicBlock[falseLabel].MatchSingleAndBr(ILCode.Stloc, out falseLocVar, out falseExpr, out falseFall) && trueLocVar == falseLocVar && trueFall == falseFall) || (labelToBasicBlock[trueLabel].MatchSingle(ILCode.Ret, out unused, out trueExpr) && labelToBasicBlock[falseLabel].MatchSingle(ILCode.Ret, out unused, out falseExpr))) && body.Contains(labelToBasicBlock[trueLabel]) && body.Contains(labelToBasicBlock[falseLabel]) ) { bool isStloc = trueLocVar != null; ILCode opCode = isStloc ? ILCode.Stloc : ILCode.Ret; TypeSig retType = isStloc ? trueLocVar.Type : this.context.CurrentMethod.ReturnType; bool retTypeIsBoolean = retType.GetElementType() == ElementType.Boolean; int leftBoolVal; int rightBoolVal; ILExpression newExpr; // a ? true:false is equivalent to a // a ? false:true is equivalent to !a // a ? true : b is equivalent to a || b // a ? b : true is equivalent to !a || b // a ? b : false is equivalent to a && b // a ? false : b is equivalent to !a && b if (retTypeIsBoolean && trueExpr.Match(ILCode.Ldc_I4, out leftBoolVal) && falseExpr.Match(ILCode.Ldc_I4, out rightBoolVal) && ((leftBoolVal != 0 && rightBoolVal == 0) || (leftBoolVal == 0 && rightBoolVal != 0)) ) { // It can be expressed as trivilal expression if (leftBoolVal != 0) { newExpr = condExpr; } else { newExpr = new ILExpression(ILCode.LogicNot, null, condExpr) { InferredType = corLib.Boolean }; } } else if ((retTypeIsBoolean || falseExpr.InferredType.GetElementType() == ElementType.Boolean) && trueExpr.Match(ILCode.Ldc_I4, out leftBoolVal) && (leftBoolVal == 0 || leftBoolVal == 1)) { // It can be expressed as logical expression if (leftBoolVal != 0) { newExpr = MakeLeftAssociativeShortCircuit(ILCode.LogicOr, condExpr, falseExpr); } else { newExpr = MakeLeftAssociativeShortCircuit(ILCode.LogicAnd, new ILExpression(ILCode.LogicNot, null, condExpr), falseExpr); } } else if ((retTypeIsBoolean || trueExpr.InferredType.GetElementType() == ElementType.Boolean) && falseExpr.Match(ILCode.Ldc_I4, out rightBoolVal) && (rightBoolVal == 0 || rightBoolVal == 1)) { // It can be expressed as logical expression if (rightBoolVal != 0) { newExpr = MakeLeftAssociativeShortCircuit(ILCode.LogicOr, new ILExpression(ILCode.LogicNot, null, condExpr), trueExpr); } else { newExpr = MakeLeftAssociativeShortCircuit(ILCode.LogicAnd, condExpr, trueExpr); } } else { // Ternary operator tends to create long complicated return statements if (opCode == ILCode.Ret) return false; // Only simplify generated variables if (opCode == ILCode.Stloc && !trueLocVar.GeneratedByDecompiler) return false; // Create ternary expression newExpr = new ILExpression(ILCode.TernaryOp, null, condExpr, trueExpr, falseExpr); } var tail = head.Body.RemoveTail(ILCode.Brtrue, ILCode.Br); var listNodes = new List<ILNode>(); var newExprNodes = newExpr.GetSelfAndChildrenRecursive<ILNode>(listNodes).ToArray(); foreach (var node in labelToBasicBlock[trueLabel].GetSelfAndChildrenRecursive<ILNode>(listNodes).Except(newExprNodes)) newExpr.ILRanges.AddRange(node.AllILRanges); foreach (var node in labelToBasicBlock[falseLabel].GetSelfAndChildrenRecursive<ILNode>(listNodes).Except(newExprNodes)) newExpr.ILRanges.AddRange(node.AllILRanges); newExpr.ILRanges.AddRange(tail[0].ILRanges); tail[1].AddSelfAndChildrenRecursiveILRanges(newExpr.ILRanges); head.Body.Add(new ILExpression(opCode, trueLocVar, newExpr)); if (isStloc) head.Body.Add(new ILExpression(ILCode.Br, trueFall)); // Remove the old basic blocks body.RemoveOrThrow(labelToBasicBlock[trueLabel]); body.RemoveOrThrow(labelToBasicBlock[falseLabel]); return true; } return false; }
public bool SimplifyShortCircuit(List<ILNode> body, ILBasicBlock head, int pos) { Debug.Assert(body.Contains(head)); ILExpression condExpr; ILLabel trueLabel; ILLabel falseLabel; if(head.MatchLastAndBr(ILCode.Brtrue, out trueLabel, out condExpr, out falseLabel)) { for (int pass = 0; pass < 2; pass++) { // On the second pass, swap labels and negate expression of the first branch // It is slightly ugly, but much better then copy-pasting this whole block ILLabel nextLabel = (pass == 0) ? trueLabel : falseLabel; ILLabel otherLablel = (pass == 0) ? falseLabel : trueLabel; bool negate = (pass == 1); ILBasicBlock nextBasicBlock = labelToBasicBlock[nextLabel]; ILExpression nextCondExpr; ILLabel nextTrueLablel; ILLabel nextFalseLabel; if (body.Contains(nextBasicBlock) && nextBasicBlock != head && labelGlobalRefCount[(ILLabel)nextBasicBlock.Body.First()] == 1 && nextBasicBlock.MatchSingleAndBr(ILCode.Brtrue, out nextTrueLablel, out nextCondExpr, out nextFalseLabel) && (otherLablel == nextFalseLabel || otherLablel == nextTrueLablel)) { // Create short cicuit branch ILExpression logicExpr; if (otherLablel == nextFalseLabel) { logicExpr = MakeLeftAssociativeShortCircuit(ILCode.LogicAnd, negate ? new ILExpression(ILCode.LogicNot, null, condExpr) : condExpr, nextCondExpr); } else { logicExpr = MakeLeftAssociativeShortCircuit(ILCode.LogicOr, negate ? condExpr : new ILExpression(ILCode.LogicNot, null, condExpr), nextCondExpr); } var tail = head.Body.RemoveTail(ILCode.Brtrue, ILCode.Br); nextCondExpr.ILRanges.AddRange(tail[0].ILRanges); // brtrue nextCondExpr.ILRanges.AddRange(nextBasicBlock.ILRanges); nextBasicBlock.Body[0].AddSelfAndChildrenRecursiveILRanges(nextCondExpr.ILRanges); // label nextCondExpr.ILRanges.AddRange(nextBasicBlock.Body[1].ILRanges); // brtrue head.Body.Add(new ILExpression(ILCode.Brtrue, nextTrueLablel, logicExpr)); ILExpression brFalseLbl; head.Body.Add(brFalseLbl = new ILExpression(ILCode.Br, nextFalseLabel)); nextBasicBlock.Body[2].AddSelfAndChildrenRecursiveILRanges(brFalseLbl.ILRanges); // br brFalseLbl.ILRanges.AddRange(nextBasicBlock.EndILRanges); tail[1].AddSelfAndChildrenRecursiveILRanges(brFalseLbl.ILRanges); // br // Remove the inlined branch from scope body.RemoveOrThrow(nextBasicBlock); return true; } } } return false; }
public bool SimplifyNullCoalescing(List<ILNode> body, ILBasicBlock head, int pos) { // ... // v = ldloc(leftVar) // brtrue(endBBLabel, ldloc(leftVar)) // br(rightBBLabel) // // rightBBLabel: // v = rightExpr // br(endBBLabel) // ... // => // ... // v = NullCoalescing(ldloc(leftVar), rightExpr) // br(endBBLabel) ILVariable v, v2; ILExpression leftExpr, leftExpr2; ILVariable leftVar; ILLabel endBBLabel, endBBLabel2; ILLabel rightBBLabel; ILBasicBlock rightBB; ILExpression rightExpr; if (head.Body.Count >= 3 && 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) && labelToBasicBlock.TryGetValue(rightBBLabel, out rightBB) && rightBB.MatchSingleAndBr(ILCode.Stloc, out v2, out rightExpr, out endBBLabel2) && v == v2 && endBBLabel == endBBLabel2 && labelGlobalRefCount.GetOrDefault(rightBBLabel) == 1 && body.Contains(rightBB) ) { var tail = head.Body.RemoveTail(ILCode.Stloc, ILCode.Brtrue, ILCode.Br); ILExpression nullCoal, stloc; head.Body.Add(stloc = new ILExpression(ILCode.Stloc, v, nullCoal = new ILExpression(ILCode.NullCoalescing, null, leftExpr, rightExpr))); head.Body.Add(new ILExpression(ILCode.Br, endBBLabel)); tail[0].AddSelfAndChildrenRecursiveILRanges(stloc.ILRanges); tail[1].AddSelfAndChildrenRecursiveILRanges(nullCoal.ILRanges); tail[2].AddSelfAndChildrenRecursiveILRanges(rightExpr.ILRanges); // br (to rightBB) rightExpr.ILRanges.AddRange(rightBB.AllILRanges); rightBB.Body[0].AddSelfAndChildrenRecursiveILRanges(rightExpr.ILRanges); // label rightExpr.ILRanges.AddRange(rightBB.Body[1].ILRanges); // stloc: no recursive add rightBB.Body[2].AddSelfAndChildrenRecursiveILRanges(rightExpr.ILRanges); // br body.RemoveOrThrow(labelToBasicBlock[rightBBLabel]); return true; } return false; }
public bool SimplifyTernaryOperator(List <ILNode> body, ILBasicBlock head, int pos) { Debug.Assert(body.Contains(head)); ILExpression condExpr; ILLabel trueLabel; ILLabel falseLabel; ILVariable trueLocVar = null; ILExpression trueExpr; ILLabel trueFall; ILVariable falseLocVar = null; ILExpression falseExpr; ILLabel falseFall; object unused; if (head.MatchLastAndBr(ILCode.Brtrue, out trueLabel, out condExpr, out falseLabel) && labelGlobalRefCount[trueLabel] == 1 && labelGlobalRefCount[falseLabel] == 1 && ((labelToBasicBlock[trueLabel].MatchSingleAndBr(ILCode.Stloc, out trueLocVar, out trueExpr, out trueFall) && labelToBasicBlock[falseLabel].MatchSingleAndBr(ILCode.Stloc, out falseLocVar, out falseExpr, out falseFall) && trueLocVar == falseLocVar && trueFall == falseFall) || (labelToBasicBlock[trueLabel].MatchSingle(ILCode.Ret, out unused, out trueExpr) && labelToBasicBlock[falseLabel].MatchSingle(ILCode.Ret, out unused, out falseExpr))) && body.Contains(labelToBasicBlock[trueLabel]) && body.Contains(labelToBasicBlock[falseLabel]) ) { bool isStloc = trueLocVar != null; ILCode opCode = isStloc ? ILCode.Stloc : ILCode.Ret; TypeReference retType = isStloc ? trueLocVar.Type : this.context.CurrentMethod.ReturnType; bool retTypeIsBoolean = TypeAnalysis.IsBoolean(retType); int leftBoolVal; int rightBoolVal; ILExpression newExpr; // a ? true:false is equivalent to a // a ? false:true is equivalent to !a // a ? true : b is equivalent to a || b // a ? b : true is equivalent to !a || b // a ? b : false is equivalent to a && b // a ? false : b is equivalent to !a && b if (retTypeIsBoolean && trueExpr.Match(ILCode.Ldc_I4, out leftBoolVal) && falseExpr.Match(ILCode.Ldc_I4, out rightBoolVal) && ((leftBoolVal != 0 && rightBoolVal == 0) || (leftBoolVal == 0 && rightBoolVal != 0)) ) { // It can be expressed as trivilal expression if (leftBoolVal != 0) { newExpr = condExpr; } else { newExpr = new ILExpression(ILCode.LogicNot, null, condExpr); } } else if (retTypeIsBoolean && trueExpr.Match(ILCode.Ldc_I4, out leftBoolVal)) { // It can be expressed as logical expression if (leftBoolVal != 0) { newExpr = MakeLeftAssociativeShortCircuit(ILCode.LogicOr, condExpr, falseExpr); } else { newExpr = MakeLeftAssociativeShortCircuit(ILCode.LogicAnd, new ILExpression(ILCode.LogicNot, null, condExpr), falseExpr); } } else if (retTypeIsBoolean && falseExpr.Match(ILCode.Ldc_I4, out rightBoolVal)) { // It can be expressed as logical expression if (rightBoolVal != 0) { newExpr = MakeLeftAssociativeShortCircuit(ILCode.LogicOr, new ILExpression(ILCode.LogicNot, null, condExpr), trueExpr); } else { newExpr = MakeLeftAssociativeShortCircuit(ILCode.LogicAnd, condExpr, trueExpr); } } else { // Ternary operator tends to create long complicated return statements if (opCode == ILCode.Ret) { return(false); } // Only simplify generated variables if (opCode == ILCode.Stloc && !trueLocVar.IsGenerated) { return(false); } // Create ternary expression newExpr = new ILExpression(ILCode.TernaryOp, null, condExpr, trueExpr, falseExpr); } head.Body.RemoveTail(ILCode.Brtrue, ILCode.Br); head.Body.Add(new ILExpression(opCode, trueLocVar, newExpr)); if (isStloc) { head.Body.Add(new ILExpression(ILCode.Br, trueFall)); } // Remove the old basic blocks body.RemoveOrThrow(labelToBasicBlock[trueLabel]); body.RemoveOrThrow(labelToBasicBlock[falseLabel]); return(true); } return(false); }
public bool SimplifyTernaryOperator(List<ILNode> body, ILBasicBlock head, int pos) { Debug.Assert(body.Contains(head)); ILExpression condExpr; ILLabel trueLabel; ILLabel falseLabel; ILVariable trueLocVar = null; ILExpression trueExpr; ILLabel trueFall; ILVariable falseLocVar = null; ILExpression falseExpr; ILLabel falseFall; object unused; if (head.MatchLastAndBr(ILCode.Brtrue, out trueLabel, out condExpr, out falseLabel) && labelGlobalRefCount[trueLabel] == 1 && labelGlobalRefCount[falseLabel] == 1 && ((labelToBasicBlock[trueLabel].MatchSingleAndBr(ILCode.Stloc, out trueLocVar, out trueExpr, out trueFall) && labelToBasicBlock[falseLabel].MatchSingleAndBr(ILCode.Stloc, out falseLocVar, out falseExpr, out falseFall) && trueLocVar == falseLocVar && trueFall == falseFall) || (labelToBasicBlock[trueLabel].MatchSingle(ILCode.Ret, out unused, out trueExpr) && labelToBasicBlock[falseLabel].MatchSingle(ILCode.Ret, out unused, out falseExpr))) && body.Contains(labelToBasicBlock[trueLabel]) && body.Contains(labelToBasicBlock[falseLabel]) ) { bool isStloc = trueLocVar != null; ILCode opCode = isStloc ? ILCode.Stloc : ILCode.Ret; TypeReference retType = isStloc ? trueLocVar.Type : this.context.CurrentMethod.ReturnType; bool retTypeIsBoolean = TypeAnalysis.IsBoolean(retType); int leftBoolVal; int rightBoolVal; ILExpression newExpr; // a ? true:false is equivalent to a // a ? false:true is equivalent to !a // a ? true : b is equivalent to a || b // a ? b : true is equivalent to !a || b // a ? b : false is equivalent to a && b // a ? false : b is equivalent to !a && b if (retTypeIsBoolean && trueExpr.Match(ILCode.Ldc_I4, out leftBoolVal) && falseExpr.Match(ILCode.Ldc_I4, out rightBoolVal) && ((leftBoolVal != 0 && rightBoolVal == 0) || (leftBoolVal == 0 && rightBoolVal != 0)) ) { // It can be expressed as trivilal expression if (leftBoolVal != 0) { newExpr = condExpr; } else { newExpr = new ILExpression(ILCode.LogicNot, null, condExpr); } } else if (retTypeIsBoolean && trueExpr.Match(ILCode.Ldc_I4, out leftBoolVal)) { // It can be expressed as logical expression if (leftBoolVal != 0) { newExpr = MakeLeftAssociativeShortCircuit(ILCode.LogicOr, condExpr, falseExpr); } else { newExpr = MakeLeftAssociativeShortCircuit(ILCode.LogicAnd, new ILExpression(ILCode.LogicNot, null, condExpr), falseExpr); } } else if (retTypeIsBoolean && falseExpr.Match(ILCode.Ldc_I4, out rightBoolVal)) { // It can be expressed as logical expression if (rightBoolVal != 0) { newExpr = MakeLeftAssociativeShortCircuit(ILCode.LogicOr, new ILExpression(ILCode.LogicNot, null, condExpr), trueExpr); } else { newExpr = MakeLeftAssociativeShortCircuit(ILCode.LogicAnd, condExpr, trueExpr); } } else { // Ternary operator tends to create long complicated return statements if (opCode == ILCode.Ret) return false; // Only simplify generated variables if (opCode == ILCode.Stloc && !trueLocVar.IsGenerated) return false; // Create ternary expression newExpr = new ILExpression(ILCode.TernaryOp, null, condExpr, trueExpr, falseExpr); } head.Body.RemoveTail(ILCode.Brtrue, ILCode.Br); head.Body.Add(new ILExpression(opCode, trueLocVar, newExpr)); if (isStloc) head.Body.Add(new ILExpression(ILCode.Br, trueFall)); // Remove the old basic blocks body.RemoveOrThrow(labelToBasicBlock[trueLabel]); body.RemoveOrThrow(labelToBasicBlock[falseLabel]); return true; } return false; }
public bool SimplifyTernaryOperator(List <ILNode> body, ILBasicBlock head, int pos) { Debug.Assert(body.Contains(head)); ILExpression condExpr; ILLabel trueLabel; ILLabel falseLabel; ILVariable trueLocVar = null; ILExpression trueExpr; ILLabel trueFall; ILVariable falseLocVar = null; ILExpression falseExpr; ILLabel falseFall; object unused; if (head.MatchLastAndBr(ILCode.Brtrue, out trueLabel, out condExpr, out falseLabel) && labelGlobalRefCount[trueLabel] == 1 && labelGlobalRefCount[falseLabel] == 1 && ((labelToBasicBlock[trueLabel].MatchSingleAndBr(ILCode.Stloc, out trueLocVar, out trueExpr, out trueFall) && labelToBasicBlock[falseLabel].MatchSingleAndBr(ILCode.Stloc, out falseLocVar, out falseExpr, out falseFall) && trueLocVar == falseLocVar && trueFall == falseFall) || (labelToBasicBlock[trueLabel].MatchSingle(ILCode.Ret, out unused, out trueExpr) && labelToBasicBlock[falseLabel].MatchSingle(ILCode.Ret, out unused, out falseExpr))) && body.Contains(labelToBasicBlock[trueLabel]) && body.Contains(labelToBasicBlock[falseLabel]) ) { bool isStloc = trueLocVar != null; ILCode opCode = isStloc ? ILCode.Stloc : ILCode.Ret; TypeSig retType = isStloc ? trueLocVar.Type : this.context.CurrentMethod.ReturnType; bool retTypeIsBoolean = retType.GetElementType() == ElementType.Boolean; int leftBoolVal; int rightBoolVal; ILExpression newExpr; // a ? true:false is equivalent to a // a ? false:true is equivalent to !a // a ? true : b is equivalent to a || b // a ? b : true is equivalent to !a || b // a ? b : false is equivalent to a && b // a ? false : b is equivalent to !a && b if (retTypeIsBoolean && trueExpr.Match(ILCode.Ldc_I4, out leftBoolVal) && falseExpr.Match(ILCode.Ldc_I4, out rightBoolVal) && ((leftBoolVal != 0 && rightBoolVal == 0) || (leftBoolVal == 0 && rightBoolVal != 0)) ) { // It can be expressed as trivilal expression if (leftBoolVal != 0) { newExpr = condExpr; } else { newExpr = new ILExpression(ILCode.LogicNot, null, condExpr) { InferredType = corLib.Boolean }; } } else if ((retTypeIsBoolean || falseExpr.InferredType.GetElementType() == ElementType.Boolean) && trueExpr.Match(ILCode.Ldc_I4, out leftBoolVal) && (leftBoolVal == 0 || leftBoolVal == 1)) { // It can be expressed as logical expression if (leftBoolVal != 0) { newExpr = MakeLeftAssociativeShortCircuit(ILCode.LogicOr, condExpr, falseExpr); } else { newExpr = MakeLeftAssociativeShortCircuit(ILCode.LogicAnd, new ILExpression(ILCode.LogicNot, null, condExpr), falseExpr); } } else if ((retTypeIsBoolean || trueExpr.InferredType.GetElementType() == ElementType.Boolean) && falseExpr.Match(ILCode.Ldc_I4, out rightBoolVal) && (rightBoolVal == 0 || rightBoolVal == 1)) { // It can be expressed as logical expression if (rightBoolVal != 0) { newExpr = MakeLeftAssociativeShortCircuit(ILCode.LogicOr, new ILExpression(ILCode.LogicNot, null, condExpr), trueExpr); } else { newExpr = MakeLeftAssociativeShortCircuit(ILCode.LogicAnd, condExpr, trueExpr); } } else { // Ternary operator tends to create long complicated return statements if (opCode == ILCode.Ret) { return(false); } // Only simplify generated variables if (opCode == ILCode.Stloc && !trueLocVar.GeneratedByDecompiler) { return(false); } // Create ternary expression newExpr = new ILExpression(ILCode.TernaryOp, null, condExpr, trueExpr, falseExpr); } var tail = head.Body.RemoveTail(ILCode.Brtrue, ILCode.Br); var listNodes = new List <ILNode>(); var newExprNodes = newExpr.GetSelfAndChildrenRecursive <ILNode>(listNodes).ToArray(); foreach (var node in labelToBasicBlock[trueLabel].GetSelfAndChildrenRecursive <ILNode>(listNodes).Except(newExprNodes)) { newExpr.ILRanges.AddRange(node.AllILRanges); } foreach (var node in labelToBasicBlock[falseLabel].GetSelfAndChildrenRecursive <ILNode>(listNodes).Except(newExprNodes)) { newExpr.ILRanges.AddRange(node.AllILRanges); } newExpr.ILRanges.AddRange(tail[0].ILRanges); tail[1].AddSelfAndChildrenRecursiveILRanges(newExpr.ILRanges); head.Body.Add(new ILExpression(opCode, trueLocVar, newExpr)); if (isStloc) { head.Body.Add(new ILExpression(ILCode.Br, trueFall)); } // Remove the old basic blocks body.RemoveOrThrow(labelToBasicBlock[trueLabel]); body.RemoveOrThrow(labelToBasicBlock[falseLabel]); return(true); } return(false); }
public bool JoinBasicBlocks(List<ILNode> body, ILBasicBlock head, int pos) { ILLabel nextLabel; ILBasicBlock nextBB; if (!head.Body.ElementAtOrDefault(head.Body.Count - 2).IsConditionalControlFlow() && head.Body.Last().Match(ILCode.Br, out nextLabel) && labelGlobalRefCount[nextLabel] == 1 && labelToBasicBlock.TryGetValue(nextLabel, out nextBB) && body.Contains(nextBB) && nextBB.Body.First() == nextLabel && !nextBB.Body.OfType<ILTryCatchBlock>().Any() ) { var tail = head.Body.RemoveTail(ILCode.Br); if (context.CalculateILRanges) { tail[0].AddSelfAndChildrenRecursiveILRanges(nextBB.ILRanges); nextBB.Body[0].AddSelfAndChildrenRecursiveILRanges(nextBB.ILRanges); } nextBB.Body.RemoveAt(0); // Remove label if (context.CalculateILRanges) { if (head.Body.Count > 0) head.Body[head.Body.Count - 1].EndILRanges.AddRange(nextBB.ILRanges); else head.ILRanges.AddRange(nextBB.ILRanges); head.EndILRanges.AddRange(nextBB.EndILRanges); } head.Body.AddRange(nextBB.Body); body.RemoveOrThrow(nextBB); return true; } return false; }
// This is before the expression is processed, so ILValue's and constants havn't been assigned public bool SimplifyTernaryOperator(List <ILNode> body, ILBasicBlock head, int pos) { Debug.Assert(body.Contains(head)); // Debug.Assert((head.Body[0] as ILLabel).Name != "Block_54"); // Debug.Assert((head.Body[0] as ILLabel).Name != "L1257"); ILExpression condExpr; ILLabel trueLabel; ILLabel falseLabel; ILExpression trueExpr; ILLabel trueFall; ILExpression falseExpr; ILLabel falseFall; ILExpression finalFall; ILLabel finalFalseFall; ILLabel finalTrueFall; if ((head.MatchLastAndBr(GMCode.Bt, out trueLabel, out condExpr, out falseLabel) || head.MatchLastAndBr(GMCode.Bf, out falseLabel, out condExpr, out trueLabel)) && labelGlobalRefCount[trueLabel] == 1 && labelGlobalRefCount[falseLabel] == 1 && labelToBasicBlock[trueLabel].MatchSingleAndBr(GMCode.Push, out trueExpr, out trueFall) && labelToBasicBlock[falseLabel].MatchSingleAndBr(GMCode.Push, out falseExpr, out falseFall) && trueFall == falseFall && body.Contains(labelToBasicBlock[trueLabel]) && labelToBasicBlock[trueFall].MatchLastAndBr(GMCode.Bf, out finalFalseFall, out finalFall, out finalTrueFall) && finalFall.Code == GMCode.Pop ) // (finalFall == null || finalFall.Code == GMCode.Pop) { Debug.Assert(finalFall.Arguments.Count != 2); ILValue falseLocVar = falseExpr.Code == GMCode.Constant ? falseExpr.Operand as ILValue : null; ILValue trueLocVar = trueExpr.Code == GMCode.Constant ? trueExpr.Operand as ILValue : null; Debug.Assert(falseLocVar != null || trueLocVar != null); ILExpression newExpr = null; // a ? true : b is equivalent to a || b // a ? b : true is equivalent to !a || b // a ? b : false is equivalent to a && b // a ? false : b is equivalent to !a && b if (trueLocVar != null && trueLocVar.Type == GM_Type.Short && (trueLocVar == 0 || trueLocVar == 1)) { // It can be expressed as logical expression if (trueLocVar != 0) { newExpr = MakeLeftAssociativeShortCircuit(GMCode.LogicOr, condExpr, falseExpr); } else { newExpr = MakeLeftAssociativeShortCircuit(GMCode.LogicAnd, new ILExpression(GMCode.Not, null, condExpr), falseExpr); } } else if (falseLocVar != null && falseLocVar.Type == GM_Type.Short && (falseLocVar == 0 || falseLocVar == 1)) { // It can be expressed as logical expression if (falseLocVar != 0) { newExpr = MakeLeftAssociativeShortCircuit(GMCode.LogicOr, new ILExpression(GMCode.Not, null, condExpr), trueExpr); } else { newExpr = MakeLeftAssociativeShortCircuit(GMCode.LogicAnd, condExpr, trueExpr); } } Debug.Assert(newExpr != null); // head.Body.RemoveTail(ILCode.Brtrue, ILCode.Br); head.Body.RemoveRange(head.Body.Count - 2, 2); head.Body.Add(new ILExpression(GMCode.Bf, finalFalseFall, newExpr)); head.Body.Add(new ILExpression(GMCode.B, finalTrueFall)); // Remove the inlined branch from scope // body.RemoveOrThrow(nextBasicBlock); // Remove the old basic blocks body.RemoveOrThrow(labelToBasicBlock[trueLabel]); body.RemoveOrThrow(labelToBasicBlock[falseLabel]); body.RemoveOrThrow(labelToBasicBlock[trueFall]); return(true); } return(false); }