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; } }