protected override ICode VisitAssignment(StmtAssignment s) {
     var ctx = s.Ctx;
     var newTarget = ctx.Local(s.Target.Type);
     var phi = new ExprVarPhi(ctx) { Exprs = new[] { s.Target, newTarget } };
     this.phiMap.Add(s.Target, phi);
     return new StmtAssignment(s.Ctx, newTarget, (Expr)this.Visit(s.Expr));
 }
 protected override ICode VisitVarPhi(ExprVarPhi e) {
     if (e.Type.IsBoolean()) {
         List<Expr> newExprs = null;
         foreach (var expr in e.Exprs) {
             var mustConvert = !expr.Type.IsBoolean();
             var newExpr = mustConvert ? this.ConvertToBoolean(expr) : expr;
             if (mustConvert && newExprs == null) {
                 newExprs = new List<Expr>(e.Exprs.TakeWhile(x => x != expr));
             }
             if (newExprs != null) {
                 newExprs.Add(newExpr);
             }
         }
         if (newExprs != null) {
             return new ExprVarPhi(e.Ctx) { Exprs = newExprs };
         }
     }
     return e;
 }
        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;
            }
        }
 protected override ICode VisitVarPhi(ExprVarPhi e) {
     if (e.Exprs.Count() == 1) {
         return this.Visit(e.Exprs.First());
     }
     var exprNew = e.Exprs.Select(x => (Expr)this.Visit(x)).ToArray();
     var exprs = exprNew
         .SelectMany(x => {
             if (x == null) {
                 return Enumerable.Empty<Expr>();
             }
             if (x.ExprType == Expr.NodeType.VarPhi) {
                 return ((ExprVarPhi)x).Exprs;
             }
             return new[] { x };
         })
         .Distinct(Expr.EqComparerExact)
         .ToArray();
     if (exprs.SequenceEqual(e.Exprs)) {
         return e;
     } else {
         return new ExprVarPhi(e.Ctx) { Exprs = exprs };
     }
 }
 protected override ICode VisitVarPhi(ExprVarPhi e) {
     // Variables within phi's cannot be removed
     this.inPhiCount++;
     var ret = base.VisitVarPhi(e);
     this.inPhiCount--;
     return ret;
 }
 protected override ICode VisitVarPhi(ExprVarPhi e) {
     bool finalise = false;
     if (this.phiSeen == null) {
         this.phiSeen = new HashSet<ExprVarPhi>();
         finalise = true;
     }
     this.code.AppendFormat("phi<{0}>(", e.GetHashCode());
     if (this.phiSeen.Add(e)) {
         foreach (var v in e.Exprs) {
             this.Visit(v);
             this.code.Append(",");
         }
         this.code.Length--;
     } else {
         this.code.AppendFormat("<rec-{0}>", e.GetHashCode());
     }
     this.code.Append(")");
     if (finalise) {
         this.phiSeen = null;
     }
     return e;
 }
 protected override ICode VisitVarPhi(ExprVarPhi e) {
     this.clusters.Add(e.Exprs.OfType<ExprVar>().Concat(e).ToArray());
     return e;
 }
        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;
        }
        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;
            }
        }