public override void CaseALocalDeclStm(ALocalDeclStm node) { AMethodDecl pMethod = Util.GetAncestor<AMethodDecl>(node); AALocalDecl decl = (AALocalDecl) node.GetLocalDecl(); if (decl.GetInit() == null) { ALocalLvalue lvalue = new ALocalLvalue(new TIdentifier(decl.GetName().Text)); data.LocalLinks[lvalue] = decl; data.LvalueTypes[lvalue] = decl.GetType(); List<PStm> statements = AssignDefault(lvalue); AABlock pBlock = (AABlock)node.Parent(); foreach (PStm statement in statements) { pBlock.GetStatements().Insert(pBlock.GetStatements().IndexOf(node), statement); } pBlock.RemoveChild(node); } else { //Make an assignment expression before moving ALocalLvalue lvalue = new ALocalLvalue(new TIdentifier(decl.GetName().Text)); data.LvalueTypes[lvalue] = decl.GetType(); AAssignmentExp exp = new AAssignmentExp(new TAssign("="), lvalue, decl.GetInit()); AExpStm expStm = new AExpStm(new TSemicolon(";"), exp); node.ReplaceBy(expStm); data.LvalueTypes[lvalue] = decl.GetType(); data.ExpTypes[exp] = decl.GetType(); data.LocalLinks[lvalue] = decl; } AABlock block = (AABlock) pMethod.GetBlock(); block.GetStatements().Insert(0, node); }
public override void CaseAMethodDecl(AMethodDecl node) { if (firstMethodCall) StatementRemover.Parse(node); firstMethodCall = false; before.Clear(); after.Clear(); uses.Clear(); intersectingLocals.Clear(); definedLocals.Clear(); renamedLocals.Clear(); assigns.Clear(); changes = false; //Make uses setUses = true; base.CaseAMethodDecl(node); setUses = false; //Build a list of what's visible do { changes = false; base.CaseAMethodDecl(node); } while (changes); setSpans = true; base.CaseAMethodDecl(node); setSpans = false; //Join locals of same type, unless they are both parameters or they are listed as intersecting for (int i = 0; i < definedLocals.Count; i++) { for (int j = i + 1; j < definedLocals.Count; j++) { AALocalDecl decl1 = definedLocals[i]; AALocalDecl decl2 = definedLocals[j]; if (Util.TypeToString(decl1.GetType()) == Util.TypeToString(decl2.GetType()) && !intersectingLocals.Contains(new Pair(decl1, decl2))) { if (Util.GetAncestor<AABlock>(decl1) == null && Util.GetAncestor<AABlock>(decl2) == null) continue; AALocalDecl replacement = decl1; AALocalDecl replaced = decl2; //Dont replace the parameter if (Util.GetAncestor<AABlock>(replaced) == null) { replacement = decl2; replaced = decl1; i--; } j--; renamedLocals.Add(replaced, replacement); definedLocals.Remove(replaced); foreach (Pair pair in intersectingLocals) { if (pair.Local1 == replaced) pair.Local1 = replacement; if (pair.Local2 == replaced) pair.Local2 = replacement; } //Assign defaults if (replaced.GetInit() == null) { ALocalLvalue lvalue = new ALocalLvalue(new TIdentifier(replaced.GetName().Text)); finalTrans.data.LocalLinks[lvalue] = replaced; finalTrans.data.LvalueTypes[lvalue] = replaced.GetType(); List<PStm> statements = AssignDefault(lvalue); PStm pStm = Util.GetAncestor<PStm>(replaced); AABlock pBlock = (AABlock) pStm.Parent(); foreach (PStm statement in statements) { pBlock.GetStatements().Insert(pBlock.GetStatements().IndexOf(pStm), statement); } pBlock.RemoveChild(pStm); } else { //Make an assignment expression instead ALocalDeclStm declStm = (ALocalDeclStm)replaced.Parent(); ALocalLvalue lvalue = new ALocalLvalue((TIdentifier)replaced.GetName().Clone()); finalTrans.data.LvalueTypes[lvalue] = replaced.GetType(); AAssignmentExp exp = new AAssignmentExp(new TAssign("=", lvalue.GetName().Line, lvalue.GetName().Pos), lvalue, replaced.GetInit()); AExpStm expStm = new AExpStm(declStm.GetToken(), exp); declStm.ReplaceBy(expStm); finalTrans.data.LvalueTypes[lvalue] = replacement.GetType(); finalTrans.data.ExpTypes[exp] = replacement.GetType(); finalTrans.data.LocalLinks[lvalue] = replacement; } } } } //Unique names List<string> names = new List<string>(); //Avoid clash with methods/fields/structs names.AddRange(finalTrans.data.Methods.Select(declItem => declItem.Decl.GetName().Text)); names.AddRange(finalTrans.data.Fields.Select(declItem => declItem.Decl.GetName().Text)); names.AddRange(finalTrans.data.Structs.Select(declItem => declItem.Decl.GetName().Text)); foreach (AALocalDecl local in definedLocals) { string name = local.GetName().Text; int version = 1; while (names.Contains(name)) { version++; name = local.GetName().Text + version; } local.GetName().Text = name; names.Add(name); } //Move defined locals to the start of the method foreach (AALocalDecl formal in node.GetFormals()) { definedLocals.Remove(formal); } AABlock block = (AABlock)node.GetBlock(); for (int i = 0; i < block.GetStatements().Count; i++) { ALocalDeclStm stm; if (block.GetStatements()[i] is ALocalDeclStm) { stm = (ALocalDeclStm)block.GetStatements()[i]; definedLocals.Remove((AALocalDecl)stm.GetLocalDecl()); continue; } //Add the rest at i if (definedLocals.Count == 0) break; AALocalDecl decl = definedLocals[0]; definedLocals.RemoveAt(0); if (decl.GetInit() == null) { ALocalLvalue lvalue = new ALocalLvalue(new TIdentifier(decl.GetName().Text)); finalTrans.data.LocalLinks[lvalue] = decl; finalTrans.data.LvalueTypes[lvalue] = decl.GetType(); List<PStm> statements = AssignDefault(lvalue); PStm pStm = Util.GetAncestor<PStm>(decl); AABlock pBlock = (AABlock) pStm.Parent(); foreach (PStm statement in statements) { pBlock.GetStatements().Insert(pBlock.GetStatements().IndexOf(pStm), statement); } pBlock.RemoveChild(pStm); } else { //Make an assignment expression before moving stm = (ALocalDeclStm)decl.Parent(); ALocalLvalue lvalue = new ALocalLvalue(new TIdentifier(decl.GetName().Text)); finalTrans.data.LvalueTypes[lvalue] = decl.GetType(); AAssignmentExp exp = new AAssignmentExp(new TAssign("="), lvalue, decl.GetInit()); AExpStm expStm = new AExpStm(new TSemicolon(";"), exp); stm.ReplaceBy(expStm); finalTrans.data.LvalueTypes[lvalue] = decl.GetType(); finalTrans.data.ExpTypes[exp] = decl.GetType(); finalTrans.data.LocalLinks[lvalue] = decl; } stm = new ALocalDeclStm(new TSemicolon(";"), decl); block.GetStatements().Insert(i, stm); } fixRefferences = true; base.CaseAMethodDecl(node); fixRefferences = false; //If we have an assignment to a local where the stored result is never used, remove the assignment //Since we changed some statements, rebuild stuff before.Clear(); after.Clear(); uses.Clear(); intersectingLocals.Clear(); definedLocals.Clear(); renamedLocals.Clear(); assigns.Clear(); changes = false; //Make uses setUses = true; base.CaseAMethodDecl(node); setUses = false; //Build a list of what's visible do { changes = false; base.CaseAMethodDecl(node); } while (changes); PStm[] stms = new PStm[before.Keys.Count]; before.Keys.CopyTo(stms, 0); foreach (PStm stm in stms) { if (assigns[stm] != null && //Assignment exp !after[stm].Contains(assigns[stm]) && //Assignment unused Util.GetAncestor<AMethodDecl>(assigns[stm]) != null && !(stm is ALocalDeclStm))//It is to a local { stm.Apply(new MoveMethodDeclsOut(finalTrans.data)); stm.Parent().RemoveChild(stm); } } //Remove foo = foo; RemoveStupidAssignments assignmentRemover = new RemoveStupidAssignments(finalTrans.data); node.Apply(assignmentRemover); //Remove unused local variables foreach (AALocalDecl local in definedLocals) { if (Util.GetAncestor<AAProgram>(local) != null && Util.GetAncestor<AABlock>(local) != null && !finalTrans.data.LocalLinks.Where(p => p.Value == local).Any(p => Util.GetAncestor<AAProgram>(p.Key) != null)) local.Parent().Parent().RemoveChild(local.Parent()); } if (assignmentRemover.RemovedOne) { CaseAMethodDecl(node); return; } //If an assignment to a variable is completely local, and that assignment is only used once, put the assignment where it is used //Since we changed some statements, rebuild stuff before.Clear(); after.Clear(); uses.Clear(); intersectingLocals.Clear(); definedLocals.Clear(); renamedLocals.Clear(); assigns.Clear(); changes = false; //Make uses setUses = true; base.CaseAMethodDecl(node); setUses = false; //Build a list of what's visible do { changes = false; base.CaseAMethodDecl(node); } while (changes); foreach (KeyValuePair<PStm, AALocalDecl> pair in assigns) { PStm assignStm = pair.Key; AALocalDecl assignVar = pair.Value; bool isLocal = Util.IsLocal(assignStm, finalTrans.data); bool containsInvokeInPrevStm = false; if (assignVar != null && after[assignStm].Contains(assignVar)) { bool dontMove = false; //First, if there are any conditional parrent statement, where the variable is in live before the stm, then we can't move it PStm condParent = (PStm) Util.GetNearestAncestor(assignStm, typeof (AIfThenStm), typeof (AIfThenElseStm), typeof (AWhileStm)); while (condParent != null) { if (before[condParent].Contains(assignVar)) { dontMove = true; break; } condParent = (PStm)Util.GetNearestAncestor(condParent.Parent(), typeof(AIfThenStm), typeof(AIfThenElseStm), typeof(AWhileStm)); } PStm useStm = null; List<PStm> successors = GetSuccessor(assignStm); bool containsConditionalAssignments = false; while (successors.Count > 0) { if (successors.Count > 500) useStm = useStm; PStm successor = successors[0]; successors.RemoveAt(0); if (uses[successor].Contains(assignVar)) { if (useStm == null && !containsConditionalAssignments && !(successor is AWhileStm)) useStm = successor; else { dontMove = true; break; } } if (after[successor].Contains(assignVar) && !(assigns.ContainsKey(successor) && assigns[successor] == assignVar)) { List<PStm> newSuccessors = GetSuccessor(successor); foreach (PStm stm in newSuccessors) { if (!successors.Contains(stm)) successors.Add(stm); } } if (assigns.ContainsKey(successor) && uses[assignStm].Contains(assigns[successor])) { dontMove = true; break; } if (assigns.ContainsKey(successor) && assigns[successor] == assignVar) { condParent = (PStm)Util.GetNearestAncestor(successor, typeof(AIfThenStm), typeof(AIfThenElseStm), typeof(AWhileStm)); while (condParent != null) { if (!Util.IsAncestor(assignStm, condParent)) { containsConditionalAssignments = true; break; } condParent = (PStm)Util.GetNearestAncestor(condParent.Parent(), typeof(AIfThenStm), typeof(AIfThenElseStm), typeof(AWhileStm)); } //If we found a usage, and it is inside a while that the assignStm is not inside, but we are inside, don't move if (useStm != null) { AWhileStm whileParant = Util.GetAncestor<AWhileStm>(successor); while (whileParant != null) { if (Util.IsAncestor(useStm, whileParant) && !Util.IsAncestor(assignStm, whileParant)) { dontMove = true; break; } whileParant = Util.GetAncestor<AWhileStm>(whileParant.Parent()); } } } FindInvoke finder = new FindInvoke(); successor.Apply(finder); if (finder.ContainsInvoke && useStm == null) containsInvokeInPrevStm = true; } if (useStm != null && !dontMove) { //If assignStm is inside an if, and the use stm is not, and there is another assignment //to the same variable in an else block, then don't join AIfThenElseStm ifThenElse = Util.GetAncestor<AIfThenElseStm>(assignStm); while (ifThenElse != null) { if (!Util.IsAncestor(useStm, ifThenElse)) { ABlockStm otherBlock; if (Util.IsAncestor(assignStm, ifThenElse.GetThenBody())) otherBlock = (ABlockStm) ifThenElse.GetElseBody(); else otherBlock = (ABlockStm)ifThenElse.GetThenBody(); StmEnum enumerator = new StmEnum(otherBlock); while (enumerator.MoveNext()) { PStm stm = (PStm) enumerator.Current; if (assigns.ContainsKey(stm) && assigns[stm] == assignVar) { dontMove = true; break; } } if (dontMove) break; } ifThenElse = Util.GetAncestor<AIfThenElseStm>(ifThenElse.Parent()); } //If the assignStm or useStm is inside a while, it could get complicated //if (Util.HasAncestor<AWhileStm>(assignStm) || Util.HasAncestor<AWhileStm>(useStm)) // dontMove = true; } if (useStm != null && dontMove == false && (isLocal || !containsInvokeInPrevStm)) { //Ensure that it is not used twice in this stm FindLvalue finder = new FindLvalue(assignVar, finalTrans.data); useStm.Apply(finder); if (!finder.IsUsedTwice && (isLocal || !finder.HasPrevInvoke)) { PExp rightside; if (assignStm is ALocalDeclStm) { rightside = ((AALocalDecl)((ALocalDeclStm)assignStm).GetLocalDecl()).GetInit(); } else { rightside = ((AAssignmentExp)((AExpStm)assignStm).GetExp()).GetExp(); assignStm.Parent().RemoveChild(assignStm); } if (rightside != null) { finder.Lvalue.Parent().ReplaceBy(rightside); CaseAMethodDecl(node); return; } } } } } if (StatementRemover.Parse(node)) { CaseAMethodDecl(node); return; } firstMethodCall = true; }