public static ICode V(ICode ast) { var v = new VisitorIfSimplification(ast); var ret = v.Visit(ast); foreach (var replace in v.replaceVars) { ret = VisitorReplace.V(ret, replace.Item1, replace.Item2); } return(ret); }
// Only have if, switch, cil, continuation, try - no other type of statement // Blocks will only start with cil or try // Will end with null, if, switch or continuation // If ending in 'if', 'then' and 'else' will both have continuations only // 'try' statements will have only 0 or 1 catch clauses public static ICode V(ICode ast) { var v = new VisitorConvertCilToSsa(ast); ast = v.Visit(ast); foreach (var instResult in v.instResults.Values) { var var = new ExprVarLocal(ast.Ctx, instResult.Type); ast = VisitorReplace.V(ast, instResult, var); } return(ast); }
protected override ICode VisitIf(StmtIf s) { var ctx = s.Ctx; var condition = (Expr)this.Visit(s.Condition); this.stack.Push(new List <ExprVar>()); var then = (Stmt)this.Visit(s.Then); var thenDA = this.stack.Pop(); this.stack.Push(new List <ExprVar>()); var @else = (Stmt)this.Visit(s.Else); var elseDA = this.stack.Pop(); var intersection = thenDA.Intersect(elseDA, (IEqualityComparer <ExprVar>) this.phiComparer).ToArray(); this.stack.Peek().AddRange(intersection); var conditionVars = VisitorFindVars.V(condition); var needAssigning = conditionVars.Except(this.stack.SelectMany(x => x), (IEqualityComparer <ExprVar>) this.phiComparer).ToArray(); if (needAssigning.Any()) { var replacements = needAssigning.Select(x => { var newExpr = ctx.Local(x.Type); var phi = new ExprVarPhi(ctx) { Exprs = new[] { x, newExpr } }; return(new { orgExpr = x, newExpr, phi }); }).ToArray(); foreach (var replace in replacements) { this.stack.Peek().Add(replace.newExpr); this.stack.Peek().Add(replace.phi); condition = (Expr)VisitorReplace.V(condition, replace.orgExpr, replace.phi); } this.ensureAssigned.Add(s, replacements.Select(x => x.newExpr).ToArray()); } if (condition != s.Condition || then != s.Then || @else != s.Else) { var newS = new StmtIf(ctx, condition, then, @else); this.stmtMap.Add(newS, s); return(newS); } else { return(s); } }
public static ICode V(ICode ast) { var ctx = ast.Ctx; var blockInfo = VisitorSubstituteIrreducable.FindSuitableBlocks.GetInfo(ast); var bInfo = blockInfo.Select(x => new { toCount = VisitorContToCounter.GetCount(x.Key, ast), ast = x.Key, codeCount = x.Value.numICodes, }).ToArray(); var block = bInfo.Where(x => x.toCount >= 2).OrderBy(x => x.toCount * x.codeCount).FirstOrDefault(); if (block == null) { return(ast); } var phis = new Dictionary <Expr, Expr>(); var blockCopies = Enumerable.Range(0, block.toCount - 1) .Select(x => { var v = new VisitorDuplicateCode(); var ret = v.Visit(block.ast); phis = phis.Merge(v.phiMap, (a, b) => new ExprVarPhi(ctx) { Exprs = new[] { a, b } }); return(ret); }) .Concat(block.ast) .ToArray(); var contTos = VisitorFindContinuationsRecursive.Get(ast).Where(x => x.To == block.ast).ToArray(); for (int i = 0; i < contTos.Length; i++) { var contTo = contTos[i]; var blockCopy = blockCopies[i]; ast = VisitorReplace.V(ast, contTo, blockCopy); } ast = VisitorReplaceExprUse.V(ast, phis); return(ast); }
protected override ICode VisitDoLoop(StmtDoLoop s) { var ctx = s.Ctx; var body = (Stmt)this.Visit(s.Body); var @while = (Expr)this.Visit(s.While); var conditionVars = VisitorFindVars.V(@while); var needAssigning = conditionVars.Except(this.stack.SelectMany(x => x), (IEqualityComparer <ExprVar>) this.phiComparer).ToArray(); if (needAssigning.Any()) { var replacements = needAssigning.Select(x => { var newExpr = ctx.Local(x.Type); var phi = new ExprVarPhi(ctx) { Exprs = new[] { x, newExpr } }; return(new { orgExpr = x, newExpr, phi }); }).ToArray(); foreach (var replace in replacements) { this.stack.Peek().Add(replace.newExpr); this.stack.Peek().Add(replace.phi); @while = (Expr)VisitorReplace.V(@while, replace.orgExpr, replace.phi); } var assignmentStmts = replacements .Select(x => new StmtAssignment(ctx, x.newExpr, new ExprDefaultValue(ctx, x.newExpr.Type))) .ToArray(); body = new StmtBlock(ctx, assignmentStmts.Concat(body)); } if (body != s.Body || @while != s.While) { return(new StmtDoLoop(ctx, body, @while)); } else { return(s); } }
// TODO: Restrict movement across try/catch/finally borders public static ICode V(ICode ast) { var v = new VisitorSsaCopyPropagation(); var ast2 = v.Visit(ast); var alreadyReplaced = new Dictionary <Expr, Expr>(); foreach (var a in v.assignments.Values) { if (a.mustKeep) { continue; } if (a.assignment == null) { continue; } if (a.count == 1) { if (!VisitorFindSpecials.Any(a.assignment, Expr.Special.PossibleSideEffects)) { ast2 = VisitorReplace.V(ast2, a.assignment, null); } } else if (a.count == 2 /*|| * (IsSimple(alreadyReplaced.ValueOrDefault(a.assignment.Expr, a.assignment.Expr)) && !a.assignment.Expr.Type.IsNonPrimitiveValueType())*/) { var updater = new Updater(a.assignment.Target); ast2 = updater.Visit(ast2); foreach (var replaced in updater.Replaced) { alreadyReplaced[replaced.Item1] = replaced.Item2; } } } return(ast2); }
public static ICode V(ICode ast) { var ctx = ast.Ctx; var blockInfo = FindSuitableBlocks.GetInfo(ast); var bestBlock = blockInfo .Where(x => !x.Value.containsLeaveProtectedRegion && x.Value.numConts <= 1) .OrderBy(x => x.Value.numConts == 0 ? 1000 : x.Value.numConts) .ThenBy(x => x.Value.numICodes) .FirstOrDefault(); if (bestBlock.Key == null) { return(ast); } if (bestBlock.Value.numConts > 1) { // Best block must have just one continuation return(ast); } Stmt addContTo = null; if (bestBlock.Value.numConts == 0) { addContTo = (Stmt)blockInfo.FirstOrDefault(x => x.Value.numConts == 0 && x.Key != bestBlock.Key).Key; if (addContTo == null) { return(ast); } } var blockAst = (Stmt)bestBlock.Key; if (blockAst.StmtType != Stmt.NodeType.Block) { // Best block must be StmtBlock return(ast); } var stmtBlock = (StmtBlock)blockAst; var stmts = stmtBlock.Statements.ToArray(); var cont = bestBlock.Value.numConts == 0 ? new StmtContinuation(ctx, addContTo, false) : (StmtContinuation)stmts.Last(); var ifSkipContentPhi = new ExprVarPhi(ctx); var ifSkipInitialVar = ctx.Local(ctx.Boolean); var ifSkipContentVar = ctx.Local(ctx.Boolean); var ifSkipContentPhiExprs = new List <Expr> { ifSkipInitialVar, ifSkipContentVar }; var ifSkipReset = new StmtAssignment(ctx, ifSkipContentVar, ctx.Literal(false)); var inIfBlock = new StmtBlock(ctx, stmts.Take(stmts.Length - (bestBlock.Value.numConts == 0 ? 0 : 1))); var ifBlock = new StmtIf(ctx, ctx.ExprGen.Not(ifSkipContentPhi), inIfBlock, null); var newBlock = new StmtBlock(ctx, ifBlock, ifSkipReset, cont); ast = VisitorReplace.V(ast, blockAst, newBlock); var allConts = VisitorFindContinuationsRecursive.Get(ast); var contsNeedChanging = allConts.Where(x => x != cont && x.To == cont.To).ToArray(); var contsReplaceInfo = contsNeedChanging .Select(x => { var ifVar = ctx.Local(ctx.Boolean); var newCont = new StmtBlock(ctx, new StmtAssignment(ctx, ifVar, ctx.Literal(true)), new StmtContinuation(ctx, newBlock, x.LeaveProtectedRegion)); return(new { oldCont = x, ifVar, newCont }); }) .ToArray(); foreach (var contReplace in contsReplaceInfo) { ifSkipContentPhiExprs.Add(contReplace.ifVar); ast = VisitorReplace.V(ast, contReplace.oldCont, contReplace.newCont); } ifSkipContentPhi.Exprs = ifSkipContentPhiExprs; // TODO: Shouldn't be required, but definite-assignment doesn't quite work properly, so is required var initalSkipVarAssignment = new StmtAssignment(ctx, ifSkipInitialVar, ctx.Literal(false)); var newAst = new StmtBlock(ctx, initalSkipVarAssignment, (Stmt)ast); return(newAst); }